Reading Assignment: Strategy Improvements

The time has come where you are going to beat my strategy! I want you to take either this strategy or any other strategy and improve it to the point where it outperforms me. The requirements are the following:

  1. Use 0.2% brokerage fee
  2. Backtested and validated on at least 2 independent datasets
  3. NO CHEATING

Anyone can curve-fit and adapt a strategy so it makes insane returns in a backtest, that is not the point with this assignment. I want you to share your real attempts of improvement.

I’m looking forward to seeing you’re strategies. Please share your results here, either with a screenshot or with code + screenshot.

4 Likes

Working on it at the moment; feel free to contact me if anyone wants to collaborate as part of an Algo Team - or A-Team… together we develop and Thrive!!!

[email protected]

3 Likes

Here is one strategy for XBT Bitmex 1hr TF that I’ve been testing, but not fully confirmed for repainting. It’s partially based on a couple other scripts as noted in script notes.

The script backtest is based on 1000 starting capital, trading 100% of account equity compounding. Stop loss and triggered trailing stop is part of the strategy… still tweaking these pieces… feel free to copy\paste and test as well.

//@version=3
// Original Author: @JayRogers
// Revision Author: JustUncleL
// Revision Author: HeCormier

strategy("[HC] Strategy: Algo", shorttitle=“Strategy: Algo”, overlay=true,
default_qty_type=strategy.percent_of_equity, default_qty_value=100, initial_capital=1000,
calc_on_order_fills= true, calc_on_every_tick=true, max_bars_back=10,
pyramiding=0,commission_type=strategy.commission.percent,commission_value=0.2)

src = close

//* General Inputs //
showTrendCloud = input(title=“Show TrendCloud?”, type=bool, defval=true) //
Plot Trend Cloud //
showRBDDBRColor = input(title=“Show RBR DBD Candle Colors?”, type=bool, defval=true) //
RBD (Rally Base Drop) & DBR (Drop Base Rally) Candle Colors //
showTDLevelPoints = input(title=“Show TDSP/TDDP?”, type=bool, defval=true) // * TD Level Points * //
showSMA = input(title=“Show SMA?”, type=bool, defval=false) // * Simple Moving Averages * //
showPositionLevels = input(title=“Show Position Levels?”, type=bool, defval=true) //
Plot Order, Stop Loss and Trailing Stop Trigger Levels *//

//* Simple Moving Averages *//
ma12 = na
ma12 := sma(src, 13)
ma21 = na
ma21 := sma(src, 21)
ma55 = na
ma55 := sma(src, 55)
ma89 = na
ma89 := sma(src, 89)
ma200 = na
ma200 := sma(src, 200)
plot(showSMA ? ma12 : na, color=red, transp=0, style=line, title=“SMA13”, linewidth=1)
plot(showSMA ? ma21 : na, color=yellow, transp=0, style=line, title=“SMA21”, linewidth=1)
plot(showSMA ? ma55 : na, color=lime, transp=0, style=line, title=“SMA55”, linewidth=1)
plot(showSMA ? ma89 : na, color=aqua, transp=0, style=line, title=“SMA100”, linewidth=1)
plot(showSMA ? ma200 : na, color=purple, transp=0, style=line, title=“SMA200”, linewidth=1)

//* RBD (Rally Base Drop) & DBR (Drop Base Rally) Candle Colors *//
cR = (close - open) >= 0 ? ((close - open) / (high - low))*100 > 50 ? true : false : na //Rally Candle
cB = (abs(close - open) / (high - low))*100 < 50 ? true : false //Base Candle
cD = (open - close) >= 0 ? ((open - close) / (high - low))*100 > 50 ? true : false : na //Drop Candle
limeBar = cR
whiteBar = (cR[1] and cB) or (cD[1] and cB)
redBar = cD
barcolor(showRBDDBRColor ? limeBar ? lime : na : na)
barcolor(showRBDDBRColor ? whiteBar ? white : na : na)
barcolor(showRBDDBRColor ? redBar ? red : na : na)

// * TD Level Points * //
TDSP1 = high < high[1] and high[1] > high[2]
TDSP2 = high < high[1] and high[1] < high[2] and high[2] > high[3] and high[3] > high[4]
TDSP3 = high < high[1] and high[1] < high[2] and high[2] < high[3] and high[3] > high[4] and high[4] > high[5] and high[5] > high[6]
TDDP1 = low > low[1] and low[1] < low[2]
TDDP2 = low > low[1] and low[1] > low[2] and low[2] < low[3] and low[3] < low[4]
TDDP3 = low > low[1] and low[1] > low[2] and low[2] > low[3] and low[3] < low[4] and low[4] < low[5] and low[5] < low[6]
plotshape(showTDLevelPoints ? TDSP3 ? TDSP3 : na : na, title= “TDSP3”, color=yellow, transp=40, size=size.tiny, style=shape.cross, location=location.abovebar, offset=-3)
plotshape(showTDLevelPoints ? TDDP3 ? TDDP3 : na : na, title= “TDDP3”, color=yellow, transp=40, size=size.tiny, style=shape.cross, location=location.belowbar, offset=-3)
plotshape(showTDLevelPoints ? TDSP2 ? TDSP2 : na : na, title= “TDSP2”, color=yellow, transp=80, size=size.tiny, style=shape.cross, location=location.abovebar, offset=-4)
plotshape(showTDLevelPoints ? TDDP2 ? TDDP2 : na : na, title= “TDDP2”, color=yellow, transp=80, size=size.tiny, style=shape.cross, location=location.belowbar, offset=-4)

