An ES Break-Out System with Unexpected Parameters
I was recently testing the idea of a short term VBO strategy on ES utilizing very tight stops. I wanted to see if using a tight ATR stop in concert with the entry day’s low (for buys) would cut down on losses after a break out. In other words, if the break out doesn’t go as anticipated get out and wait for the next signal. With the benefit of hindsight in writing this post, I certainly felt like my exit mechanism was what was going to make or break this system. It turns out that all pre-conceived notions should be thrown out when volatility enters the picture.
- If 14 ADX < 20 get ready to trade
- Buy 1 ATR above the midPoint of the past 4 closing prices
- Place an initial stop at 1 ATR and a Profit Objective of 1 ATR
- Trail the stop up to the prior day’s low if it is greater than entryPrice – 1 ATR initially, and then trail if a higher low is established
- Wait 3 bars to Re-Enter after going flat – Reversals allowed
That’s it. Basically wait for a trendless period and buy on the bulge and then get it out if it doesn’t materialize. I knew I could improve the system by optimizing the parameters but I felt I was in the ball park. My hypothesis was that the system would fail because of the tight stops. I felt that the ADX trigger was OK and the BO level would get in on a short burst. Just from past experience I knew that using the prior day’s price extremes as a stop usually doesn’t fair that well.
Without commission the initial test was a loser: -$1K and -$20K draw down over the past 10 years. I thought I would test my hypothesis by optimizing a majority of the parameters:
- ADX Len
- ADX Trigger Value
- ATR Len
- ATR BO multiplier
- ATR Multiplier for Trade Risk
- ATR Multiplier for Profit Objective
- Number of bars to trail the stop – used lowest lows for longs
As you can probably figure, I had to use the Genetic Optimizer to get the job done. Over a billion different permutations. In the end here is what the computer pushed out using the best set of parameters.
Optimization Report – The Best of the Best
ADX – Does it Really Matter?
Take a look at the chart – the ADX is mostly in Trigger territory – does it really matter?
A Chart is Worth a 1,000 Words
What does this chart tell us?
Was the parameter selection biased by the heightened level of volatility? The system has performed on the parameter set very well over the past two or three years. But should you use this parameter set going into the future – volatility will eventually settle down.
Now using my experience in trading I would have selected a different parameter set. Here are my biased results going into the initial programming. I would use a wider stop for sure, but I would have used the generic ADX values.
I would have used 14 ADX Len with a 20-trigger, and risk 1 to make 3 and use a wider trailing stop. With trend neutral break out algorithms, it seems you have to be in the game all of the time. The ADX was supposed to capture zones that predicated break out moves, but the ADX didn’t help out at all. Wider stops helped but it was the ADX values that really changed the complexion of the system. Also the number of bars to wait after going flat had a large impact as well. During low volatility you can be somewhat picky with trades but when volatility increases you got to be in the game – no ADX filtering and no delay in re-Entry. Surprise, surprise!
Here is the code – some neat stuff here if you are just learning EL. Notice how I anchor some of the indicator based variables by indexing them by barsSinceEntry. Drop me a note if you see something wrong or want a little further explanation.
Inputs: adxLen(14),adxTrig(25),atrLen(10),atrBOMult(1),atrRiskMult(1),atrProfMult(2),midPtNumBar(3),posMovTrailNumBars(2),reEntryDelay(3); vars: mp(0),trailLongStop(0),trailShortStop(0),BSE(999),entryBar(0),tradeRisk(0),tradeProf(0); vars: BBO(0),SBO(0),ATR(0),totTrades(0); mp = marketPosition; totTrades = totalTrades; BSE = barsSinceExit(1); If totTrades <> totTrades then BSE = 0; If totalTrades = 0 then BSE = 99; ATR = avgTrueRange(atrLen); SBO = midPoint(c,midPtNumBar) - ATR * atrBOMult; BBO = midPoint(c,midPtNumBar) + ATR * atrBOMult; tradeRisk = ATR * atrRiskMult; tradeProf = ATR * atrProfMult; If mp <> 1 and adx(adxLen) < adxTrig and BSE > reEntryDelay and open of next bar < BBO then buy next bar at BBO stop; If mp <>-1 and adx(adxLen) < adxTrig AND BSE > reEntryDelay AND open of next bar > SBO then sellshort next bar at SBO stop; If mp = 1 and mp <> 1 then Begin trailLongStop = entryPrice - tradeRisk; end; If mp = -1 and mp <> -1 then Begin trailShortStop = entryPrice + tradeRisk; end; if mp = 1 then sell("L-init-loss") next bar at entryPrice - tradeRisk[barsSinceEntry] stop; if mp = -1 then buyToCover("S-init-loss") next bar at entryPrice + tradeRisk[barsSinceEntry] stop; if mp = 1 then begin sell("L-ATR-prof") next bar at entryPrice + tradeProf[barsSinceEntry] limit; trailLongStop = maxList(trailLongStop,lowest(l,posMovTrailNumBars)); sell("L-TL-Stop") next bar at trailLongStop stop; end; if mp =-1 then begin buyToCover("S-ATR-prof") next bar at entryPrice -tradeProf[barsSinceEntry] limit; trailShortStop = minList(trailShortStop,highest(h,posMovTrailNumBars)); // print(d, " Short and trailStop is : ",trailShortStop); buyToCover("S-TL-Stop") next bar at trailShortStop stop; end;
- By George Pruitt from blog, George Pruitt