Exit Discrepancy: Automated vs. BackTested
Posted: Oct 27 2019
I created a strategy for trading the NASDAQ 100 emini futures on 23 minute price bars. It was running as an automated strategy on 10/24/19.
There was one trade that day which lost $870. The actual entry is fairly close to what shows up in the current back-test (i.e. short entry at 7920.75
in the back-test, while the actual short entry was at 7920 - so 3 ticks of slippage). However, the exit does not agree at all with the back-test. The back-test shows an exit labelled with the designation "ExStp-S2". The Positions History tab of the Orders and Positions Tracker Window shows that the short position was actually entered at 10:06:00 AM. This agrees with the closing time of the price bar before the entry on the chart, and corresponds to the opening time of the price bar on which the entry occurs in the back-test. I do not use Intrabar Order Generation in the strategy. I slightly modified the strategy to print out the stop-loss values bar by bar on the day of interest. According to the strategy code, the stop-loss values will be active on the next price bar - not the current price bar. The output window shows these stop-loss values for the trade:
Time = 1029 BarsSinceEntry = 0 StopLoss_S = 7953.25000
Time = 1052 BarsSinceEntry = 1 StopLoss_S = 7971.25000
Time = 1115 BarsSinceEntry = 2 StopLoss_S = 7985.25000
Time = 1138 BarsSinceEntry = 3 StopLoss_S = 7995.25000
Time = 1201 BarsSinceEntry = 4 StopLoss_S = 8001.25000
Time = 1224 BarsSinceEntry = 5 StopLoss_S = 8003.25000
Time = 1247 BarsSinceEntry = 6 StopLoss_S = 8001.25000
Time = 1310 BarsSinceEntry = 7 StopLoss_S = 7995.25000
Time = 1333 BarsSinceEntry = 8 StopLoss_S = 7985.25000
Time = 1356 BarsSinceEntry = 9 StopLoss_S = 7971.25000
Time = 1419 BarsSinceEntry = 10 StopLoss_S = 7953.25000
The back-test shows the trade being stopped out on the open of the bar following the 14:19 price bar at a price of 7954, which makes sense. Adjusting the printed stop-loss values 3 ticks lower because of slippage of the actual entry price will not change the outcome that the trade should be stopped out on the open of the 11th bar of the trade at 7954.
However, in reality, the trade was not stopped out and continued until 14:42 (2:42 PM), another 23 minutes (the period of another price bar). My recollection is that the chart on that day showed that there was a market exit ("ExMark-S") based on a different exit criteria - if barssinceentry >= NBarEx1 (which is equal to 11) then buytocover next bar at market. The question is why the stop-loss did not work in the real world. I do not understand why? Can anyone explain this? Instead of losing $700 (as in the back-test) , I lost $870 (reality) - 24% more. I really need to determine why this discrepancy occurred.
Here is the exit-related code. I did not remove the declarations of some of the entry-related inputs and variables, but the entry logic is not shown:
There was one trade that day which lost $870. The actual entry is fairly close to what shows up in the current back-test (i.e. short entry at 7920.75
in the back-test, while the actual short entry was at 7920 - so 3 ticks of slippage). However, the exit does not agree at all with the back-test. The back-test shows an exit labelled with the designation "ExStp-S2". The Positions History tab of the Orders and Positions Tracker Window shows that the short position was actually entered at 10:06:00 AM. This agrees with the closing time of the price bar before the entry on the chart, and corresponds to the opening time of the price bar on which the entry occurs in the back-test. I do not use Intrabar Order Generation in the strategy. I slightly modified the strategy to print out the stop-loss values bar by bar on the day of interest. According to the strategy code, the stop-loss values will be active on the next price bar - not the current price bar. The output window shows these stop-loss values for the trade:
Time = 1029 BarsSinceEntry = 0 StopLoss_S = 7953.25000
Time = 1052 BarsSinceEntry = 1 StopLoss_S = 7971.25000
Time = 1115 BarsSinceEntry = 2 StopLoss_S = 7985.25000
Time = 1138 BarsSinceEntry = 3 StopLoss_S = 7995.25000
Time = 1201 BarsSinceEntry = 4 StopLoss_S = 8001.25000
Time = 1224 BarsSinceEntry = 5 StopLoss_S = 8003.25000
Time = 1247 BarsSinceEntry = 6 StopLoss_S = 8001.25000
Time = 1310 BarsSinceEntry = 7 StopLoss_S = 7995.25000
Time = 1333 BarsSinceEntry = 8 StopLoss_S = 7985.25000
Time = 1356 BarsSinceEntry = 9 StopLoss_S = 7971.25000
Time = 1419 BarsSinceEntry = 10 StopLoss_S = 7953.25000
The back-test shows the trade being stopped out on the open of the bar following the 14:19 price bar at a price of 7954, which makes sense. Adjusting the printed stop-loss values 3 ticks lower because of slippage of the actual entry price will not change the outcome that the trade should be stopped out on the open of the 11th bar of the trade at 7954.
However, in reality, the trade was not stopped out and continued until 14:42 (2:42 PM), another 23 minutes (the period of another price bar). My recollection is that the chart on that day showed that there was a market exit ("ExMark-S") based on a different exit criteria - if barssinceentry >= NBarEx1 (which is equal to 11) then buytocover next bar at market. The question is why the stop-loss did not work in the real world. I do not understand why? Can anyone explain this? Instead of losing $700 (as in the back-test) , I lost $870 (reality) - 24% more. I really need to determine why this discrepancy occurred.
Here is the exit-related code. I did not remove the declarations of some of the entry-related inputs and variables, but the entry logic is not shown:
Code: Select all
Inputs:
a2(-40),
b2(400),
c2(650);
{ Strategy inputs }
Inputs: Wgt1 (-0.7884), { Neural network weight value (-1 to 1) }
FirstEntryTm (943), { Earliest allowable trade entry time (HHMM) }
LastEntryTm (1505), { Latest allowable trade entry time (HHMM) }
NBarEn1 (15), { Indicator look-back length (bars) }
NBarEn3 (24), { Price pattern look-back length (bars) }
EntFr (2.5632), { Multiple of price difference (e.g., ATR); entry }
NBarEx1 (11), { Number of bars from entry for market exit }
NBarEx2 (30), { Number of bars from entry for market exit if unprofitable }
NATR (59), { Indicator look-back length (bars) }
ATRFrTrail (1.2481), { Multiple of price difference (e.g., ATR); exit }
TrailPct (11.0000), { Trailing stop percentage }
PSParam (1.00), { Position sizing parameter value }
RoundPS (true), { Round-to-nearest (true/false) }
RoundTo (1), { Round-to position size value }
MinSize (1), { Minimum allowable position size }
SizeLimit (50);
{ Variables for entry and exit prices }
Var: EntPrS (0),
SStop (0),
NewSStop (0),
STrailOn (false);
{ Variables for average true range for entry and exit orders }
Var: AveTR (0),
MyBound2(0),
StopLoss_S(0);
{ Average true range }
AveTR = AvgTrueRange(NATR);
{ Exit orders, short trades }
If MarketPosition = -1 then begin
If BarsSinceEntry = 0 then begin
SStop = Power(10, 10);
STrailOn = false;
end;
If EntryPrice - C > ATRFrTrail * AveTR then
STrailOn = true;
If STrailOn then begin
NewSStop = EntryPrice - TrailPct * (EntryPrice - C)/100.0;
SStop = MinList(SStop, NewSStop);
end;
If STrailOn then
Buy to cover("ExTrail-S") next bar at SStop stop;
If BarsSinceEntry >= NBarEx1 or (BarsSinceEntry >= NBarEx2 and C > EntryPrice) then
Buy to cover("ExMark-S") next bar at market;
MyBound2 = a2 * (BarsSinceEntry * BarsSinceEntry) + b2 * BarsSinceEntry + c2;
StopLoss_S = EntryPrice + MyBound2/BigPointValue;
BuyToCover("ExStp-S2") next bar at {(EntryPrice + MyBound2/BigPointValue)} StopLoss_S Stop;
If Date = 1191024 then begin
Print("Time = ",Time:0:0," BarsSinceEntry = ",BarsSinceEntry:0:0," StopLoss_S = ", StopLoss_S:0:5);
end;
end;
If MarketPosition = 0 then begin
SetStopShare;
SetStopLoss(c2);
end;