//* Algo Strategy Inputs //
inpDescriptionStrategy = input(defval=true, title = “Strategy Settings”)
useRes = input(defval = true, title = “Use Alternate Resolution?”)
intRes = input(defval = 3, title = “Multiplier for Alernate Resolution”)
stratRes = ismonthly? tostring(interval
intRes,"###M") : isweekly? tostring(intervalintRes,"###W") : isdaily? tostring(intervalintRes,"###D") : isintraday ? tostring(interval*intRes,"####") : ‘60’
basisType = input(defval = “SMMA”, title = "Basis Moving Average Type: ", options=[“SMA”, “EMA”, “DEMA”, “TEMA”, “WMA”, “VWMA”, “SMMA”, “HullMA”, “LSMA”, “ALMA”, “SSMA”, “TMA”])
basisLen = input(defval = 8, title = “MA Period”, minval = 1)
offsetSigma = input(defval = 6, title = “Offset for LSMA / Sigma for ALMA”, minval = 0)
offsetALMA = input(defval = 0.85, title = “Offset for ALMA”, minval = 0, step = 0.01)
delayOffset = input(defval = 0, title = “Delay Open/Close MA (Forces Non-Repainting)”, minval = 0, step = 1)

//* Return MA Input Selection //
variant(type, src, len, offSig, offALMA) =>
v1 = sma(src, len) // Simple
v2 = ema(src, len) // Exponential
v3 = 2 * v2 - ema(v2, len) // Double Exponential
v4 = 3 * (v2 - ema(v2, len)) + ema(ema(v2, len), len) // Triple Exponential
v5 = wma(src, len) // Weighted
v6 = vwma(src, len) // Volume Weighted
v7 = 0.0
v7 := na(v7[1]) ? sma(src, len) : (v7[1] * (len - 1) + src) / len // Smoothed
v8 = wma(2 * wma(src, len / 2) - wma(src, len), round(sqrt(len))) // Hull
v9 = linreg(src, len, offSig) // Least Squares
v10 = alma(src, len, offALMA, offSig) // Arnaud Legoux
v11 = sma(v1,len) // Triangular (extreme smooth)
// SuperSmoother filter
// © 2013 John F. Ehlers
a1 = exp(-1.414
3.14159 / len)
b1 = 2a1cos(1.4143.14159 / len)
c2 = b1
c3 = (-a1)a1
c1 = 1 - c2 - c3
v12 = 0.0
v12 := c1
(src + nz(src[1])) / 2 + c2
nz(v12[1]) + c3*nz(v12[2])
type==“EMA”?v2 : type==“DEMA”?v3 : type==“TEMA”?v4 : type==“WMA”?v5 : type==“VWMA”?v6 : type==“SMMA”?v7 : type==“HullMA”?v8 : type==“LSMA”?v9 : type==“ALMA”?v10 : type==“TMA”?v11: type==“SSMA”?v12: v1

//* Security Wrapper for Alternate Resolution *//
reso(exp, use, res) => use ? security(tickerid, res, exp, gaps=barmerge.gaps_off, lookahead=barmerge.lookahead_on) : exp

//* Plot Trend Cloud *//
closeSeries = variant(basisType, close[delayOffset], basisLen, offsetSigma, offsetALMA)
openSeries = variant(basisType, open[delayOffset], basisLen, offsetSigma, offsetALMA)
closeSeriesAlt = reso(closeSeries, useRes, stratRes)
openSeriesAlt = reso(openSeries, useRes, stratRes)
trendColor = (closeSeriesAlt > openSeriesAlt) ? green : red
closeP=plot(showTrendCloud ? closeSeriesAlt : na, title = “Close Series”, color = trendColor, linewidth = 1, style = line, transp = 1)
openP=plot(showTrendCloud ? openSeriesAlt : na, title = “Open Series”, color = trendColor, linewidth = 1, style = line, transp = 1)
fill(closeP,openP,color=trendColor,transp=80)

// *** Strategy Long/Short Call Calculation ***
longEntry = na
shortEntry = na
inLongPosition = na
inShortPosition = na
flat = na
inLongPosition := longEntry[1] ? true : shortEntry[1] ? false : inLongPosition[1]
inShortPosition:= shortEntry[1] ? true : longEntry[1] ? false : inShortPosition[1]
flat := not inLongPosition and not inShortPosition

xlong = cross(closeSeriesAlt, openSeriesAlt) and closeSeriesAlt > openSeriesAlt
xshort = cross(closeSeriesAlt, openSeriesAlt) and closeSeriesAlt < openSeriesAlt

longEntry := xlong[1] and abs(openSeriesAlt - closeSeriesAlt) > 1
shortEntry := xshort[1] and abs(openSeriesAlt - closeSeriesAlt) > 1

// *** STRATEGY *** //
//Variables declarations
inpDescriptionPosition = input(defval=true, title = “Strategy Position Settings”) // Settings Header
inpTakeProfit = input(defval = 20, title = “Take Profit %”, minval = 0)
inpStopLoss = input(defval = 2, title = “Stop Loss %”, minval = 0)
inpTrailStop = input(defval = 2.5, title = “Trailing Stop Loss %”, minval = 0)
inpTrailOffset = input(defval = 0.5, title = “Trailing Stop Loss Offset %”, minval = 0)
procent = 0.0
openprice = 0.0
curprice = close[0]
useTakeProfit = 0.0
useStopLoss = 0.0
useTrailStop = 0.0
useTrailOffset = 0.0
openprice := nz(openprice[1])
useTakeProfit := nz(useTakeProfit[1])
useStopLoss := nz(useStopLoss[1])
useTrailStop := nz(useTrailStop[1])
useTrailOffset := nz(useTrailOffset[1])
useTakeProfit := useTakeProfit==0.0 ? na : useTakeProfit
useStopLoss := useStopLoss==0.0 ? na : useStopLoss
useTrailStop := useTrailStop==0.0 ? na : useTrailStop
useTrailOffset := useTrailOffset==0.0 ? na : useTrailOffset
openprice := openprice==0.0 ? na : openprice

