Announcement

Collapse
No announcement yet.

Partner 728x90

Collapse

Fill event misalignment in backtesting

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

    #16
    Alex, after looking further into I think the main issue is that the fill / execution time would simply be different for each series you submit to, if you fill on 0 > it would report it as 9:08 execution > which is correct for this series's resolution. If you submit to the finer 1 minute series > it would report it as fill at 9:07 already - in each bars series that's another bar number of course.

    For the time of the fill event absent of any OnBarUpdate() event call, you can directly work in OnExecution() -

    protected override void OnExecution(IExecution execution)
    {
    if (entry != null && entry == execution.Order)
    Print("Executed @ " + execution.Time);
    }

    Pushing this DateTime returned to GetBar() would offer you requesting the bar number on which that execution fell.

    I think that would be the best approach.

    Comment


      #17
      I forgot to mention that in the code I posted above, the variable barSeries can be 0 or 1, it makes no difference in the result. It still reports bar 631 as the fill bar when it should be 632.

      When I modify my test program to get the execution time in OnExecution(), the execution time is correctly recorded at 6:07 (Pacific time).

      The trouble is, when I pass this DateTime to GetBar() in OnBarUpdate(), I get series 0 filling on bar 376 (should be 377), and series 1 filling on bar 629 (should be 632). I don't understand this. Bar 629 corresponds to a time of 6:04, not the fill time of 6:07.

      Here's the current test:
      PHP Code:
              #region Variables
              // Parameters for Zen-Fire TF 06-12 2 minute, Default 24/7 template, 1 day ending 5/14/2012 
              private int barNum = 375; // Default setting for BarNum
              private double limitPrice = 780.3; // Default setting for LimitPrice
              private IOrder entry = null;
              private int barSeries = 1;
              private int [] fillbar;
              private DateTime filltime = DateTime.MinValue;
              #endregion
      
              protected override void Initialize() {
                  Add(PeriodType.Minute, 1);
                  Unmanaged = true;
                  CalculateOnBarClose = false; // doesn't matter
                  ExitOnClose = false;
                  TraceOrders = true;
              }
              protected override void OnStartUp() {
                  ClearOutputWindow();
                  fillbar = new int[CurrentBars.GetLength(0)];
              }
      
              protected override void OnExecution(IExecution e) {
                  if (entry != null && entry == e.Order) {
                      filltime = e.Time;
                      Print("Executed at "+e.Time.ToString());
                  }
              }
      
              protected override void OnBarUpdate() {
                  if (entry != null && filltime > DateTime.MinValue && fillbar[BarsInProgress] == 0)
                      fillbar[BarsInProgress] = GetBar(BarsInProgress, filltime);
                  if (BarsInProgress != 0) return;
                  if (CurrentBar == barNum)
                      entry = SubmitOrder(barSeries, OrderAction.Buy, OrderType.Limit, 1, limitPrice, 0, "", "test");
                  if (CurrentBar == barNum+10 && entry != null) {
                      Print("Filled "+filltime.ToString()+" at "+entry.AvgFillPrice.ToString());
                      for (int i = 0; i < fillbar.GetLength(0); ++i)
                          Print("on series "+i.ToString()+" bar "+fillbar[i].ToString());
                  }
              } 
      
      ...and here's the output:

      5/14/2012 6:04:00 Entered internal SubmitOrder() method at 5/14/2012 6:04:00: Action=Buy OrderType=Limit Quantity=1 LimitPrice=780.3 StopPrice=0 OcoId='' Name='test'
      Executed at 5/14/2012 6:07:00
      Filled 5/14/2012 6:07:00 at 780.3
      on series 0 bar 376
      on series 1 bar 629

      The actual fill bars should be 377 and 632.

      -Alex
      Last edited by anachronist; 05-25-2012, 07:06 PM.

      Comment


        #18
        Alex, here's for example an approach with OnExecution and GetBar that works fine in my testing returning 377 and 632 for your test and the filled bar, which is correct according to the reported execution timestamp :

        Code:
        protected override void OnBarUpdate() 
        { 
        if (entry != null && entry.OrderState == OrderState.Filled && Time[0] >= exeTime)
        	{
        	      refBack = GetBar(exeTime);
        		
                      	if (BarsInProgress == 0)
        		   Print(CurrentBar - refBack);
        				
        		if (BarsInProgress == 1)
        		   Print(CurrentBars[1] - refBack);
        	}
        			
        if (BarsInProgress != 0) return; 
                    
        	if (CurrentBar == barNum)
        	{
        		DrawDot("dot", true, 0, Low[0], Color.Blue);
        		DrawText("text", CurrentBar.ToString(), 0, High[0] + TickSize, Color.Blue);  
                                    entry = SubmitOrder(barSeries, OrderAction.Buy, OrderType.Limit, 1, limitPrice, 0, "", "test"); 
        	}
        }
        		
        protected override void OnExecution(IExecution execution)
        {
           if (entry != null && entry == execution.Order)
        	exeTime = execution.Time;
        }

        Comment


          #19
          Thanks Bertrand. The trick I was failing to grasp is to check whether Time[0] >= filltime in my OnBarUpdate(). I also was using GetBar() wrong.

          I must say, the documentation for GetBar() isn't clear at all. The example code, which calculates BarsAgo, implies that GetBar() returns the bar number. The documentation text says the index returned is from the first bar "oldest to newest" but seems to be just the opposite.

          -Alex

          Comment


            #20
            One other thing I don't understand. I have been using OnOrderUpdate() in my ATM backtest code to process all the order events because I need cancellations and rejections too. Does OnExecution() get called only for fills?

            Comment


              #21
              Thanks for the input, we'll oversee the GetBar() docs for your next update. Correct, OnExecution() would only deal with incoming fills (this could be a partial as well). Keep in mind it will be called after OnOrderUpdate.

              A good weekend,

              Comment


                #22
                Okay, it was working fine for limit orders but now I'm getting a severe misalignment with market orders. The misalignment also shows up on the chart.

                How can a market order get filled 26 bars and 18 minutes later on the primary series??

                To reproduce:
                • Zen-fire ES 06-12, 3 minute bars, 1 day of history ending 5/24/2012, default 24/7 session template.
                • Add a secondary series of 1-tick bars.
                • Submit an unmanaged market order to buy at bar when the primary series CurrentBar==160.
                • The fill is on bar 186, and this fill is also shown on the chart on bar 186.

                Here is the code to reproduce:
                Code:
                		#region Variables
                		// Parameters for Zen-Fire TF 06-12 3 minute, Default 24/7 template, 1 day ending 5/24/2012 
                		private int barNum = 160;
                 		private IOrder entry = null;
                		private int [] fillbar;
                		private DateTime filltime = DateTime.MinValue;
                		#endregion
                
                		protected override void Initialize() {
                			Add(PeriodType.Tick, 1);
                			Unmanaged = true;
                			CalculateOnBarClose = false;
                			ExitOnClose = false;
                			TraceOrders = true;
                		}
                		protected override void OnStartUp() {
                			ClearOutputWindow();
                			fillbar = new int[CurrentBars.GetLength(0)];
                		}
                
                		protected override void OnExecution(IExecution e) {
                			if (entry != null && entry == e.Order) {
                				filltime = e.Time;
                				Print("Executed at "+e.Time.ToString());
                			}
                		}
                
                		protected override void OnBarUpdate() {
                			if (entry != null && entry.OrderState == OrderState.Filled && Time[0] >= filltime
                				&& filltime > DateTime.MinValue && fillbar[BarsInProgress] == 0) {
                				fillbar[BarsInProgress] = CurrentBars[BarsInProgress] - GetBar(BarsInProgress, filltime);
                				Print("Filled on series "+BarsInProgress.ToString()+" bar "+fillbar[BarsInProgress].ToString()+", time "+Time[0].ToString());
                			}
                			if (BarsInProgress != 0) return;
                			if (CurrentBar == barNum)
                				entry = SubmitOrder(1, OrderAction.Buy, OrderType.Market, 1, 0, 0, "", "test");
                		}
                Here is the output (times are Pacific time zone):

                5/22/2012 23:15:26 Entered internal SubmitOrder() method at 5/22/2012 23:15:26: Action=Buy OrderType=Market Quantity=1 LimitPrice=0 StopPrice=0 OcoId='' Name='test'
                Executed at 5/23/2012 6:18:46
                Filled on series 1 bar 5879, time 5/23/2012 6:18:46
                Filled on series 0 bar 186, time 5/23/2012 6:21:00
                The order trace shows a really weird time for the order submission: the prior day. It should be 5/23/2012 at 5:03:00. The fill should occur immediately after that.

                I know I must be missing something fundamental here, but the above result seems totally nonsensical.

                If I change the secondary series type to 1 minute bars, it works fine. It just messes up when the secondary series uses PeriodType,Tick or PeriodType.Second.

                -Alex
                Last edited by anachronist; 05-31-2012, 05:37 PM.

                Comment


                  #23
                  Alex, is the tick data completely loaded as needed? If you added tick data in the strategy and data was missing, NT would not reload that according to the data loading rules internally - this is a limitation we currently experience for added series. I tip on this being a data issue, as for a MultiSeries strategy all series would have to be loaded up and passing their BarsRequired before any action is taken. Can you please check into your tick data loaded up and reload manually if needed?

                  Comment


                    #24
                    Ah. While I have tick data history, apparently it's only for day-session data, even though the data series on my chart is for 24/7. The bar in question occurs before the session start. This leads me to ask some additional questions:
                    • Does historical data get fetched to fill holes only when I request the data on a chart, but not when I request it in a strategy?
                    • I have noticed in a process monitor that NinjaTrader makes requests from 7ticks.com, which appears to be a provider of historical data. Is the history being requested from there, or through my zen-fire data feed?
                    • Does my data feed or 7ticks provide tick data outside the regular trading hours?

                    Thanks.
                    Alex

                    Comment


                      #25
                      Hello,

                      Data requests occur based on these data load rules:



                      This is the historical data servers for your Zenfire connection.

                      All data is recorded, ETH and RTH on the servers.

                      -Brett
                      BrettNinjaTrader Product Management

                      Comment


                        #26
                        Hmm, I wonder why I can't seem to get ETH tick data then.
                        -Alex

                        Comment


                          #27
                          Alex, same on a standalone chart for the TF for example running on your Default 24/7? Then please try with a fresh cache for NT7. Shutdown the plaftfrom and go to

                          Documents\NinjaTrader 7\db\cache

                          and delete the sub(!!) folders seen here completely.

                          Once done, restart NT7 and reconnect to your provider. When you open your charts now it will rebuild the cache used. Would you still see issues receiving ETH tick data properly?

                          Thanks,

                          Comment


                            #28
                            That worked, after I figured out that I have to close all my workspaces before shutting down, and don't try to re-load the data by re-opening one of those workspaces, but rather create a whole new chart. Thanks!
                            -Alex

                            Comment


                              #29
                              Thanks for reporting back Alex, glad to hear.

                              Comment

                              Latest Posts

                              Collapse

                              Topics Statistics Last Post
                              Started by sjsj2732, Yesterday, 04:31 AM
                              0 responses
                              36 views
                              0 likes
                              Last Post sjsj2732  
                              Started by NullPointStrategies, 03-13-2026, 05:17 AM
                              0 responses
                              287 views
                              0 likes
                              Last Post NullPointStrategies  
                              Started by argusthome, 03-08-2026, 10:06 AM
                              0 responses
                              287 views
                              0 likes
                              Last Post argusthome  
                              Started by NabilKhattabi, 03-06-2026, 11:18 AM
                              0 responses
                              133 views
                              1 like
                              Last Post NabilKhattabi  
                              Started by Deep42, 03-06-2026, 12:28 AM
                              0 responses
                              95 views
                              0 likes
                              Last Post Deep42
                              by Deep42
                               
                              Working...
                              X