I have been reading about mean reverting strategies for intra days and in one article I red the author claimed that it’s actually easier to do it in the second half of the day when the movements are a bit smoother. To test this I made a simple bollinger band strategy and the result looks nice, but does anyone know if this is actually can perform on a longer period of time? I have only optimised the stop loss. Everything else is untouched.
Defparam Cumulateorders = false
n = 1
Starttime = 100000
Endtime = 220000
// Indicators
blow = Bollingerdown[20]
bhigh = Bollingerup[20]
MA1 = Average[8]
MA2 = Average[200]
// LONG
cb1 = (low < blow and close < blow)
cb2 = (MA1 > MA2)
cb3 = (currenttime > Starttime and currenttime < Endtime)
IF NOT Longonmarket and cb1 and cb2 and cb3 THEN
BUY n SHARES AT MARKET
ENDIF
cb4 = high > bhigh and close > bhigh
IF cb4 Then
sell n shares at market
endif
// SHORT
cs1 = (high > bhigh and close > bhigh)
cs2 = (MA1 < MA2)
cs3 = (currenttime > Starttime and currenttime < Endtime)
IF NOT Shortonmarket and cs1 and cs2 and cs3 THEN
SELLSHORT n SHARES AT MARKET
ENDIF
cs4 = low < blow and close < blow
IF cs4 Then
Exitshort n shares at market
endif
SET STOP pLOSS 50
BTW – I have backtested with 0.6 pip spread.
EricParticipant
Master
Hi
Looking good, i put it on demo
i changed line 26 to only “sell at market”
and line 41 to “exitshort at market”
Hi Eric!
I’ve done the same. You can also change the exit conditions to only include the “close”. Including the other command makes no difference to the result.
Here is a quick version for USDJPY (5min) spread 0.8. I have not worked on optimisation yet. I hav added the ADX indicator.
Defparam Cumulateorders = false
Starttime = 100000
Endtime = 240000
// Indicators
blow = Bollingerdown[20]
bhigh = Bollingerup[20]
MA1 = Average[8]
MA2 = Average[200]
ad = adx[21]
adlevel = 23
// LONG
cb1 = (low < blow and close < blow)
cb2 = (MA1 > MA2)
cb3 = (currenttime > Starttime and currenttime < Endtime)
cb4 = (ad > adlevel)
IF NOT Longonmarket and cb1 and cb2 and cb3 and cb4 THEN
BUY 1 CONTRACT AT MARKET
ENDIF
cb8 = close > bhigh
cb9 = LONGONMARKET AND DAYOFWEEK=5 AND TIME>=235000
IF cb8 OR cb9 Then
sell at market
endif
// SHORT
cs1 = (high > bhigh and close > bhigh)
cs2 = (MA1 < MA2)
cs3 = (currenttime > Starttime and currenttime < Endtime)
cs4 = (ad > adlevel)
IF NOT Shortonmarket and cs1 and cs2 and cs3 and cs4 THEN
SELLSHORT 1 CONTRACT AT MARKET
ENDIF
cs8 = close < blow
cs9 = SHORTONMARKET AND DAYOFWEEK=5 AND TIME>=235000
IF cs8 OR cs9 Then
Exitshort at market
endif
SET STOP pLOSS 70
Here is an updated version on the EURUSD. The major improvement is with focus on a lower draw down.
Defparam Cumulateorders = false
Starttime = 100000
Endtime = 240000
// Indicators
blow = Bollingerdown[20]
bhigh = Bollingerup[20]
MA1 = Average[8]
MA2 = Average[200]
ad = adx[24]
adlevel = 14
// LONG
cb1 = (low < blow and close < blow)
cb2 = (MA1 > MA2)
cb3 = (currenttime > Starttime and currenttime < Endtime)
cb4 = (ad > adlevel)
IF NOT Longonmarket and cb1 and cb2 and cb3 and cb4 THEN
BUY 1 CONTRACT AT MARKET
ENDIF
cb8 = close > bhigh
cb9 = LONGONMARKET AND DAYOFWEEK=5 AND TIME>=230000
IF cb8 OR cb9 Then
sell at market
endif
// SHORT
cs1 = (high > bhigh and close > bhigh)
cs2 = (MA1 < MA2)
cs3 = (currenttime > Starttime and currenttime < Endtime)
cs4 = (ad > adlevel)
IF NOT Shortonmarket and cs1 and cs2 and cs3 and cs4 THEN
SELLSHORT 1 CONTRACT AT MARKET
ENDIF
cs8 = close < blow
cs9 = SHORTONMARKET AND DAYOFWEEK=5 AND TIME>=230000
IF cs8 OR cs9 Then
Exitshort at market
endif
SET STOP pLOSS 50
Just a quick run.- It Looks like if only going short on the udsjpy ver- it gets better statistic. Long only provide 1.5%
Cheers Kasper
Hi Kasper!
Where do you find the 1,5% gain? In my backtest (100 000 bars) I have the split 53,86%/87,5% between Long/short.
1,5% would make sense on a 100 000 bars backtest because only about 3 months are positive trend, the rest is negative.
Hi Victor- I might be wrong- I will check again when home 🙂
MazParticipant
Veteran
Hi guys,
I like this one so if you don’t mind me contributing, I’ve made some modifications and thought I’d share.
- Logic optimization: The system is quite slow over many bars so I’ve made some logic optimizations to have it perform a bit faster. It makes a considerable difference during optimization. It could be further optimized, but keeping it as readable as possible for now.
- As people from all over might be working on this I’ve introduced a GMT timezone offset variable so that you can keep the same times and just change it to +1 (if in the EU) or have fun with it. It’s a clean way to shift trading time constrains forward of back with 1 number
- Stop loss selection framework – currently I’ve just got 2 options there: a static stop loss or (the one selected currently) a ATR based dynamic stop loss. This seems to perform better on USD/JPY – haven’t tested any more yet.
- Variable optimization selection framework so you can keep the same code base and dump different variable sets. (I haven’t optimized all the variables yet)
// ADX-Bollinger Mean Reversion v 1.12
// Version 0.22
//
DEFPARAM cumulateOrders = false
DEFPARAM preloadBars = 300
once positionSize = 1
once GMTOffset = 0 // Your time zone reletive to +/- GMT (in hours) 1=gmt | 2=cet
once optimization = 1
// -- Optimizations selection --
if optimization = 1 then // USD_JPY :: M5 (Jan 2016- Apr 2017)
startTime = 090000 // 100000
endTime = 230000 // 240000
fridayEndTime = 225000 //
bolUpPeriod = 20
bolDnPeriod = 20
maShrtPeriod = 8
maLongPeriod = 200
adxPeriod = 21
adxThreshold = 22
stopLossMode = 2 // 1: Static | 2: Dynamic
stopLoss = 70 // For Static stop
slATRmultiple = 6 // For Dynamic stop
elsif optimization = 2 then
// Add your optimizations here
// elsif optimization = 3 then // ... and so on
endif
// -- Time zone adjustments --
startTime = startTime + ( GMTOffset * 10000 )
endTime = endTime + ( GMTOffset * 10000 )
fridayEndTime = fridayEndTime + ( GMTOffset * 10000 )
// -- Indicators -----
bLow = BollingerDown[bolUpPeriod]
bHigh = BollingerUp[bolDnPeriod]
MA1 = average[maShrtPeriod]
MA2 = average[maLongPeriod]
ad = adx[adxPeriod]
atr = averageTrueRange[40]
// -- Entry conditions -----
// -- Common Conditions (for both long and short) --
isTradingTime = (currenttime > startTime and currenttime < endTime)
atADXLevel = (ad > adxThreshold)
isLateFriday = (dayOfWeek = 5 and time >= fridayEndTime)
if isTradingTime and atADXLevel then
// -- long conditions only --
bc1 = not longOnMarket //and isTradingTime and atADXLevel
bc1 = bc1 and (max(low, close) < bLow) //(low < bLow and close < bLow)
bc1 = bc1 and (MA1 > MA2) //and (MA2 > MA2[1])
// -- Short conditions only --
sc1 = not shortOnMarket //and isTradingTime and atADXLevel
sc1 = sc1 and (min(high, close) > bHigh) //(high > bHigh and close > bHigh)
sc1 = sc1 and (MA1 < MA2) //and (MA2 < MA2[1])
else
bc1 = 0
sc1 = 0
endif
if onMarket then
// -- Long EXIT conditions only --
le1 = longOnMarket and ( (close > bHigh) or isLateFriday )
// -- Short EXIT conditions only --
se1 = shortOnMarket and ( (close < bLow) or isLateFriday )
else
le1 = 0
se1 = 0
endif
// -- Execution Handlers -----
if bc1 then
buy positionSize contract at market
elsif sc1 then
sellShort positionSize contract at market
elsif le1 then
sell at market
elsif se1 then
exitshort at market
endif
if stopLossMode = 1 then // static stop loss
SET STOP pLOSS stopLoss
elsif stopLossMode = 2 then // dynamic ATR based stop loss
SET STOP pLOSS (atr * slATRmultiple)
elsif stopLossMode = 3 then // Time based stop
// - na -
elsif stopLossMode = 4 then // trailing stop
// - na -
endif
Hope this helps. Any questions about what I did, let me know. Cheers @ victormork, good work.
Hi Victor, I still get the same result on 100000 unit- However I had a 0 more in the initial capital- but it still off your results- what timezone are you in?
Hi Maz- I don’t get our result at all? 🙁
If I am correct you are 1 hour behind me(?) I’m at +1 GMT
here is my results from your ITF file.
what could be wrong?
Cheers Kasper
// ADX-Bollinger Mean Reversion v 1.12
// Version 0.22
//
DEFPARAM cumulateOrders = false
DEFPARAM preloadBars = 300
once positionSize = 1
once GMTOffset = 1 // Your time zone reletive to +/- GMT (in hours) 1=gmt | 2=cet
once optimization = 1
// -- Optimizations selection --
if optimization = 1 then // USD_JPY :: M5 (Jan 2016- Apr 2017)
startTime = 090000 // 100000
endTime = 230000 // 240000
fridayEndTime = 225000 // 235000
//startTime = 100000
//endTime = 240000
//fridayEndTime = 235000
bolUpPeriod = 20
bolDnPeriod = 20
maShrtPeriod = 8
maLongPeriod = 200
adxPeriod = 21
adxThreshold = 22
stopLossMode = 2 // 1: Static | 2: Dynamic
stopLoss = 70 // For Static stop
slATRmultiple = 6 // For Dynamic stop
elsif optimization = 2 then
// Add your optimizations here
// elsif optimization = 3 then // ... and so on
endif
// -- Time zone adjustments --
startTime = startTime + ( GMTOffset * 10000 )
endTime = endTime + ( GMTOffset * 10000 )
fridayEndTime = fridayEndTime + ( GMTOffset * 10000 )
// -- Indicators -----
bLow = BollingerDown[bolUpPeriod]
bHigh = BollingerUp[bolDnPeriod]
MA1 = average[maShrtPeriod]
MA2 = average[maLongPeriod]
ad = adx[adxPeriod]
atr = averageTrueRange[40]
// -- Entry conditions -----
// -- Common Conditions (for both long and short) --
isTradingTime = (currenttime > startTime and currenttime < endTime)
atADXLevel = (ad > adxThreshold)
isLateFriday = (dayOfWeek = 5 and time >= fridayEndTime)
if isTradingTime and atADXLevel then
// -- long conditions only --
bc1 = not longOnMarket //and isTradingTime and atADXLevel
bc1 = bc1 and (max(low, close) < bLow) //(low < bLow and close < bLow)
bc1 = bc1 and (MA1 > MA2) //and (MA2 > MA2[1])
// -- Short conditions only --
sc1 = not shortOnMarket //and isTradingTime and atADXLevel
sc1 = sc1 and (min(high, close) > bHigh) //(high > bHigh and close > bHigh)
sc1 = sc1 and (MA1 < MA2) //and (MA2 < MA2[1])
else
bc1 = 0
sc1 = 0
endif
if onMarket then
// -- Long EXIT conditions only --
le1 = longOnMarket and ( (close > bHigh) or isLateFriday )
// -- Short EXIT conditions only --
se1 = shortOnMarket and ( (close < bLow) or isLateFriday )
else
le1 = 0
se1 = 0
endif
// -- Execution Handlers -----
if bc1 then
buy positionSize contract at market
elsif sc1 then
sellShort positionSize contract at market
elsif le1 then
sell at market
elsif se1 then
exitshort at market
endif
if stopLossMode = 1 then // static stop loss
SET STOP pLOSS stopLoss
elsif stopLossMode = 2 then // dynamic ATR based stop loss
SET STOP pLOSS (atr * slATRmultiple)
elsif stopLossMode = 3 then // Time based stop
// - na -
elsif stopLossMode = 4 then // trailing stop
// - na -
endif
MazParticipant
Veteran
Not sure, Kasper. I have tried playing with the time zones and here are 3 different results attached. I see from the screen shot your results are displayed in Yen? Not sure what data feed or vehicle to market you are using or if that has something to do with it? I’m sure it’s something simple.