// Date and Time Backtest Ranges
inpDescriptionBacktest = input(defval=true, title = “Strategy Backtest Range Settings”)
st_yr_inp = input(defval=2018, title=‘Backtest Start Year’, type=integer)
st_mn_inp = input(defval=07, title=‘Backtest Start Month’, type=integer)
st_dy_inp = input(defval=01, title=‘Backtest Start Day’, type=integer)
en_yr_inp = input(defval=2020, title=‘Backtest End Year’, type=integer)
en_mn_inp = input(defval=12, title=‘Backtest End Month’, type=integer)
en_dy_inp = input(defval=31, title=‘Backtest End Day’, type=integer)

// Set start and end dates for backtest
start = timestamp(st_yr_inp, st_mn_inp, st_dy_inp,23,59)
end = timestamp(en_yr_inp, en_mn_inp, en_dy_inp,23,59)
testDateRange = time > start and time < end

// Long Strategy
if (longEntry and testDateRange and (strategy.position_size==0 or inShortPosition))
openprice := close[0]
procent := nz((curprice/100)(1/syminfo.mintick))
useTakeProfit := inpTakeProfit >= 1 ? inpTakeProfit
procent : na
useStopLoss := inpStopLoss >= 1 ? inpStopLossprocent : na
useTrailStop := inpTrailStop >= 1 ? inpTrailStop
procent : na
useTrailOffset := inpTrailOffset >= 1 ? inpTrailOffset*procent : na
strategy.entry(‘L’,strategy.long)

strategy.exit(“Exit Long SL/TP”, from_entry = “L”, profit = useTakeProfit, loss = useStopLoss, trail_points = useTrailStop, trail_offset = useTrailOffset)

// Short Strategy
if (shortEntry and testDateRange and (strategy.position_size==0 or inLongPosition))
openprice := close[0]
procent := nz((curprice/100)(1/syminfo.mintick))
useTakeProfit := inpTakeProfit >= 1 ? inpTakeProfit
procent : na
useStopLoss := inpStopLoss >= 1 ? inpStopLossprocent : na
useTrailStop := inpTrailStop >= 1 ? inpTrailStop
procent : na
useTrailOffset := inpTrailOffset >= 1 ? inpTrailOffset*procent : na
strategy.entry(‘S’,strategy.short)

strategy.exit(“Exit Short SL/TP”, from_entry = “S”, profit = useTakeProfit, loss = useStopLoss, trail_points = useTrailStop, trail_offset = useTrailOffset)

//* Plot Order, Stop Loss and Trailing Stop Trigger Levels //
plot(showPositionLevels ? inLongPosition ? openprice[0]-(useStopLoss
syminfo.mintick) : na : na,color=red,style=cross, linewidth=1, title=‘SLL’)
plot(showPositionLevels ? inShortPosition ? openprice[0]+(useStopLosssyminfo.mintick) : na : na,color=red,style=cross, linewidth=1, title=‘SLS’)
plot(showPositionLevels ? inLongPosition ? openprice[0]+(useTrailStop
syminfo.mintick) : na : na,color=aqua,style=cross, linewidth=1, title=‘TSL’)
plot(showPositionLevels ? inShortPosition ? openprice[0]-(useTrailStop*syminfo.mintick) : na : na,color=aqua,style=cross, linewidth=1, title=‘TSS’)
plot(showPositionLevels ? inLongPosition ? openprice[0] : na : na,color=white,style=cross, linewidth=1, title=‘TSL’)
plot(showPositionLevels ? inShortPosition ? openprice[0] : na : na,color=white,style=cross, linewidth=1, title=‘TSS’)

10 Likes

hey hank, I would be really interested in seeing how this performs…
keep in touch [email protected]

3 Likes

Got a whole bunch of errors when trying this out myself. But otherwise it looks like it worked out great for you. Good job!

3 Likes

I think the blockquotes messed up the formatting… maybe try this? I can’t find an option to upload a txt file…that would be handy.

//@version=3
// Original Author: @JayRogers
// Revision Author: JustUncleL
// Revision Author: HeCormier

strategy("[HC] Strategy: Algo", shorttitle=“Strategy: Algo”, overlay=true,
default_qty_type=strategy.percent_of_equity, default_qty_value=100, initial_capital=1000,
calc_on_order_fills= true, calc_on_every_tick=true, max_bars_back=10,
pyramiding=0,commission_type=strategy.commission.percent,commission_value=0.2)

src = close

//* General Inputs //
showTrendCloud = input(title=“Show TrendCloud?”, type=bool, defval=true) //
Plot Trend Cloud //
showRBDDBRColor = input(title=“Show RBR DBD Candle Colors?”, type=bool, defval=true) //
RBD (Rally Base Drop) & DBR (Drop Base Rally) Candle Colors //
showTDLevelPoints = input(title=“Show TDSP/TDDP?”, type=bool, defval=true) // * TD Level Points * //
showSMA = input(title=“Show SMA?”, type=bool, defval=false) // * Simple Moving Averages * //
showPositionLevels = input(title=“Show Position Levels?”, type=bool, defval=true) //
Plot Order, Stop Loss and Trailing Stop Trigger Levels *//

