Announcement

Collapse
No announcement yet.

Partner 728x90

Collapse

Best way to backtest with OnEachTick and Strategy Analyzer?

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    Best way to backtest with OnEachTick and Strategy Analyzer?

    Hi,

    Hope all is well. I have a strategy, that utilizes OnEachTick, that I'm trying to backtest through strategy analyzer. I just wanted to ask, besides setting Order Fill Resolution on High to Tick, is there any other way to ensure highest accuracy?

    Thanks for your time.

    #2
    Hello ComfyCouch,

    Testing OnEachTick specifically would require using realtime, in backtests the script is always executed OnBarClose. You can simulate OnEachTick logic by using a 1 tick series in your script. Using the high fill resolution would not be an equivalent, that is only for fills and not your logic.



    You can see the following example of how to simulate more granular logic in a backtest, a secondary series can be used and then OnBarUpdate can be called at that frequency: https://ninjatrader.com/support/help...ipt_strate.htm

    Comment


      #3
      Thanks for the reply Jesse.

      In the example code, was there a mistake listed in the commented lines in which he refers to the secondary data series as a 1 minute data series and not a 1 tick data series? In State == State.Configure, he adds a secondary tick data series and below, he refers to his secondary data series as a 1 minute data series.

      if (BarsInProgress == 0)
      {
      // When the fast EMA crosses above the slow EMA, enter long on the secondary (1min) bar series
      if (CrossAbove(EMA(Fast), EMA(Slow), 1))
      {
      /* The entry condition is triggered on the primary bar series, but the order is sent and filled on the
      secondary bar series. The way the bar series is determined is by the first parameter: 0 = primary bars,
      1 = secondary bars, 2 = tertiary bars, etc. */
      EnterLong(1, 1, "Long: 1min");
      }
      Last edited by ComfyCouch; 07-19-2022, 11:26 AM.

      Comment


        #4
        Hello ComfyCouch,

        BarsInProgress 0 would be the primary so that sample is saying the primary was 1 minute.

        The entry is being submitted to BarsInProgress 1 which is the secondary.

        If you have logic that needs to be calculated OnEachTick that would also go within a condition like the following:
        Code:
        if (BarsInProgress == 0) //primary
        {
        
        }
        if (BarsInProgress == 1) //secondary
        {
             // logic that needs calculated at the frequency of 1 tick
        }

        Comment


          #5
          Here's what I have going so far. Would this be the correct way of introducing a one tick data series in a strategy for intrabar fills? Furthermore, would doing this, and enabling Tick Replay, provide the closest amount of accuracy for accurate backtests?

          Code:
          protected override void OnStateChange()
          {
          if (State == State.SetDefaults)
          {
          Description = @"Enter the description for your new custom Strategy here.";
          Name = "UsingOnEachTick";        
          Calculate = Calculate.OnEachTick;      [I][B]/* #1 - I calculate using Calculate.OnEachTick. */[/B][/I]
          RealtimeErrorHandling = RealtimeErrorHandling.IgnoreAllErrors;
          StopTargetHandling = StopTargetHandling.PerEntryExecution;
          
          
          ProfitTick = 8;
          StopLoss = 4;
          Addition = .25;
          
          }
          else if (State == State.Configure)
          {
          
          AddDataSeries(Data.BarsPeriodType.Tick, 1);          [B][I]/* #2 - I add a 1 tick data series (secondary data series) to be able to have intrabar fills. */[/I][/B]
          SetProfitTarget(@"Long", CalculationMode.Ticks, ProfitTick);
          SetStopLoss(@"Long", CalculationMode.Ticks, StopLoss, true);
          SetProfitTarget(@"Short", CalculationMode.Ticks, ProfitTick);
          SetStopLoss(@"Short", CalculationMode.Ticks, StopLoss, true);
          }
          }
          
          protected override void OnBarUpdate()
          {
          if (CurrentBars[0] < 56)
          return;
          
          if (BarsInProgress == 0)
          {
          
          [B][I]// #3 - Logic needed for the strategy would be here and calculated on the primary data series (in this case, I'd be using a 30 second chart as my primary data series). [/I][/B]
          
          [I]//Long[/I]
          if ([B][I]/* #4 - Conditions for a long entry, using logic from #3.*/ [/I][/B])
          {
          EnterLongStopLimit(1, false, 1, Low[1] + Addition, Low[1] + Addition, @"Long");       [B][I]/* #5 - Using barsInProgressIndex = 1, I am submitting this order on the secondary data series, a 1 tick data series, to gain intrabar fills when the condition(s) in #4 are true. */[/I][/B]
          }
          
          //Short
          if ([I][B]/* #6 - Conditions for a short entry, using logic from #3.*/[/B][/I]) 
          {
          EnterShortStopLimit(1, false, 1, High[1] - Addition, High[1] - Addition, @"Short");       /[B][I]* #7 - Using barsInProgressIndex = 1, I am submitting this order on the secondary data series, a 1 tick data series, to gain intrabar fills when the condition(s) in #6 are true. */[/I][/B]
          }
          }
          else
          {
          return;
          }
          }

          Comment


            #6
            Hey Jesse, did you get a chance to look at my reply above?

            Thanks.

            Comment


              #7
              Hello ComfyCouch,

              Using tick replay will not aid in more accurate fills, TickReplay is for a specific programming purpose to have the OnMarketData override called in historical. That provides an estimate of ask/bid events at the time of the last so that would still not be completely accurate to realtime testing.

              In the code you provided that will submit the orders to the secondary for Fills. If you need to have that condition executed at a faster rate then you would need to place that logic in BarsInProgress 1 instead of 0, as it is now it will check the condition at the rate of the primary and submit the order to the secondary.

              Comment


                #8
                Understood. I think I've managed to figure it out and revised my code (and tested it) based off of your suggestions/help. The orders have been submitting on a tick by tick basis (from what I've seen). However, I've encountered a different challenge now and would appreciate any help/advice that could steer me in the right direction.

                After submitting my orders in a secondary data series (1 tick chart) using BarsInProgress == 1, I've found that the orders are cancelled (rightfully) if it is not filled by the next bar. Ideally, I'd only like the order to be cancelled, if not filled by the next bar, on the primary data series. To counter this, I make the bool argument IsLiveUntilCancelled equal to true while also using CancelOrder to ensure that the order is cancelled after the next bar on the primary data series. However, I'm having trouble in that when using market replay to test this strategy/code, it seems like the order still prevails after the next bar opens and does not cancel until being filled or until another condition becomes true.

                Here's the code below:

                Code:
                private Order entryOrder         = null;
                private int savedBar                 = 0;
                
                protected override void OnStateChange()
                {
                if (State == State.SetDefaults)
                {
                Description = @"Enter the description for your new custom Strategy here.";
                Name = "UsingOnEachTick";        
                Calculate = Calculate.OnEachTick;  
                RealtimeErrorHandling = RealtimeErrorHandling.IgnoreAllErrors;
                StopTargetHandling = StopTargetHandling.PerEntryExecution;
                
                
                ProfitTick = 8;
                StopLoss = 4;
                Addition = .25;
                
                }
                else if (State == State.Configure)
                {
                
                AddDataSeries(Data.BarsPeriodType.Tick, 1);      
                SetProfitTarget(@"Long", CalculationMode.Ticks, ProfitTick);
                SetStopLoss(@"Long", CalculationMode.Ticks, StopLoss, true);
                SetProfitTarget(@"Short", CalculationMode.Ticks, ProfitTick);
                SetStopLoss(@"Short", CalculationMode.Ticks, StopLoss, true);
                }
                }
                
                protected override void OnBarUpdate()
                {
                if (CurrentBars[0] < 56)
                return;
                
                if (BarsInProgress == 0)
                {
                [B][I]// [/I] #1 - Logic needed for strategy would be here and calculated on the primary data series (in this case, I'd be using a 30 second chart as my primary data series).[/B]
                
                [I][B]// ***[/B][/I]
                Print(string.Format("{0} | CurrentBar is: {1}", Time[0], CurrentBar));
                }
                
                else if (BarsInProgress == 1)
                {
                [I]//Long[/I]
                if (entryOrder == null && [B][I]/* #2 - Conditions for a long entry, using logic from #1. */ [/I][/B])
                {
                [B][I]// #3 - Using BarsInProgress == 1, the orders are successfully submitting on a one tick chart while also utilizing Low prices from primary data series. We also utilize make the bool argument isLiveUntilCancelled == true as the orders submitted on a one tick chart will cancel after one bar, whereas we want it to cancel after one bar on the primary data series.[/I][/B]
                EnterLongStopLimit(1, true, 1, Lows[0][1] + Addition, Lows[0][1] + Addition, @"Long");
                
                [B][I]// #4 - We assign savedBar the current bar in the primary data series.[/I][/B]
                [I]savedBar = CurrentBars[0];[/I]
                
                [B][I]// *** [/I][/B]
                Print(string.Format("{0} | Entering long at: {1}. CurrentBars[0] is: {2}. savedBar (which should be equal to CurrentBars[0] is: {3}.", Time[0], Lows[0][1] + Addition, CurrentBars[0], savedBar));    
                }
                
                [B][I]// #5 - If the entryOrder is not filled after one bar, we cancel the order.[/I][/B]
                else if (entryOrder != null && CurrentBars[0] > savedBar + 1)
                {
                CancelOrder(entryOrder);
                
                [B]// ***[/B]
                Print(string.Format("{0} | Canceling long order. CurrentBars[0] is: {1}. savedBar + 1 (which should be equal to CurrentBars[0] is: {2}.", Time[0], CurrentBars[0], savedBar + 1));
                }
                }
                }
                
                protected override void OnOrderUpdate(Order order, double limitPrice, double stopPrice, int quantity, int filled, double averageFillPrice, OrderState orderState, DateTime time, ErrorCode error, string nativeError)
                {
                if (entryOrder != null && order.Name == @"Long")
                {
                entryOrder = order;
                
                if (order.OrderState == OrderState.Cancelled)
                {
                
                [B][I]// If entryOrder is cancelled, then we reset entryOrder back to null and proceed to wait again until CancelOrder is called in OnBarUpdate().[/I][/B]
                entryOrder = null;
                }
                }
                }

                EDIT:

                I enabled TraceOrders and added Print statements in the following (labeled with commented asterisks above):

                - After BarsInProgress == 0
                - After EnterLongStopLimit()
                - After CancelOrder().


                Here's what came up (highlighted before and after the order being submitted and not being filled in bold):

                5/18/202211:58:30 AM | CurrentBar is: 7673
                5/18/2022 11:59:00 AM | CurrentBar is: 7674
                5/18/2022 11:58:42 AM Strategy 'UsingOnEachTick/218259144': Entered internal SubmitOrderManaged() method at 5/18/2022 11:58:42 AM: BarsInProgress=1 Action=Buy OrderType=StopLimit Quantity=1 LimitPrice=12127.00 StopPrice=12127.00 SignalName='Long' FromEntrySignal=''
                5/18/2022 11:58:41 AM | Entering long at: 12127. CurrentBars[0] is: 7674. savedBar (which should be equal to CurrentBars[0] is: 7674.

                5/18/2022 11:58:42 AM Strategy 'UsingOnEachTick/218259144': Entered internal SubmitOrderManaged() method at 5/18/2022 11:58:42 AM: BarsInProgress=1 Action=Buy OrderType=StopLimit Quantity=1 LimitPrice=12127.00 StopPrice=12127.00 SignalName='Long' FromEntrySignal=''
                5/18/2022 11:58:42 AM Strategy 'UsingOnEachTick/218259144': Ignored SubmitOrderManaged() method at 5/18/2022 11:58:42 AM: BarsInProgress=1 Action=Buy OrderType=StopLimit Quantity=1 LimitPrice=12127.00 StopPrice=12127.00 SignalName='Long' FromEntrySignal='' Reason='There already is a matching order with same prices and quantity'
                5/18/2022 11:58:41 AM | Entering long at: 12127. CurrentBars[0] is: 7674. savedBar (which should be equal to CurrentBars[0] is: 7674.
                5/18/2022 11:58:42 AM Strategy 'UsingOnEachTick/218259144': Entered internal SubmitOrderManaged() method at 5/18/2022 11:58:42 AM: BarsInProgress=1 Action=Buy OrderType=StopLimit Quantity=1 LimitPrice=12127.00 StopPrice=12127.00 SignalName='Long' FromEntrySignal=''
                5/18/2022 11:58:42 AM Strategy 'UsingOnEachTick/218259144': Ignored SubmitOrderManaged() method at 5/18/2022 11:58:42 AM: BarsInProgress=1 Action=Buy OrderType=StopLimit Quantity=1 LimitPrice=12127.00 StopPrice=12127.00 SignalName='Long' FromEntrySignal='' Reason='There already is a matching order with same prices and quantity'
                5/18/2022 11:58:41 AM | Entering long at: 12127. CurrentBars[0] is: 7674. savedBar (which should be equal to CurrentBars[0] is: 7674.
                5/18/2022 11:58:42 AM Strategy 'UsingOnEachTick/218259144': Entered internal SubmitOrderManaged() method at 5/18/2022 11:58:42 AM: BarsInProgress=1 Action=Buy OrderType=StopLimit Quantity=1 LimitPrice=12127.00 StopPrice=12127.00 SignalName='Long' FromEntrySignal=''
                5/18/2022 11:58:42 AM Strategy 'UsingOnEachTick/218259144': Ignored SubmitOrderManaged() method at 5/18/2022 11:58:42 AM: BarsInProgress=1 Action=Buy OrderType=StopLimit Quantity=1 LimitPrice=12127.00 StopPrice=12127.00 SignalName='Long' FromEntrySignal='' Reason='There already is a matching order with same prices and quantity'
                5/18/2022 11:58:41 AM | Entering long at: 12127. CurrentBars[0] is: 7674. savedBar (which should be equal to CurrentBars[0] is: 7674.
                5/18/2022 11:58:43 AM Strategy 'UsingOnEachTick/218259144': Entered internal SubmitOrderManaged() method at 5/18/2022 11:58:43 AM: BarsInProgress=1 Action=Buy OrderType=StopLimit Quantity=1 LimitPrice=12127.00 StopPrice=12127.00 SignalName='Long' FromEntrySignal=''
                5/18/2022 11:58:43 AM Strategy 'UsingOnEachTick/218259144': Ignored SubmitOrderManaged() method at 5/18/2022 11:58:43 AM: BarsInProgress=1 Action=Buy OrderType=StopLimit Quantity=1 LimitPrice=12127.00 StopPrice=12127.00 SignalName='Long' FromEntrySignal='' Reason='There already is a matching order with same prices and quantity'
                5/18/2022 11:58:42 AM | Entering long at: 12127. CurrentBars[0] is: 7674. savedBar (which should be equal to CurrentBars[0] is: 7674.
                5/18/2022 11:58:43 AM Strategy 'UsingOnEachTick/218259144': Entered internal SubmitOrderManaged() method at 5/18/2022 11:58:43 AM: BarsInProgress=1 Action=Buy OrderType=StopLimit Quantity=1 LimitPrice=12127.00 StopPrice=12127.00 SignalName='Long' FromEntrySignal=''
                5/18/2022 11:58:43 AM Strategy 'UsingOnEachTick/218259144': Ignored SubmitOrderManaged() method at 5/18/2022 11:58:43 AM: BarsInProgress=1 Action=Buy OrderType=StopLimit Quantity=1 LimitPrice=12127.00 StopPrice=12127.00 SignalName='Long' FromEntrySignal='' Reason='There already is a matching order with same prices and quantity'
                5/18/2022 11:58:42 AM | Entering long at: 12127. CurrentBars[0] is: 7674. savedBar (which should be equal to CurrentBars[0] is: 7674.
                5/18/2022 11:58:43 AM Strategy 'UsingOnEachTick/218259144': Entered internal SubmitOrderManaged() method at 5/18/2022 11:58:43 AM: BarsInProgress=1 Action=Buy OrderType=StopLimit Quantity=1 LimitPrice=12127.00 StopPrice=12127.00 SignalName='Long' FromEntrySignal=''
                5/18/2022 11:58:43 AM Strategy 'UsingOnEachTick/218259144': Ignored SubmitOrderManaged() method at 5/18/2022 11:58:43 AM: BarsInProgress=1 Action=Buy OrderType=StopLimit Quantity=1 LimitPrice=12127.00 StopPrice=12127.00 SignalName='Long' FromEntrySignal='' Reason='There already is a matching order with same prices and quantity'
                5/18/2022 11:58:42 AM | Entering long at: 12127. CurrentBars[0] is: 7674. savedBar (which should be equal to CurrentBars[0] is: 7674.
                5/18/2022 11:58:43 AM Strategy 'UsingOnEachTick/218259144': Entered internal SubmitOrderManaged() method at 5/18/2022 11:58:43 AM: BarsInProgress=1 Action=Buy OrderType=StopLimit Quantity=1 LimitPrice=12127.00 StopPrice=12127.00 SignalName='Long' FromEntrySignal=''
                5/18/2022 11:58:43 AM Strategy 'UsingOnEachTick/218259144': Ignored SubmitOrderManaged() method at 5/18/2022 11:58:43 AM: BarsInProgress=1 Action=Buy OrderType=StopLimit Quantity=1 LimitPrice=12127.00 StopPrice=12127.00 SignalName='Long' FromEntrySignal='' Reason='There already is a matching order with same prices and quantity'
                5/18/2022 11:58:42 AM | Entering long at: 12127. CurrentBars[0] is: 7674. savedBar (which should be equal to CurrentBars[0] is: 7674.
                5/18/2022 11:58:44 AM Strategy 'UsingOnEachTick/218259144': Entered internal SubmitOrderManaged() method at 5/18/2022 11:58:44 AM: BarsInProgress=1 Action=Buy OrderType=StopLimit Quantity=1 LimitPrice=12127.00 StopPrice=12127.00 SignalName='Long' FromEntrySignal=''
                5/18/2022 11:58:44 AM Strategy 'UsingOnEachTick/218259144': Ignored SubmitOrderManaged() method at 5/18/2022 11:58:44 AM: BarsInProgress=1 Action=Buy OrderType=StopLimit Quantity=1 LimitPrice=12127.00 StopPrice=12127.00 SignalName='Long' FromEntrySignal='' Reason='There already is a matching order with same prices and quantity'
                5/18/2022 11:58:43 AM | Entering long at: 12127. CurrentBars[0] is: 7674. savedBar (which should be equal to CurrentBars[0] is: 7674.
                5/18/2022 11:58:44 AM Strategy 'UsingOnEachTick/218259144': Entered internal SubmitOrderManaged() method at 5/18/2022 11:58:44 AM: BarsInProgress=1 Action=Buy OrderType=StopLimit Quantity=1 LimitPrice=12127.00 StopPrice=12127.00 SignalName='Long' FromEntrySignal=''
                5/18/2022 11:58:44 AM Strategy 'UsingOnEachTick/218259144': Ignored SubmitOrderManaged() method at 5/18/2022 11:58:44 AM: BarsInProgress=1 Action=Buy OrderType=StopLimit Quantity=1 LimitPrice=12127.00 StopPrice=12127.00 SignalName='Long' FromEntrySignal='' Reason='There already is a matching order with same prices and quantity'
                5/18/2022 11:58:43 AM | Entering long at: 12127. CurrentBars[0] is: 7674. savedBar (which should be equal to CurrentBars[0] is: 7674.
                5/18/2022 11:58:44 AM Strategy 'UsingOnEachTick/218259144': Entered internal SubmitOrderManaged() method at 5/18/2022 11:58:44 AM: BarsInProgress=1 Action=Buy OrderType=StopLimit Quantity=1 LimitPrice=12127.00 StopPrice=12127.00 SignalName='Long' FromEntrySignal=''
                5/18/2022 11:58:44 AM Strategy 'UsingOnEachTick/218259144': Ignored SubmitOrderManaged() method at 5/18/2022 11:58:44 AM: BarsInProgress=1 Action=Buy OrderType=StopLimit Quantity=1 LimitPrice=12127.00 StopPrice=12127.00 SignalName='Long' FromEntrySignal='' Reason='There already is a matching order with same prices and quantity'
                5/18/2022 11:58:43 AM | Entering long at: 12127. CurrentBars[0] is: 7674. savedBar (which should be equal to CurrentBars[0] is: 7674.
                5/18/2022 11:58:44 AM Strategy 'UsingOnEachTick/218259144': Entered internal SubmitOrderManaged() method at 5/18/2022 11:58:44 AM: BarsInProgress=1 Action=Buy OrderType=StopLimit Quantity=1 LimitPrice=12127.00 StopPrice=12127.00 SignalName='Long' FromEntrySignal=''
                5/18/2022 11:58:44 AM Strategy 'UsingOnEachTick/218259144': Ignored SubmitOrderManaged() method at 5/18/2022 11:58:44 AM: BarsInProgress=1 Action=Buy OrderType=StopLimit Quantity=1 LimitPrice=12127.00 StopPrice=12127.00 SignalName='Long' FromEntrySignal='' Reason='There already is a matching order with same prices and quantity'
                5/18/2022 11:58:43 AM | Entering long at: 12127. CurrentBars[0] is: 7674. savedBar (which should be equal to CurrentBars[0] is: 7674.
                5/18/2022 11:58:44 AM Strategy 'UsingOnEachTick/218259144': Entered internal SubmitOrderManaged() method at 5/18/2022 11:58:44 AM: BarsInProgress=1 Action=Buy OrderType=StopLimit Quantity=1 LimitPrice=12127.00 StopPrice=12127.00 SignalName='Long' FromEntrySignal=''
                5/18/2022 11:58:44 AM Strategy 'UsingOnEachTick/218259144': Ignored SubmitOrderManaged() method at 5/18/2022 11:58:44 AM: BarsInProgress=1 Action=Buy OrderType=StopLimit Quantity=1 LimitPrice=12127.00 StopPrice=12127.00 SignalName='Long' FromEntrySignal='' Reason='There already is a matching order with same prices and quantity'
                5/18/2022 11:58:43 AM | Entering long at: 12127. CurrentBars[0] is: 7674. savedBar (which should be equal to CurrentBars[0] is: 7674.
                5/18/2022 11:59:30 AM | CurrentBar is: 7675
                5/18/2022 12:00:00 PM | CurrentBar is: 7676

                It seems like it's not even processing CancelOrder().
                Last edited by ComfyCouch; 07-26-2022, 08:04 PM.

                Comment


                  #9
                  Hello ComfyCouch,

                  From the output I don't see the cancel print happening:

                  Code:
                  Print(string.Format("{0} | Canceling long order. CurrentBars[0] is: {1}. savedBar + 1 (which should be equal to CurrentBars[0] is: {2}.", Time[0], CurrentBars[0], savedBar + 1));
                  I would suggest to try and print the variables you used in that condition to get a better idea of why that may not be called.

                  Code:
                  Print((entryOrder != null) + CurrentBars[0] + " > " +  savedBar + 1);
                  if(...)
                  {
                  }
                  else if (entryOrder != null && CurrentBars[0] > savedBar + 1)
                  {
                  }

                  Comment


                    #10
                    Thanks for the reply Jesse. I changed something in OnOrderUpdate which somehow solved the problem, it appears.

                    Different question, though. For backtesting, would adding a one tick series while using OnEachTick be the same as using OnBarClose with a one tick series?

                    Comment


                      #11
                      Hello ComfyCouch,

                      Backtesting works as OnBarClose so adding a 1 tick series and using OnEachTick are not the same. You can't use OnEachTick/IsFirstTickOfBar in a backtest. Adding a 1 tick series will call OnBarUpdate for every tick similar to using OnEachTick in realtime, the difference is that 1 tick bars are each individual bars. In realtime using OnEachTick you still have your primary series bars like a 1 minute bar, but you are viewing each tick update within that bar. That means you can detect the first tick of the bar where as a 1 tick series every tick is the first tick of that tick bar.

                      Comment


                        #12
                        Originally posted by NinjaTrader_Jesse View Post
                        Hello ComfyCouch,

                        Backtesting works as OnBarClose so adding a 1 tick series and using OnEachTick are not the same. You can't use OnEachTick/IsFirstTickOfBar in a backtest. Adding a 1 tick series will call OnBarUpdate for every tick similar to using OnEachTick in realtime, the difference is that 1 tick bars are each individual bars. In realtime using OnEachTick you still have your primary series bars like a 1 minute bar, but you are viewing each tick update within that bar. That means you can detect the first tick of the bar where as a 1 tick series every tick is the first tick of that tick bar.
                        Understood. What I've since done is changed my strategy so that it calculates OnBarClose, while adding a 1 tick series for intrabar granularity. That said, when using strategy analyzer, does that mean I should NOT be using tick replay?

                        S̶e̶c̶o̶n̶d̶ ̶q̶u̶e̶s̶t̶i̶o̶n̶:̶ ̶W̶h̶a̶t̶ ̶I̶ ̶d̶i̶d̶ ̶w̶a̶s̶ ̶t̶h̶e̶ ̶a̶b̶o̶v̶e̶,̶ ̶c̶h̶a̶n̶g̶e̶ ̶t̶h̶e̶ ̶s̶t̶r̶a̶t̶e̶g̶y̶ ̶t̶o̶ ̶c̶a̶l̶c̶u̶l̶a̶t̶e̶ ̶O̶n̶B̶a̶r̶C̶l̶o̶s̶e̶,̶ ̶a̶n̶d̶ ̶a̶d̶d̶e̶d̶ ̶a̶ ̶1̶ ̶t̶i̶c̶k̶ ̶s̶e̶r̶i̶e̶s̶ ̶f̶o̶r̶ ̶i̶n̶t̶r̶a̶b̶a̶r̶ ̶f̶i̶l̶l̶s̶.̶ ̶T̶h̶e̶n̶,̶ ̶I̶ ̶b̶a̶c̶k̶t̶e̶s̶t̶e̶d̶ ̶i̶t̶ ̶u̶s̶i̶n̶g̶ ̶s̶t̶r̶a̶t̶e̶g̶y̶ ̶a̶n̶a̶l̶y̶z̶e̶r̶ ̶a̶n̶d̶ ̶c̶o̶m̶p̶a̶r̶e̶d̶ ̶t̶h̶e̶ ̶r̶e̶s̶u̶l̶t̶s̶ ̶t̶o̶ ̶M̶a̶r̶k̶e̶t̶ ̶r̶e̶p̶l̶a̶y̶ ̶w̶/̶ ̶p̶l̶a̶y̶b̶a̶c̶k̶.̶ ̶T̶h̶e̶ ̶r̶e̶s̶u̶l̶t̶s̶ ̶w̶e̶r̶e̶ ̶v̶e̶r̶y̶ ̶s̶i̶m̶i̶l̶a̶r̶,̶ ̶h̶o̶w̶e̶v̶e̶r̶,̶ ̶t̶h̶e̶r̶e̶ ̶w̶e̶r̶e̶ ̶s̶o̶m̶e̶ ̶t̶r̶a̶d̶e̶s̶ ̶m̶i̶s̶s̶i̶n̶g̶ ̶i̶n̶ ̶m̶a̶r̶k̶e̶t̶ ̶r̶e̶p̶l̶a̶y̶ ̶v̶e̶r̶s̶u̶s̶ ̶i̶n̶ ̶t̶h̶e̶ ̶b̶a̶c̶k̶t̶e̶s̶t̶.̶ ̶I̶ ̶c̶h̶a̶l̶k̶e̶d̶ ̶t̶h̶i̶s̶ ̶u̶p̶ ̶t̶o̶ ̶i̶t̶ ̶m̶i̶s̶s̶i̶n̶g̶ ̶a̶ ̶t̶r̶a̶d̶e̶ ̶d̶u̶e̶ ̶t̶o̶ ̶p̶r̶i̶c̶e̶ ̶b̶e̶i̶n̶g̶ ̶a̶b̶o̶v̶e̶ ̶a̶ ̶s̶t̶o̶p̶ ̶l̶i̶m̶i̶t̶ ̶o̶r̶d̶e̶r̶,̶ ̶b̶u̶t̶ ̶w̶h̶e̶n̶ ̶p̶l̶a̶y̶i̶n̶g̶ ̶b̶a̶c̶k̶ ̶t̶h̶r̶o̶u̶g̶h̶ ̶m̶a̶r̶k̶e̶t̶ ̶r̶e̶p̶l̶a̶y̶,̶ ̶i̶f̶ ̶I̶ ̶s̶e̶t̶ ̶t̶h̶e̶ ̶s̶p̶e̶e̶d̶ ̶t̶o̶ ̶M̶a̶x̶,̶ ̶i̶t̶ ̶m̶i̶s̶s̶e̶s̶ ̶t̶h̶e̶ ̶t̶r̶a̶d̶e̶s̶ ̶w̶h̶e̶r̶e̶a̶s̶ ̶i̶f̶ ̶I̶ ̶l̶e̶t̶ ̶i̶t̶ ̶s̶l̶o̶w̶ ̶d̶o̶w̶n̶ ̶a̶n̶d̶ ̶p̶u̶t̶ ̶t̶h̶e̶ ̶s̶p̶e̶e̶d̶ ̶t̶o̶ ̶1̶ ̶o̶r̶ ̶2̶,̶ ̶i̶t̶ ̶f̶i̶l̶l̶s̶ ̶t̶h̶e̶ ̶t̶r̶a̶d̶e̶s̶.̶ ̶I̶s̶ ̶t̶h̶a̶t̶ ̶s̶u̶p̶p̶o̶s̶e̶ ̶t̶o̶ ̶h̶a̶p̶p̶e̶n̶?̶

                        EDIT: Fixed the problem in the second question - all I had to do was add this bit of code:

                        Code:
                        if (order.OrderState == OrderState.Rejected)
                        in OnOrderUpdate, as if an order was cancelled.
                        Last edited by ComfyCouch; 08-01-2022, 04:50 PM.

                        Comment


                          #13
                          I think I should clarify what I meant. My strategy does use intrabar data to make a decision on an entry. With that in mind, I initially decided to use Calculate.OnEachTick with the addition of a one tick series to submit orders through. I then backtested this by using strategy analyzer and enabling Tick Replay. However, since then, I'm thinking it's actually not useful to use OnEachTick and Tick Replay, since I'm not using any indicators.

                          That said, if I'm not using any indicators whatsoever and only using candlestick data for my logic, what would the difference be in:

                          a) Running a backtest through strategy analyzer (with a secondary 1 tick series) using OnEachTick and enabling Tick Replay

                          versus

                          b) Running a backtest through strategy analyzer (with a secondary 1 tick series) using OnBarClose and NOT enabling Tick Replay?

                          As always, thanks for your time and help through this, really appreciate it.

                          Comment


                            #14
                            Hello ComfyCouch,

                            Backtests do not use OnEachTick so enabling that will not work historically even with tick replay. Tick replay is also not intended to help with fills so you can turn that off unless you had a specific reason you needed to use tick replay.

                            To make a granular backtest which is similar to running in realtime you can add a 1 tick series and use that to submit orders or drive logic. In realtime you would not need to change anything and it can run OnBarClose like the backtest.

                            OnEachTick is only for realtime and allows you to see each tick update for the realtime bar.

                            TickReplay is generally used for indicators that calculate using OnMarketData, that allows OnMarketData to run historically to give an estimate of the ask/bid at the time of the last events.





                            Comment


                              #15
                              Originally posted by NinjaTrader_Jesse View Post
                              Hello ComfyCouch,

                              Backtests do not use OnEachTick so enabling that will not work historically even with tick replay. Tick replay is also not intended to help with fills so you can turn that off unless you had a specific reason you needed to use tick replay.

                              To make a granular backtest which is similar to running in realtime you can add a 1 tick series and use that to submit orders or drive logic. In realtime you would not need to change anything and it can run OnBarClose like the backtest.

                              OnEachTick is only for realtime and allows you to see each tick update for the realtime bar.

                              TickReplay is generally used for indicators that calculate using OnMarketData, that allows OnMarketData to run historically to give an estimate of the ask/bid at the time of the last events.




                              Got it. I guess the closest way to get the best accuracy using Strategy Analyzer would be using OnBarClose without Tick Replay, then (in my case).

                              Comment

                              Latest Posts

                              Collapse

                              Topics Statistics Last Post
                              Started by NullPointStrategies, Yesterday, 05:17 AM
                              0 responses
                              63 views
                              0 likes
                              Last Post NullPointStrategies  
                              Started by argusthome, 03-08-2026, 10:06 AM
                              0 responses
                              139 views
                              0 likes
                              Last Post argusthome  
                              Started by NabilKhattabi, 03-06-2026, 11:18 AM
                              0 responses
                              75 views
                              0 likes
                              Last Post NabilKhattabi  
                              Started by Deep42, 03-06-2026, 12:28 AM
                              0 responses
                              45 views
                              0 likes
                              Last Post Deep42
                              by Deep42
                               
                              Started by TheRealMorford, 03-05-2026, 06:15 PM
                              0 responses
                              50 views
                              0 likes
                              Last Post TheRealMorford  
                              Working...
                              X