I am using High Order Fill Resolution! This seems to be important to see the issue.
I have a strategy that does the following during historical backtesting.
1) If flat and some conditions are true, then I EnterLong
2) In OnExecutionUpdate, I submit an ExitLongStopMarket with a certain stop price
On subsequent bars in OnBarUpdate, my code continues to test if we're flat and if we are flat, then may submit a new entry order.
It's pretty simple.
What I've found is that the stop exit appears to execute a full bar early sometimes which leaves the position flat and a new entry order is submitted in OnBarUpdate.
Then we're actually entering with a market order at the next bar open BEFORE the stop order would have exited during that next bar.
I seem to recall reading something in the documentation about orders submitted from OnExecutionUpdate, that the processing engine will actually look ahead one bar when processing.
This seems to be confirmed by my observations, but I would really like to know why this is done this way.
This seems to violate the most sacred tenet of back testing that you should never use future information.
Plus it creates situations that couldn't happen in the real world. I would never have entered that entry order until one bar later because the position would still be open until the middle of the next bar when it gets stopped out.
I suspect you know what I'm talking about here, but if not, see the sample strategy code below to recreate the scenario.
To be clear, I think this behavior is probably intentional by NT. I would just like to understand why.
Thanks,
Steve
using NinjaTrader.Cbi; using NinjaTrader.Data; using System; // This namespace holds all strategies and is required. Do not change it. namespace NinjaTrader.NinjaScript.Strategies.Test { public class EarlyExecutionTest : Strategy { protected override void OnBarUpdate() { // Load "ES 09-12" Day bars from 5/1/2012 - 8/1/2012 if (Time[0].Date == DateTime.Parse("2012-06-13").Date) { var order = EnterShort("Entry1"); } if (Time[0].Date == DateTime.Parse("2012-06-15").Date) { if (Position.MarketPosition == MarketPosition.Flat) { // This entry happens at the open of the 6/18 bar, but the // previous position doesn't "technically" exit until // some time during the 6/18 bar, after the open. EnterLong(); } } if (Time[0].Date == DateTime.Parse("2012-06-22").Date) { ExitLong(); } } protected override void OnExecutionUpdate(Execution execution, string executionId, double price, int quantity, MarketPosition marketPosition, string orderId, DateTime time) { if (execution.Order.Name == "Entry1") { ExitShortStopMarket(0, true, 1, 1347, "", ""); } } protected override void OnStateChange() { if (State == State.SetDefaults) { Name = "Early Execution Test"; IsExitOnSessionCloseStrategy = false; Slippage = 0; TraceOrders = true; BarsRequiredToTrade = 0; EntriesPerDirection = 1; OrderFillResolution = OrderFillResolution.High; OrderFillResolutionType = BarsPeriodType.Minute; OrderFillResolutionValue = 1; } } } }
Comment