//* Simple Moving Averages *//
ma12 = na
ma12 := sma(src, 13)
ma21 = na
ma21 := sma(src, 21)
ma55 = na
ma55 := sma(src, 55)
ma89 = na
ma89 := sma(src, 89)
ma200 = na
ma200 := sma(src, 200)
plot(showSMA ? ma12 : na, color=red, transp=0, style=line, title=“SMA13”, linewidth=1)
plot(showSMA ? ma21 : na, color=yellow, transp=0, style=line, title=“SMA21”, linewidth=1)
plot(showSMA ? ma55 : na, color=lime, transp=0, style=line, title=“SMA55”, linewidth=1)
plot(showSMA ? ma89 : na, color=aqua, transp=0, style=line, title=“SMA100”, linewidth=1)
plot(showSMA ? ma200 : na, color=purple, transp=0, style=line, title=“SMA200”, linewidth=1)

//* RBD (Rally Base Drop) & DBR (Drop Base Rally) Candle Colors *//
cR = (close - open) >= 0 ? ((close - open) / (high - low))*100 > 50 ? true : false : na //Rally Candle
cB = (abs(close - open) / (high - low))*100 < 50 ? true : false //Base Candle
cD = (open - close) >= 0 ? ((open - close) / (high - low))*100 > 50 ? true : false : na //Drop Candle
limeBar = cR
whiteBar = (cR[1] and cB) or (cD[1] and cB)
redBar = cD
barcolor(showRBDDBRColor ? limeBar ? lime : na : na)
barcolor(showRBDDBRColor ? whiteBar ? white : na : na)
barcolor(showRBDDBRColor ? redBar ? red : na : na)

// * TD Level Points * //
TDSP1 = high < high[1] and high[1] > high[2]
TDSP2 = high < high[1] and high[1] < high[2] and high[2] > high[3] and high[3] > high[4]
TDSP3 = high < high[1] and high[1] < high[2] and high[2] < high[3] and high[3] > high[4] and high[4] > high[5] and high[5] > high[6]
TDDP1 = low > low[1] and low[1] < low[2]
TDDP2 = low > low[1] and low[1] > low[2] and low[2] < low[3] and low[3] < low[4]
TDDP3 = low > low[1] and low[1] > low[2] and low[2] > low[3] and low[3] < low[4] and low[4] < low[5] and low[5] < low[6]
plotshape(showTDLevelPoints ? TDSP3 ? TDSP3 : na : na, title= “TDSP3”, color=yellow, transp=40, size=size.tiny, style=shape.cross, location=location.abovebar, offset=-3)
plotshape(showTDLevelPoints ? TDDP3 ? TDDP3 : na : na, title= “TDDP3”, color=yellow, transp=40, size=size.tiny, style=shape.cross, location=location.belowbar, offset=-3)
plotshape(showTDLevelPoints ? TDSP2 ? TDSP2 : na : na, title= “TDSP2”, color=yellow, transp=80, size=size.tiny, style=shape.cross, location=location.abovebar, offset=-4)
plotshape(showTDLevelPoints ? TDDP2 ? TDDP2 : na : na, title= “TDDP2”, color=yellow, transp=80, size=size.tiny, style=shape.cross, location=location.belowbar, offset=-4)

//* Algo Strategy Inputs //
inpDescriptionStrategy = input(defval=true, title = “Strategy Settings”)
useRes = input(defval = true, title = “Use Alternate Resolution?”)
intRes = input(defval = 3, title = “Multiplier for Alernate Resolution”)
stratRes = ismonthly? tostring(interval
intRes,"###M") : isweekly? tostring(intervalintRes,"###W") : isdaily? tostring(intervalintRes,"###D") : isintraday ? tostring(interval*intRes,"####") : ‘60’
basisType = input(defval = “SMMA”, title = "Basis Moving Average Type: ", options=[“SMA”, “EMA”, “DEMA”, “TEMA”, “WMA”, “VWMA”, “SMMA”, “HullMA”, “LSMA”, “ALMA”, “SSMA”, “TMA”])
basisLen = input(defval = 8, title = “MA Period”, minval = 1)
offsetSigma = input(defval = 6, title = “Offset for LSMA / Sigma for ALMA”, minval = 0)
offsetALMA = input(defval = 0.85, title = “Offset for ALMA”, minval = 0, step = 0.01)
delayOffset = input(defval = 0, title = “Delay Open/Close MA (Forces Non-Repainting)”, minval = 0, step = 1)
cloudSpread = input(defval = 1, title=“Cloud Spread Trigger”, minval = 0)

//* Return MA Input Selection //
variant(type, src, len, offSig, offALMA) =>
v1 = sma(src, len) // Simple
v2 = ema(src, len) // Exponential
v3 = 2 * v2 - ema(v2, len) // Double Exponential
v4 = 3 * (v2 - ema(v2, len)) + ema(ema(v2, len), len) // Triple Exponential
v5 = wma(src, len) // Weighted
v6 = vwma(src, len) // Volume Weighted
v7 = 0.0
v7 := na(v7[1]) ? sma(src, len) : (v7[1] * (len - 1) + src) / len // Smoothed
v8 = wma(2 * wma(src, len / 2) - wma(src, len), round(sqrt(len))) // Hull
v9 = linreg(src, len, offSig) // Least Squares
v10 = alma(src, len, offALMA, offSig) // Arnaud Legoux
v11 = sma(v1,len) // Triangular (extreme smooth)
// SuperSmoother filter
// © 2013 John F. Ehlers
a1 = exp(-1.414
3.14159 / len)
b1 = 2a1cos(1.4143.14159 / len)
c2 = b1
c3 = (-a1)a1
c1 = 1 - c2 - c3
v12 = 0.0
v12 := c1
(src + nz(src[1])) / 2 + c2
nz(v12[1]) + c3*nz(v12[2])
type==“EMA”?v2 : type==“DEMA”?v3 : type==“TEMA”?v4 : type==“WMA”?v5 : type==“VWMA”?v6 : type==“SMMA”?v7 : type==“HullMA”?v8 : type==“LSMA”?v9 : type==“ALMA”?v10 : type==“TMA”?v11: type==“SSMA”?v12: v1

