# Dual Thrust Trading Algorithm (ps4)

Author: a624587332, Date: 2022-07-14 02:43:15
Tags:

```//@version=4
study("Dual Thrust Trading Algorithm (ps4)", overlay=true)
// author: capissimo

// This is an PS4 update to the Dual Thrust trading algorithm developed by Michael Chalek.
// It has been commonly used in futures, forex and equity markets.
// The idea of Dual Thrust is similar to a typical breakout system,
// however dual thrust uses the historical price to construct update the look back period -
// theoretically making it more stable in any given period.

//*** Inputs
p      = input(20,         "Lookback Window", minval=1)
mult   = input(2.0,        "Multiplier", minval=0.001, maxval=50)
rule   = input("Original", "Trend Identification Rule", options=["Original","SMA3","EMA10","SMA5/SMA10"])
algo   = input("Algo #1",  "Algorithm used:", options=["Algo #1", "Algo #2"])
mlen   = input(5,          "Lookback Window M") // 4
nlen   = input(14,         "Lookback Window N") // 20
k      = input(0.9,        "Coeff", step=0.01) // .7, .9
disc   = input(0.55,       "Trending discount", step=0.01) //  .6
use_bb = input(false,      "Bollinger? (alt. Standard Error) Bands")
pbb    = input(20,         "Lookback Window", minval=1)
sdeg   = input(3,          "Smoothing Factor", minval=1)
multbb = input(2.0,        "Bands Multiplier", minval=0.001, maxval=50)
repnt  = input(true,       "Repaint?")

//*** Main
O = security(syminfo.tickerid, tostring(timeframe.multiplier), repnt ? open  : open,  barmerge.gaps_off, barmerge.lookahead_on)
H = security(syminfo.tickerid, tostring(timeframe.multiplier), repnt ? high  : high,  barmerge.gaps_off, barmerge.lookahead_on)
L = security(syminfo.tickerid, tostring(timeframe.multiplier), repnt ? low   : low,   barmerge.gaps_off, barmerge.lookahead_on)
C = security(syminfo.tickerid, tostring(timeframe.multiplier), repnt ? close : close, barmerge.gaps_off, barmerge.lookahead_on)

// ==Bands==
//
// Standard Error of the Estimate (SEE) Bands are constructed around a linear regression curve and
// based on two standard errors above and below this regression line.
// The error bands measure the standard error of the estimate around the linear re-gression line.
// Therefore, as a price series follows the course of the regression line the bands will narrow,
// showing little error in the estimate. As the market gets noisy and random,
// the error will be greater resulting in wider bands.

beta(array,per) =>
val1 = sum(bar_index*array,per)-(per*sma(bar_index,per)*sma(array,per))
val2 = sum(pow(bar_index,2),per)-(per*pow(sma(bar_index,per),2))
calcB = val1/val2

alpha(array,per) =>
calcA = sma(array,per)-(beta(array,per)*sma(bar_index,per))

see(array,per,mult,dir,type) =>
lr = linreg(array,per,0)
val1 = (sum(pow(array,2),per))-((alpha(array,per)*sum(array,per)))-((beta(array,per)*sum(bar_index*array,per)))
val2 = per - 2
narrow = sqrt(val1/val2)
est = sum(pow(lr-array,2),per) / (per - 2 )
wide = sqrt(est)
d = dir ? 1 : -1
band = type ? narrow : wide
seb = lr + d * mult * band

// SEE Bands
UWB = plot(use_bb ? na: sma(see(close, pbb, 2.1, true, false), sdeg), color=color.blue, transp=90)
UNB = plot(use_bb ? na: sma(see(close, pbb, 2, true, true), sdeg), color=color.blue, transp=90)
plot(use_bb ? na: sma(linreg(close, pbb, 0), sdeg), color=color.orange, transp=0)
BNB = plot(use_bb ? na: sma(see(close, pbb, 2, false, true), sdeg), color=color.blue, transp=90)
BWB = plot(use_bb ? na: sma(see(close, pbb, 2.1, false, false), sdeg), color=color.blue, transp=90)
fill(UWB, BWB, title="WideSEE", color=color.blue)
fill(UNB, BNB, title="NarrowSEE", color=color.blue)

// Bollinger Bands
basis = sma(close, pbb)
dev   = multbb * stdev(close, pbb)
upper = basis + dev
lower = basis - dev
plot(use_bb ? basis : na, color=color.orange, linewidth=2, transp=0)
fill(plot(use_bb ? upper : na, transp=65), plot(use_bb ? lower : na, transp=65), color=color.blue, transp=90)

// At the close of the day, calculate two values:
// the highest price - the closing price, and
// the closing price - the lowest price.
// Then take the two larger ones, multiply the k values. The results are called trig-ger values.

// On the second day, the opening price is recorded,
// and then immediately after the price exceeds (opening + trigger value),
// or the price is lower than the (opening - trigger value), the short selling immedi-ately.

// This is an inversion system without a single stop? i.e. the reverse signal is also the unwinding signal.

// K1 and K2 are the parameters.
// When K1 is greater than K2, it is much easier to trigger the long signal and vice versa.
// For demonstration, here we choose K1 = K2 = 0.5.
// In live trading, we can still use historical data to optimize those parameters or
// adjust the parameters according to the market trend.
// K1 should be small than k2 if you are bullish on the market and k1 should be much bigger if you are bearish on the market.

// Trend Identification - Bullish or Bearish
uptrend = false, dntrend = false
if rule=="Original"
rng = C - O
doji = rng == 0
uptrend := rng > 0 or doji and rng > 0
dntrend := rng < 0 or doji and rng < 0
else
sm   = sma(C, 3)                    // #1
em   = ema(C, 10)                   // #2
ma5  = sma(C, 5), ma10 = sma(C, 10) // #3
uptrend := rule=="SMA3" ? C > sm : rule=="EMA10" ? C > em : ma5 > ma10
dntrend := rule=="SMA3" ? C < sm : rule=="EMA10" ? C < em : ma5 < ma10

k1 = k, k2 = k
if uptrend  // Assigned empirically. Should be optimized separately
k1 := k1 * disc  //.2
k2 := k2 * (1 + disc)
if dntrend
k1 := k1 * (1 + disc)
k2 := k2 * disc //.2

dtta1_algo(k1, k2, len) =>
hh = highest(H, len)
hc = highest(C, len)
lc = lowest(C, len)
ll = lowest(L, len)

// The range is calculated based on the close, high and low over the most recent N-periods.
// A position is opened when the market moves a certain range from the opening price.
range = max(hh - lc, hc - ll)
[O + k1 * range, O - k2 * range]

dtta2_algo(k1, k2, ml, nl) =>
hh = 0.0, ll = 0.0, hc = 0.0, lc = 0.0

hh := highest(H, ml)
hc := highest(C, ml)
lc := lowest(C, ml)
ll := lowest(L, ml)

sellRange = (hh - lc) >= (hc - ll) ? hh - lc : hc - ll

hh := highest(H, nl)
hc := highest(C, nl)
lc := lowest(C, nl)
ll := lowest(L, nl)

buyRange = (hh - lc) >= (hc - ll) ? hh - lc : hc - ll
[O + k1 * buyRange, O - k2 * sellRange]

[bt1, st1] = dtta1_algo(k1, k2, mlen)
[bt2, st2] = dtta2_algo(k1, k2, mlen, nlen)

buyTrig = 0.0, sellTrig = 0.0
if algo == "Algo #1"
buyTrig := bt1, sellTrig := st1
else
buyTrig := bt2, sellTrig := st2

shortCondition = C <= sellTrig
state  = 0
state := longCondition ? 1 : shortCondition ? -1 : nz(state)
long   = change(state) and state==-1
short  = change(state) and state==1

plotshape(uptrend and long  ? low : na, location=location.belowbar, style=shape.labelup, color=color.green, size=size.tiny, text="B", textcolor=color.white, transp=0)
plotshape(dntrend and short ? high : na, location=location.abovebar, style=shape.labeldown, color=color.red, size=size.tiny, text="S", textcolor=color.white, transp=0)