//* Security Wrapper for Alternate Resolution *//
reso(exp, use, res) => use ? security(tickerid, res, exp, gaps=barmerge.gaps_off, lookahead=barmerge.lookahead_on) : exp

//* Plot Trend Cloud *//
closeSeries = variant(basisType, close[delayOffset], basisLen, offsetSigma, offsetALMA)
openSeries = variant(basisType, open[delayOffset], basisLen, offsetSigma, offsetALMA)
closeSeriesAlt = reso(closeSeries, useRes, stratRes)
openSeriesAlt = reso(openSeries, useRes, stratRes)
trendColor = (closeSeriesAlt > openSeriesAlt) ? green : red
closeP=plot(showTrendCloud ? closeSeriesAlt : na, title = “Close Series”, color = trendColor, linewidth = 1, style = line, transp = 1)
openP=plot(showTrendCloud ? openSeriesAlt : na, title = “Open Series”, color = trendColor, linewidth = 1, style = line, transp = 1)
fill(closeP,openP,color=trendColor,transp=80)

// *** Strategy Long/Short Call Calculation ***
longEntry = na
shortEntry = na
inLongPosition = na
inShortPosition = na
flat = na
inLongPosition := longEntry[1] ? true : shortEntry[1] ? false : inLongPosition[1]
inShortPosition:= shortEntry[1] ? true : longEntry[1] ? false : inShortPosition[1]
flat := not inLongPosition and not inShortPosition

xlong = cross(closeSeriesAlt, openSeriesAlt) and closeSeriesAlt > openSeriesAlt
xshort = cross(closeSeriesAlt, openSeriesAlt) and closeSeriesAlt < openSeriesAlt

longEntry := xlong[1] and abs(openSeriesAlt - closeSeriesAlt) > cloudSpread
shortEntry := xshort[1] and abs(openSeriesAlt - closeSeriesAlt) > cloudSpread

// *** STRATEGY *** //
//Variables declarations
inpDescriptionPosition = input(defval=true, title = “Strategy Position Settings”) // Settings Header
inpTakeProfit = input(defval = 20, title = “Take Profit %”, minval = 0)
inpStopLoss = input(defval = 2, title = “Stop Loss %”, minval = 0)
inpTrailStop = input(defval = 2.5, title = “Trailing Stop Loss %”, minval = 0)
inpTrailOffset = input(defval = 0.5, title = “Trailing Stop Loss Offset %”, minval = 0)
procent = 0.0
openprice = 0.0
curprice = close[0]
useTakeProfit = 0.0
useStopLoss = 0.0
useTrailStop = 0.0
useTrailOffset = 0.0
openprice := nz(openprice[1])
useTakeProfit := nz(useTakeProfit[1])
useStopLoss := nz(useStopLoss[1])
useTrailStop := nz(useTrailStop[1])
useTrailOffset := nz(useTrailOffset[1])
useTakeProfit := useTakeProfit==0.0 ? na : useTakeProfit
useStopLoss := useStopLoss==0.0 ? na : useStopLoss
useTrailStop := useTrailStop==0.0 ? na : useTrailStop
useTrailOffset := useTrailOffset==0.0 ? na : useTrailOffset
openprice := openprice==0.0 ? na : openprice

// Date and Time Backtest Ranges
inpDescriptionBacktest = input(defval=true, title = “Strategy Backtest Range Settings”)
st_yr_inp = input(defval=2018, title=‘Backtest Start Year’, type=integer)
st_mn_inp = input(defval=07, title=‘Backtest Start Month’, type=integer)
st_dy_inp = input(defval=01, title=‘Backtest Start Day’, type=integer)
en_yr_inp = input(defval=2020, title=‘Backtest End Year’, type=integer)
en_mn_inp = input(defval=12, title=‘Backtest End Month’, type=integer)
en_dy_inp = input(defval=31, title=‘Backtest End Day’, type=integer)

// Set start and end dates for backtest
start = timestamp(st_yr_inp, st_mn_inp, st_dy_inp,23,59)
end = timestamp(en_yr_inp, en_mn_inp, en_dy_inp,23,59)
testDateRange = time > start and time < end

// Long Strategy
if (longEntry and testDateRange and (strategy.position_size==0 or inShortPosition))
openprice := close[0]
procent := nz((curprice/100)(1/syminfo.mintick))
useTakeProfit := inpTakeProfit >= 1 ? inpTakeProfit
procent : na
useStopLoss := inpStopLoss >= 1 ? inpStopLossprocent : na
useTrailStop := inpTrailStop >= 1 ? inpTrailStop
procent : na
useTrailOffset := inpTrailOffset >= 1 ? inpTrailOffset*procent : na
strategy.entry(‘L’,strategy.long)

strategy.exit(“Exit Long SL/TP”, from_entry = “L”, profit = useTakeProfit, loss = useStopLoss, trail_points = useTrailStop, trail_offset = useTrailOffset)

// Short Strategy
if (shortEntry and testDateRange and (strategy.position_size==0 or inLongPosition))
openprice := close[0]
procent := nz((curprice/100)(1/syminfo.mintick))
useTakeProfit := inpTakeProfit >= 1 ? inpTakeProfit
procent : na
useStopLoss := inpStopLoss >= 1 ? inpStopLossprocent : na
useTrailStop := inpTrailStop >= 1 ? inpTrailStop
procent : na
useTrailOffset := inpTrailOffset >= 1 ? inpTrailOffset*procent : na
strategy.entry(‘S’,strategy.short)

strategy.exit(“Exit Short SL/TP”, from_entry = “S”, profit = useTakeProfit, loss = useStopLoss, trail_points = useTrailStop, trail_offset = useTrailOffset)

//* Plot Order, Stop Loss and Trailing Stop Trigger Levels //
plot(showPositionLevels ? inLongPosition ? openprice[0]-(useStopLoss
syminfo.mintick) : na : na,color=red,style=cross, linewidth=1, title=‘SLL’)
plot(showPositionLevels ? inShortPosition ? openprice[0]+(useStopLosssyminfo.mintick) : na : na,color=red,style=cross, linewidth=1, title=‘SLS’)
plot(showPositionLevels ? inLongPosition ? openprice[0]+(useTrailStop
syminfo.mintick) : na : na,color=aqua,style=cross, linewidth=1, title=‘TSL’)
plot(showPositionLevels ? inShortPosition ? openprice[0]-(useTrailStop*syminfo.mintick) : na : na,color=aqua,style=cross, linewidth=1, title=‘TSS’)
plot(showPositionLevels ? inLongPosition ? openprice[0] : na : na,color=white,style=cross, linewidth=1, title=‘TSL’)
plot(showPositionLevels ? inShortPosition ? openprice[0] : na : na,color=white,style=cross, linewidth=1, title=‘TSS’)

2 Likes

Unfortunately still not working. Definitely seems to be a formatting issue. Tried to fix it all myself as well but eventually gave up when I had to start changing simple == operators. I really appreciate your effort though! I’ll take a look at the initial scripts and see what I can come up with.

ok np… odd but I’m going to publish it once I’m happy with the testing… I have a few other scripts I’m working on as well (studies/strategies/indicators). One you get started in pine you can’t stop lol ;o)

happy to test 4u, after as just finishing doing the training, i am about 95% of the way at the moment!! & as a side note, I really appreciate your contribution too… your a star!! A rising one at that…may the force be with you and your talents shine bright!!
[email protected]

2 Likes

Woohoo after some slogging (and a thread on a mistake I’ve made that I would still like an answer to if anyone has time (as I spent most of my time on that) please see here)

I think I’ve got one! OK so I can’t run the data set against the dates in the assignment as I’m on the free account and they’re out of range, so I’ve jumped them on 1 year and used the datasets 15/02/2019 -15/05/2019 and 15/05/2019- 15/08/2019)

The original script just using the MA’s (40 and 80) gets the following results 15/02/2019- 15/05/2019
Net Profit Total Closed Trades %Prof ProfFactor Max Drawdown Avg Trade
$114.19 26 34.62% 1.921 $29.33 $4.39
and 15/05/2019 - 15/08/2019
$372.50 27 44.44% 1.747 $168.77 $13.80
Same dates mine got

$206.11 26 50% 3.795 $36.03 $7.93

$478.38 28 46.43% 1.857 $225.59 $17.09

I’ve kept it pretty simple and all I’ve done is added the TSI index crossover to the buy signal. Code as follows (if it copies and pastes!)

//@version=4
strategy(title="MA Crossing Strategy", overlay=true, initial_capital=2000, commission_type=strategy.commission.percent, commission_value=0.2)

//sma inputs
shortVal = input(defval=40, title="Short SMA", minval=1)
longVal = input(defval=80, title="Long SMA", minval=1)

//Date and Time
fromMonth = input(defval=2, title="From month", minval=1)
fromDay= input(defval=15, title="From day", minval=1)
fromYear= input(defval=2019, title="From year", minval=2014)

toMonth = input(defval=5, title="To month", minval=1)
toDay= input(defval=15, title="To day", minval=1)
toYear= input(defval=2019, title="To year", minval=2014)

tsiLong = input(title="TSI Long Length", type=input.integer, defval=25)
tsiShort = input(title="TSI Short Length", type=input.integer, defval=13)
tsiSignal = input(title="TSI Signal Length", type=input.integer, defval=13)

//Definitions
short=sma(close, shortVal)
long=sma(close, longVal)

price = close
double_smooth(src, tsiLong, tsiShort) =>
    fist_smooth = ema(src, tsiLong)
    ema(fist_smooth, tsiLong)
pc = change(price)
double_smoothed_pc = double_smooth(pc, tsiLong, tsiShort)
double_smoothed_abs_pc = double_smooth(abs(pc), tsiLong, tsiShort)
tsi_value = 100 * (double_smoothed_pc / double_smoothed_abs_pc)

//Logic
timeInRange=(time > timestamp(fromYear, fromMonth, fromDay, 00, 00)) and (time < timestamp(toYear, toMonth, toDay,23,59))

//buy=short >= long
longSignal = (crossover(short, long) or crossover(tsi_value, ema(tsi_value, tsiSignal))) and timeInRange
//sell=long >= short
shortSignal = crossover(long, short) and timeInRange 
//shortSignal = (crossover(long, short) or crossover(ema(tsi_value, tsiSignal), tsi_value)) and timeInRange 

//Position
strategy.entry(id="longPosition", long=true, qty=0.1,when=longSignal, comment="buy")
strategy.entry(id="longPosition", long=false, qty=0.1, when=shortSignal, comment="sell" )

I still need to think about adding a better stop loss (which is what the other thread was about), I’m hoping this might be covered later!

2 Likes

Hello everyone, I’ve changed the initial script as follows:

  • changed the moving averages to 21 and 150
  • added additional conditions to open a long position: RSI < 70 (not overbought) and price > vwap
  • added additional conditions to open a short position: RSI > 30 (not oversold) and price < vwap

For the period of 2.2018 - 5.2018, I have the following results:

And for the period of 5.2018 - 8.2018:

//@version=4

strategy(title=“Moving Average Strategy”, overlay=true, initial_capital=2000, commission_type=strategy.commission.percent,commission_value=0.2)

//TIME AND DATE
fromMonth = input(defval=5, title= “From Month”, minval=1)
fromDay= input(defval=15, title= “From Day”, minval=1)
fromYear= input(defval=2018, title= “From Year”, minval=2014)

toMonth = input(defval=8, title= “To Month”, minval=1)
toDay= input(defval=15, title= “To Day”, minval=1)
toYear= input(defval=2018, title= “To Year”, minval=2014)

//DEFINITIONS
shortMa = sma(close, 21)
longMa = sma(close, 150)
RSI = rsi(close, 14)
VWAP = vwap(close)
price = close

//LOGIC
timeInRange = (time > timestamp(fromYear,fromMonth, fromDay, 00,00)) and (time < timestamp(toYear, toMonth, toDay, 23,59))
longSignal = crossover(shortMa, longMa) and timeInRange and RSI < 70 and price > VWAP
shortSignal = crossover(longMa, shortMa) and timeInRange and RSI > 30 and price < VWAP

//POSITIONS
strategy.entry(id=“longPosition”, long=true, qty=0.1, when=longSignal)
strategy.entry(id=“shortPosition”, long=false, qty=0.1, when=shortSignal)

Cheers!

1 Like

Alright, so I chose everybody’s favorite pair: BTCUSD.

If that’s what I’m trading then I’ve got a hodling mindset. My idea is I want a strategy that buys big low and sells small high, so it’s always accumulating. I just want to sell a bit off on the tops.

Well…the tops are a lot harder to identify with code than with hindsight. Here’s my thoughts:
-Act when the whole candle is separated from the MA by an ATR (or more).
-Act with confirmation. Stop beyond the wick by an ATR.
-Limit at the MA. No sale at average price.

Unfortunately the latter two conditions are too trailing for the volatility. It always fires late. And it doesn’t work very well in long bear markets. But the testing span is just too small for the mindset.

Things Pinescript fought me over (and usually won):

And I’m not here to share secret profitable sauce. :stuck_out_tongue:


3 Likes
  1. tried a number of different MAs which resulted in loss. Then changed the date range to 1 year and fiddled around with the MAs and tired without being attached to the RSE being under 30. Below example gives me: (heightened qty to 0.5)

strategy (title=“MA Simple Crossover Strategy”,overlay=true, initial_capital=2000, commission_type=strategy.commission.percent, commission_value = 0.2)

//DATE AND TIME
fromMonth=input(defval=4,title=“From Month”, minval=1)
fromDay=input(defval=15,title=“From Day”, minval=1)
fromYear=input(defval=2018,title=“From Year”, minval=2014)
toMonth=input(defval=4,title=“To Month”, minval=1)
toDay=input(defval=15,title=“To Day”, minval=1)
toYear=input(defval=2019,title=“To Year”, minval=2014)

//DEFINITIONS
shortMA= sma(close,30)
longMA= sma(close,100)
r=rsi(close, 14)

//LOGIC
timeInRange = (time>timestamp(fromYear,fromMonth,fromDay, 00, 00)) and (time<timestamp(toYear,toMonth,toDay, 23,59))
longSignal = crossover (shortMA, longMA) and timeInRange
shortSignal = crossover (longMA, shortMA) and timeInRange

//POSITIONS
strategy.entry(id=“longPosition”, long=true, qty=0.5, when=longSignal)
strategy.entry(id=“shortPosition”, long=false, qty=0.5, when=shortSignal)


  1. Changing the MA to lower numbers (30-50 days) results in losses or some in only one open trade…

  2. I would be interested in using the macd in a test but I don’t know how to apply it in the code so it makes any sense. Did anyone use it?

1 Like

Total Returns 2015 – 2019

15,01,2015 - 15,12,2019

Net Profit= 122,17%

Total Closed Trades= 95

Percent Profitable= 40%

Profit Factor= 3,064

Max Drawdown= 11,41%

Yearly Returns 2015 – 2019

15,01,2015 - 15,12,2015

Net Profit= 1,47%

Total Closed Trades= 11

Percent Profitable= 45,45%

Profit Factor= 1,113

Max Drawdown= 0,35%

15,01,2016 - 15,12,2016

Net Profit= 0,11%

Total Closed Trades= 27

Percent Profitable= 25,93%

Profit Factor= 1,076

Max Drawdown= 0,79%

15,01,2017 - 15,12,2017

Net Profit= 15,56%

Total Closed Trades= 14

Percent Profitable= 42,86%

Profit Factor= 2,371

Max Drawdown= 5,24%

15,01,2018 - 15,12,2018

Net Profit= 20,63%

Total Closed Trades= 16

Percent Profitable= 37,5%

Profit Factor= 2,491

Max Drawdown= 8%

15,01,2019 - 15,12,2019

Net Profit= 6,25%

Total Closed Trades= 18

Percent Profitable= 33,33%

Profit Factor= 1,192

Max Drawdown= 21,92%

2 Likes

I think i managed to make it but i am still with the question if somebody needs more data of past years does he need the pay version. The free versions has become very limited for testing

2 Likes

To tell you the truth, I am glad that I at least managed to copy your inputs and made sense of it. I am still in the beginning and trying to understand. So, probably my charts don’t show a lot of insight. Anyway, thanks for all you are teaching.

1 Like

I sticked to the strategy of the example and tried to tweak the two parameters:

// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © andreashansch

//@version=3
strategy(title="Moving Average Crossing", overlay=true, initial_capital=2000, commission_type=strategy.commission.percent, commission_value=0.2)

//DATE AND TIME 
fromDay   = input(defval=1, title = "From day", minval=1)
fromMonth = input(defval=1, title = "From month", minval=1)
fromYear  = input(defval=2019, title = "From year", minval=2019)

toDay   = input(defval=1, title = "To day", minval=1)
toMonth = input(defval=4, title = "To month", minval=1)
toYear  = input(defval=2019, title = "To year", minval=2019)

//DEFINITIONS
shortMa = sma(close, 49)
longMa  = sma(close, 81)

//LOGIC
timeInRange = (time > timestamp(fromYear, fromMonth, fromDay, 00, 00)) and (time < timestamp(toYear, toMonth, toDay, 23, 59))
longSignal  = crossover(shortMa, longMa)
shortSignal = crossover(longMa, shortMa)

//POSITIONS
strategy.entry(id="longPosition", long=true, qty=0.1, when=longSignal and timeInRange)
strategy.entry(id="shortPosition", long=false, qty=0.1, when=shortSignal and timeInRange)





In the last image I will show the overall performance from January 1st 2019 until now:

The overall performance seems to be OK, but there are also market situations when this trading strategy created a loss. But there is no trading algorithm which always beats the market.
But this was also a kind of shocking insight I got during these lessons. Although you have a good strategy, performed a lot of backtesting and you are doing trading in an automated way, it is very hard to beat the market! The good thing about Algo-Trading is that your algorithm trades without emotions and it does this job 24/7.

strategy(title="Moving Average crossing", overlay=true, initial_capital=2000, commission_type=strategy.commission.percent, commission_value=0.2)

//DATE AND TIME 
fromDay   = input(defval=15, title = "From day", minval=1)
fromMonth = input(defval=5, title = "From month", minval=1)
fromYear  = input(defval=2018, title = "From year", minval=2014)

toDay   = input(defval=15, title = "To day", minval=1)
toMonth = input(defval=8, title = "To month", minval=1)
toYear  = input(defval=2090, title = "To year", minval=2014)

//DEFINITIONS
shortMa = sma(close, 30)
longMa  = sma(close, 50)
rsi = rsi(close, 14)

//LOGIC
timeInRange = (time > timestamp(fromYear, fromMonth, fromDay, 00, 00)) and (time < timestamp(toYear, toMonth, toDay, 23, 59))
longSignal  = crossover(shortMa, longMa) and timeInRange and rsi < 70
shortSignal = crossover(longMa, shortMa) and timeInRange and rsi > 30

//POSITIONS
strategy.entry(id="longPosition", long=true, qty=0.1, when=longSignal)
strategy.entry(id="shortPosition", long=false, qty=0.1, when=shortSignal)

Couldn’t make it any better somehow by just adjusting this numbers… I don’t have enough knowledge to inlay more indicators…

1 Like

Still a lot to learn and discover in the indicators but it’s a start.

1 Like

Hi guys, I’m also using the free version which only allows me to backtest to Jan 1st, 2019, so I’ve used my strategy on a couple of periods within 2019.

I just added rsi and set it to 24, and used two periods: 1/1/2019-6/30/2019 and 7/1/2019-12/31/2019, basically comparing the first half with the second half of 2019. Trade qty was set to 0.1 BTC.

In the first half of the year, my strategy produced $270, 13.5% net profit with 1.484 profit factor, compared to $2082/103.63% buy & hold return.

In the second half, my strategy produced $446.07, 22.3% net return with 1.611 profit factor, better than the first half, compared to -$585.27/-29% buy & hold return.

Compared to buy & hold, my strategy underperformed @0.1 BTC/trade, but when increased to 0.2 BTC/trade, the return evened out, and when increased to 0.3 BTC/trade, it outperforms buy & hold.

Here’s my code:

//@version=4

strategy(title="Moving Average Strategy", overlay=true, initial_capital=2000, commission_type=strategy.commission.percent, commission_value=0.2)

//Date & Time
fromMonth = input(defval=7, title="from month", minval=1)
fromDay = input(defval=1, title="from day", minval=1)
fromYear = input(defval=2019, title="from year", minval=2014)

toMonth = input(defval=12, title="to month", minval=1)
toDay = input(defval=31, title="to day", minval=1)
toYear = input(defval=2019, title="to year", minval=2014)

//Definitions
shortMa = sma(close, 50)
longMa = sma(close, 80)
rsi = rsi(close, 24)

//Logic
timeInRange = time > timestamp(fromYear, fromMonth, fromDay, 00, 00) and 
   time < timestamp(toYear, toMonth, toDay, 23, 59)
longSignal = crossover(shortMa, longMa) and timeInRange and rsi<70
shortSignal = crossover(longMa, shortMa) and timeInRange and rsi>30

//Positions
strategy.entry(id="longPosition", long=true, qty=0.3, when=longSignal)
strategy.entry(id="shortPosition", long=false, qty=0.3, when=shortSignal)

2 Likes