Announcement

Collapse

Looking for a User App or Add-On built by the NinjaTrader community?

Visit NinjaTrader EcoSystem and our free User App Share!

Have a question for the NinjaScript developer community? Open a new thread in our NinjaScript File Sharing Discussion Forum!
See more
See less

Partner 728x90

Collapse

exact time filters.

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

    exact time filters.



    people with nt,



    i'm in need of assistance.


    i have a strategy i have been working on. it runs on 4 minute rty contract bars and everything seems well.


    i now want to trade only during the nasdaq exchange regular session, that is 9:30 to 16:00 eastern yankee time.



    and i have some other ideas that will never work on 4 minute bars series like the following:


    _ if a downtrend was active right before 9:30 and is active at 9:30, then open a short position exactly at 9:30.


    _ and, close all open positions exactly at 15:58.


    entries and exits should still only be generated by the 4 minute bars series, but i thought that adding a 1 minute bars series would then allow the strategy to implement very precise time filters and this has resulted in a mess.



    i have tried several versions. one using set stop loss orders and another one using onorder and onexecution updates. if i send all orders to barsindex 0 then entries and exits will seemingly work well but the strategy will fail to implement the 9:30 and 15:58 filters i described above. if i try sending all orders to barsindex 1 then the filters will improve somewhat but the entries and exits will be generated by the 1 minute bars series which ruins the strategy.




    ¿can nt provide a working sample or an explanation of how to use a larger bar size to generate entries - exits and define conditions but while also having exact time filters as i described above? i understand that it should be possible to use the larger bar size for the most important logic and have the smaller bar size series evaluate all entries - exits and stops, ¿is this correct?



    very well, regards.

    #2
    Hello rtwave,

    Thank you for your post.

    For an overview of working with multi-time frame & instruments, please see the following page:Assuming the 4-minute series is the primary series and the 1-minute series is the first added series, the 4-minute series would be BarsInProgress 0 and the 1-minute series would be BarsInProgress 1. The time filter to limit trading hours could be set up on the 1-minute series so that the time is being evaluated every minute. We have an example of using a time filter that may be found here:You mentioned the following ideas:
    _ if a downtrend was active right before 9:30 and is active at 9:30, then open a short position exactly at 9:30.

    _ and, close all open positions exactly at 15:58.
    Is your strategy set up to calculate On Bar Close, On Price Change, or On Each Tick? You could check for a downtrend on the 4-minute series when BarsInProgress == 0, and if your strategy calculates On Price Change or On Each Tick you would be able to check for that downtrend before and at 9:30 (depending on your conditions checking for a downtrend). You could consider having a bool that toggles between true/false whether a downtrend is happening, and use that bool in your entry conditions on the 1-minute series when BarsInProgress == 1. To close all open positions at 15:58, you could use conditions such as the following:

    Code:
    // if the time from the 1-minute series is 15:58 and the position is not flat
    if ((ToTime(Times[1][0]) >= 155800 && Position.MarketPosition != MarketPosition.Flat)
    {
    // if long, exit long
    if (Position.MarketPosition == MarketPosition.Long)
    ExitLong();
    // if short, exit short
    if (Position.MarketPosition == MarketPosition.Short)
    ExitShort();
    }
    Please let us know if we may be of further assistance.​
    Emily C.NinjaTrader Customer Service

    Comment


      #3



      people with nt,



      i continued to work on this situation over the last several days. it would be important if nt staff can explain how is this supposed to work.


      i have been able to create a strategy that will open positions at 09:30 and will liquidate all positions at 16:00 as intended.


      i will share an image and the code below.


      the thing is, if one sets the time on the first added series to exactly when one wants positions to be opened this won't work. i have found out that it is not enough for the conditions one has coded to be true, but one still has to set the time to open positions to one bar before the time one is interested in. so, the specified time has to be 09:19 and then positions will be opened at 09:30.


      ¿why is this? it would be logical that setting the time to 09:29 should work as all conditions would be true at 09:30 and then positions would have to be opened. and it is the exact same thing with the closing time, if one sets the time to 15:49, then it seems that at 15:50 all conditions are true but then the positions will only be liquidated at 16:00. this is unexpected and counterintuitive.


      Click image for larger version  Name:	20230922 time filters 0001.jpg Views:	0 Size:	91.7 KB ID:	1270016



      this below is the structure of the strategy i have been testing. i have been using 11 minute and 10 minute bars as primary and added series so that it will be really easy to determine which series is generating the entries - exits just at a glance.



      Code:
      
          public class  : Strategy
          {
      
              private bool = false;
              private bool = false;
      
      
              protected override void OnStateChange()
              {
                  if (State == State.SetDefaults)
                  {
                      Description                                    = @"experimental.";
                      Name                                        = "";
                      Calculate                                    = Calculate.OnBarClose;
                      EntriesPerDirection                            = 1;
                      EntryHandling                                = EntryHandling.UniqueEntries;
                      IsExitOnSessionCloseStrategy                = false;
                      ExitOnSessionCloseSeconds                    = 10;
                      IsFillLimitOnTouch                            = false;
                      MaximumBarsLookBack                            = MaximumBarsLookBack.TwoHundredFiftySix;
                      OrderFillResolution                            = OrderFillResolution.Standard;
                      Slippage                                    = 1;
                      StartBehavior                                = StartBehavior.ImmediatelySubmitSynchronizeAccount;
                      TimeInForce                                    = TimeInForce.Gtc;
                      TraceOrders                                    = true;
                      RealtimeErrorHandling                        = RealtimeErrorHandling.StopCancelCloseIgnoreRejects;
                      StopTargetHandling                            = StopTargetHandling.PerEntryExecution;
                      BarsRequiredToTrade                            = 50;
                      // Disable this property for performance gains in Strategy Analyzer optimizations
                      // See the Help Guide for additional information
                      IsInstantiatedOnEachOptimizationIteration    = true;
      
      
                      Shtrpoco                                    = true;
                      Shprta01poco                                = true;                
                      Lotrpoco                                    = true;
                      Loprta01poco                                = true;
                      Tiop                            = DateTime.Parse("9:19", System.Globalization.CultureInfo.InvariantCulture);
                      Tibe                            = DateTime.Parse("9:30", System.Globalization.CultureInfo.InvariantCulture);
                      Tien                            = DateTime.Parse("15:49", System.Globalization.CultureInfo.InvariantCulture);
                      Ticl                            = DateTime.Parse("15:49", System.Globalization.CultureInfo.InvariantCulture);
      
      
                  }
                  else if (State == State.Configure)
                  {
                      AddDataSeries(Data.BarsPeriodType.Minute, 10);            
                  }
                  else if (State == State.Realtime)
                  {
      
                  }
                  else if (State == State.DataLoaded)
                  {
      
      
                      SetStopLoss(@"", CalculationMode.Ticks, false);
                      SetStopLoss(@"", CalculationMode.Ticks, false);    
                      SetStopLoss(@"", CalculationMode.Ticks, false);
                      SetStopLoss(@"", CalculationMode.Ticks, false);
      
      
                  }
              }
      
              protected override void OnBarUpdate()
              {
      
      
                  if ( CurrentBars[0] <= BarsRequiredToTrade ) return;
      
      
                  if(BarsInProgress == 0)
                  {
      
      
      
                      if (   )
                      {
                      if ( (Position.MarketPosition != MarketPosition.Short)
                      && (Times[1][0].TimeOfDay >= Tibe.TimeOfDay)
                      && (Times[1][0].TimeOfDay < Tien.TimeOfDay) )
                      {
                      if ( == true )
                      {
                      EnterShort(Convert.ToInt32(), @"");
                      if ( == true )
                      {
                      EnterShort(Convert.ToInt32(), @"");
                      }                
                      }                
                      }
                      }
      
      
                      else
      
      
                          if (  )
                          {
                          if ( (Position.MarketPosition == MarketPosition.Long) )
                          {
                          if ( Position.Quantity == Convert.ToInt32() )
                          {
                          ExitLong(Convert.ToInt32(), @"", @"");                    
                          }
                          if ( Position.Quantity == ( Convert.ToInt32() + Convert.ToInt32() ) )
                          {
                          ExitLong(Convert.ToInt32(), @"", @"");
                          ExitLong(Convert.ToInt32(), @"", @"");
                          }
                          }
                          }
      
      
                      if (  )
                      {
                      if ( (Position.MarketPosition != MarketPosition.Long)
                      && (Times[1][0].TimeOfDay >= Tibe.TimeOfDay)
                      && (Times[1][0].TimeOfDay < Tien.TimeOfDay) )
                      {
                      if ( == true
                      && Position.MarketPosition != MarketPosition.Long )
                      {
                      EnterLong(Convert.ToInt32(), @"");
                      if ( == true )
                      {
                      EnterLong(Convert.ToInt32(), @"");
                      }                                                
                      }
                      }
                      }
      
      
                      else
      
      
                          if ( )
                          {
                          if ( (Position.MarketPosition == MarketPosition.Short) )
                          {
                          if ( Position.Quantity == Convert.ToInt32() )
                          {
                          ExitShort(Convert.ToInt32(), @"shorexoren01", @"");
                          }
                          if ( Position.Quantity == ( Convert.ToInt32() + Convert.ToInt32() ) )
                          {
                          ExitShort(Convert.ToInt32(), @"", @"");
                          ExitShort(Convert.ToInt32(), @"", @"");
                          }
                          }
                          }
      
      
      
                      if (  )
                      {
                      = true;
                      = false;                
                      }
      
      
                      else
      
      
                          if ( )
                          {
                          = false;                    
                          }
      
      
      
                      if (  )
                      {
                      = true;
                      = false;                
                      }
      
      
                      else
      
      
                          if (  )
                          {
                          = false;                    
                          }
      
      
      
                  }
                  else if(BarsInProgress == 1)
                  {
      
      
      
                      if ( (== true)
                      && (Times[1][0].TimeOfDay >= Tiop.TimeOfDay)
                      && (Times[1][0].TimeOfDay < Tiop.AddMinutes(4).TimeOfDay)
                      && (Position.MarketPosition != MarketPosition.Short) )
                      {
                      if ( == true )
                      {
                      EnterShort(Convert.ToInt32(), @"");
                      if ( == true )
                      {
                      EnterShort(Convert.ToInt32(), @"");
                      }                
                      }                
                      }
      
      
                      if ( (== true)
                      && (Times[1][0].TimeOfDay >= Tiop.TimeOfDay)
                      && (Times[1][0].TimeOfDay < Tiop.AddMinutes(4).TimeOfDay)
                      && (Position.MarketPosition != MarketPosition.Long) )
                      {
                      if ( == true )
                      {
                      EnterLong(Convert.ToInt32(), @"");
                      if ( == true )
                      {
                      EnterLong(Convert.ToInt32(), @"");
                      }                                                
                      }
                      }
      
      
      
                      if ((Times[1][0].TimeOfDay >= Ticl.TimeOfDay)
                      && (Times[1][0].TimeOfDay < Ticl.AddMinutes(4).TimeOfDay)
                      && (Position.MarketPosition == MarketPosition.Short))
                      {
                      if ( Position.Quantity == Convert.ToInt32() )
                      {
                      ExitShort(Convert.ToInt32(), @"", @"");
                      }
                      if ( Position.Quantity == ( Convert.ToInt32() + Convert.ToInt32() ) )
                      {
                      ExitShort(Convert.ToInt32(), @"", @"");
                      ExitShort(Convert.ToInt32(), @"", @"");
                      }
                      }
      
      
                      if ((Times[1][0].TimeOfDay >= Ticl.TimeOfDay)
                      && (Times[1][0].TimeOfDay < Ticl.AddMinutes(4).TimeOfDay)
                      && (Position.MarketPosition == MarketPosition.Long))
                      {
                      if ( Position.Quantity == Convert.ToInt32() )
                      {
                      ExitLong(Convert.ToInt32(), @"", @"");                    
                      }
                      if ( Position.Quantity == ( Convert.ToInt32() + Convert.ToInt32() ) )
                      {
                      ExitLong(Convert.ToInt32(), @"", @"");
                      ExitLong(Convert.ToInt32(), @"", @"");
                      }                
                      }
      
      
      
                  }
      
      
              }
      Last edited by rtwave; 09-22-2023, 06:03 PM.

      Comment


        #4


        and then there is even more unexplainable behavior.


        i have the exact same strategy, just the code for the entries and exits and exits is minimally different and then the intended behavior at 09:30 and 16:00 will not occur.


        the earliest entries are now generated at 10:00 and positions will now be liquidated at 16:24. the bar sizes are the same.


        Click image for larger version

Name:	20230922 time filters 0002.jpg
Views:	161
Size:	92.5 KB
ID:	1270019



        and the only difference is that this version of the strategy does define the index that will manage the positions:


        EnterShort(0, Convert.ToInt32(), @"");

        ExitLong(0, Convert.ToInt32(), @"", @"");​



        ¿can nt staff explain what is happening and how can these kind of entry and exit orders be used in a strategy that will open positions at 09:30, liquidate all positions at 16:00 and only trade between those times?

        Comment


          #5
          Hello rtwave,

          This may be due to the other conditions you have, unfortunately the code provided appears to be missing parts or is structured in an incorrect way. You would need to use prints to see if just the time condition portion of your condition is becoming true to know if the problem relates to your other logic.

          I would suggest starting with a more simple test and make a time condition like the sample from the following page or the sample that Emily had linked:

          https://ninjatrader.com/support/help...ightsub=totime

          The code that I mentioned is structured incorrect would be the following items, if you intentionally are leaving out code that won't help to get an accurate answer. You should instead make a much more simplified test of just the time condition if you have questions surrounding that part of your code.
          Code:
          if ( )
          {​
          
           if ( == true
          These type of statements would not be valid code and does not let us know what may be happening in the code to know if the time condition is part of the problem or not.
          JesseNinjaTrader Customer Service

          Comment


            #6



            people with nt,


            same thing.


            i created a sample strategy. it alternates short and long positions bar to bar.


            this is version a, it uses ordinary EnterShort(Convert.ToInt32(Position1), @"shortentry1"); orders.


            version a is able to open positions at 09:30 but then fails at closing all positions at 16:00.


            to reduce the number of bars the primary series is 53 minute bars and the other series is 10 minute bars.


            Click image for larger version

Name:	20230923 time filters 0001.jpg
Views:	176
Size:	88.0 KB
ID:	1270047



            Code:
            public class sampletimefiltersa : Strategy
                {
            
                    private bool conditionshort = false;
                    private bool conditionlong = false;
            
            
                    protected override void OnStateChange()
                    {
                        if (State == State.SetDefaults)
                        {
                            Description                                    = @"sampletimefiltersa";
                            Name                                        = "sampletimefiltersa";
                            Calculate                                    = Calculate.OnBarClose;
                            EntriesPerDirection                            = 1;
                            EntryHandling                                = EntryHandling.UniqueEntries;
                            IsExitOnSessionCloseStrategy                = false;
                            ExitOnSessionCloseSeconds                    = 10;
                            IsFillLimitOnTouch                            = false;
                            MaximumBarsLookBack                            = MaximumBarsLookBack.TwoHundredFiftySix;
                            OrderFillResolution                            = OrderFillResolution.Standard;
                            Slippage                                    = 1;
                            StartBehavior                                = StartBehavior.ImmediatelySubmitSynchronizeAccount;
                            TimeInForce                                    = TimeInForce.Gtc;
                            TraceOrders                                    = true;
                            RealtimeErrorHandling                        = RealtimeErrorHandling.StopCancelCloseIgnoreRejects;
                            StopTargetHandling                            = StopTargetHandling.PerEntryExecution;
                            BarsRequiredToTrade                            = 20;
                            // Disable this property for performance gains in Strategy Analyzer optimizations
                            // See the Help Guide for additional information
                            IsInstantiatedOnEachOptimizationIteration    = true;
                            Position1                                    = 1;
                            Position2                                    = 1;
                            Stopsize                                    = 20;
                            Trade01short                                = true;
                            Trade02short                                = true;                
                            Trade01long                                    = true;
                            Trade02long                                    = true;
                            Timeopen                        = DateTime.Parse("9:19", System.Globalization.CultureInfo.InvariantCulture);
                            Timebegin                        = DateTime.Parse("9:30", System.Globalization.CultureInfo.InvariantCulture);
                            Timeend                            = DateTime.Parse("15:49", System.Globalization.CultureInfo.InvariantCulture);
                            Timeclose                        = DateTime.Parse("15:49", System.Globalization.CultureInfo.InvariantCulture);
            
            
                        }
                        else if (State == State.Configure)
                        {
                            AddDataSeries(Data.BarsPeriodType.Minute, 10);            
                        }
                        else if (State == State.Realtime)
                        {
            
                        }
                        else if (State == State.DataLoaded)
                        {
            
                            SetStopLoss(@"shortentry1", CalculationMode.Ticks, Stopsize, false);
                            SetStopLoss(@"shortentry2", CalculationMode.Ticks, Stopsize, false);            
                            SetStopLoss(@"longentry1", CalculationMode.Ticks, Stopsize, false);
                            SetStopLoss(@"longentry2", CalculationMode.Ticks, Stopsize, false);
            
            
                        }
                    }
            
                    protected override void OnBarUpdate()
                    {
            
            
                        if ( CurrentBars[0] <= BarsRequiredToTrade ) return;
            
            
                        if(BarsInProgress == 0)
                        {
            
            
            
                            if (CurrentBar % 2 == 0)
                            {
                            if ( (Position.MarketPosition != MarketPosition.Short)
                            && (Times[1][0].TimeOfDay >= Timebegin.TimeOfDay)
                            && (Times[1][0].TimeOfDay < Timeend.TimeOfDay) )
                            {
                            if ( Trade01short == true )
                            {
                            EnterShort(Convert.ToInt32(Position1), @"shortentry1");
                            if ( Trade02short == true )
                            {
                            EnterShort(Convert.ToInt32(Position2), @"shortentry2");
                            }                
                            }                
                            }
                            }
            
            
                            if (CurrentBar % 2 == 1)
                            {
                            if ( (Position.MarketPosition != MarketPosition.Long)
                            && (Times[1][0].TimeOfDay >= Timebegin.TimeOfDay)
                            && (Times[1][0].TimeOfDay < Timeend.TimeOfDay) )
                            {
                            if ( Trade01long == true
                            && Position.MarketPosition != MarketPosition.Long )
                            {
                            EnterLong(Convert.ToInt32(Position1), @"longentry1");
                            if ( Trade02long == true )
                            {
                            EnterLong(Convert.ToInt32(Position2), @"longentry2");
                            }                                                
                            }
                            }
                            }
            
            
                            if ( ( CurrentBar - 1 ) % 2 == 1)
                            {
                            conditionshort = true;
                            conditionlong = false;                
                            }
            
            
                            if ( ( CurrentBar - 1 ) % 2 == 0)
                            {
                            conditionlong = true;
                            conditionshort = false;                
                            }
            
            
                        }
                        else if(BarsInProgress == 1)
                        {
            
            
            
                            if ( (conditionshort == true)
                            && (Times[1][0].TimeOfDay >= Timeopen.TimeOfDay)
                            && (Times[1][0].TimeOfDay < Timeopen.AddMinutes(4).TimeOfDay)
                            && (Position.MarketPosition != MarketPosition.Short) )
                            {
                            if ( Trade01short == true )
                            {
                            EnterShort(Convert.ToInt32(Position1), @"shortentry1");
                            if ( Trade02short == true )
                            {
                            EnterShort(Convert.ToInt32(Position2), @"shortentry2");
                            }                
                            }                
                            }
            
            
                            if ( (conditionlong == true)
                            && (Times[1][0].TimeOfDay >= Timeopen.TimeOfDay)
                            && (Times[1][0].TimeOfDay < Timeopen.AddMinutes(4).TimeOfDay)
                            && (Position.MarketPosition != MarketPosition.Long) )
                            {
                            if ( Trade01long == true )
                            {
                            EnterLong(Convert.ToInt32(Position1), @"longentry1");
                            if ( Trade02long == true )
                            {
                            EnterLong(Convert.ToInt32(Position2), @"longentry2");
                            }                                                
                            }
                            }
            
            
            
                            if ((Times[1][0].TimeOfDay >= Timeclose.TimeOfDay)
                            && (Times[1][0].TimeOfDay < Timeclose.AddMinutes(4).TimeOfDay)
                            && (Position.MarketPosition == MarketPosition.Short))
                            {
                            if ( Position.Quantity == Convert.ToInt32(Position1) )
                            {
                            ExitShort(Convert.ToInt32(Position1), @"shcltiexoren01", @"shortentry1");
                            }
                            if ( Position.Quantity == ( Convert.ToInt32(Position1) + Convert.ToInt32(Position2) ) )
                            {
                            ExitShort(Convert.ToInt32(Position1), @"shcltiexoren01", @"shortentry1");
                            ExitShort(Convert.ToInt32(Position2), @"shcltiexprtaen01", @"shortentry2");
                            }
                            }
            
            
                            if ((Times[1][0].TimeOfDay >= Timeclose.TimeOfDay)
                            && (Times[1][0].TimeOfDay < Timeclose.AddMinutes(4).TimeOfDay)
                            && (Position.MarketPosition == MarketPosition.Long))
                            {
                            if ( Position.Quantity == Convert.ToInt32(Position1) )
                            {
                            ExitLong(Convert.ToInt32(Position1), @"locltiexoren01", @"longentry1");                    
                            }
                            if ( Position.Quantity == ( Convert.ToInt32(Position1) + Convert.ToInt32(Position2) ) )
                            {
                            ExitLong(Convert.ToInt32(Position1), @"locltiexoren01", @"longentry1");
                            ExitLong(Convert.ToInt32(Position2), @"locltiexprtaen01", @"longentry2");
                            }                
                            }
            
            
            
                        }​

            Comment


              #7


              version b is the exact same strategy.


              the only difference is that entries and exits specify the bar index EnterShort(0, Convert.ToInt32(Position1), @"shortentry1"); .


              this version fails to close positions at 16:00 and it also fails to open positions at 09:30, which version a was at least able to get right.


              Click image for larger version  Name:	20230923 time filters 0002.jpg Views:	0 Size:	91.6 KB ID:	1270049


              Code:
              public class sampletimefiltersb : Strategy
                  {
              
                      private bool conditionshort = false;
                      private bool conditionlong = false;
              
              
                      protected override void OnStateChange()
                      {
                          if (State == State.SetDefaults)
                          {
                              Description                                    = @"sampletimefiltersb";
                              Name                                        = "sampletimefiltersb";
                              Calculate                                    = Calculate.OnBarClose;
                              EntriesPerDirection                            = 1;
                              EntryHandling                                = EntryHandling.UniqueEntries;
                              IsExitOnSessionCloseStrategy                = false;
                              ExitOnSessionCloseSeconds                    = 10;
                              IsFillLimitOnTouch                            = false;
                              MaximumBarsLookBack                            = MaximumBarsLookBack.TwoHundredFiftySix;
                              OrderFillResolution                            = OrderFillResolution.Standard;
                              Slippage                                    = 1;
                              StartBehavior                                = StartBehavior.ImmediatelySubmitSynchronizeAccount;
                              TimeInForce                                    = TimeInForce.Gtc;
                              TraceOrders                                    = true;
                              RealtimeErrorHandling                        = RealtimeErrorHandling.StopCancelCloseIgnoreRejects;
                              StopTargetHandling                            = StopTargetHandling.PerEntryExecution;
                              BarsRequiredToTrade                            = 20;
                              // Disable this property for performance gains in Strategy Analyzer optimizations
                              // See the Help Guide for additional information
                              IsInstantiatedOnEachOptimizationIteration    = true;
                              Position1                                    = 1;
                              Position2                                    = 1;
                              Stopsize                                    = 20;
                              Trade01short                                = true;
                              Trade02short                                = true;                
                              Trade01long                                    = true;
                              Trade02long                                    = true;
                              Timeopen                        = DateTime.Parse("9:19", System.Globalization.CultureInfo.InvariantCulture);
                              Timebegin                        = DateTime.Parse("9:30", System.Globalization.CultureInfo.InvariantCulture);
                              Timeend                            = DateTime.Parse("15:49", System.Globalization.CultureInfo.InvariantCulture);
                              Timeclose                        = DateTime.Parse("15:49", System.Globalization.CultureInfo.InvariantCulture);
              
              
                          }
                          else if (State == State.Configure)
                          {
                              AddDataSeries(Data.BarsPeriodType.Minute, 10);            
                          }
                          else if (State == State.Realtime)
                          {
              
                          }
                          else if (State == State.DataLoaded)
                          {
              
                              SetStopLoss(@"shortentry1", CalculationMode.Ticks, Stopsize, false);
                              SetStopLoss(@"shortentry2", CalculationMode.Ticks, Stopsize, false);            
                              SetStopLoss(@"longentry1", CalculationMode.Ticks, Stopsize, false);
                              SetStopLoss(@"longentry2", CalculationMode.Ticks, Stopsize, false);
              
              
                          }
                      }
              
                      protected override void OnBarUpdate()
                      {
              
              
                          if ( CurrentBars[0] <= BarsRequiredToTrade ) return;
              
              
                          if(BarsInProgress == 0)
                          {
              
              
              
                              if (CurrentBar % 2 == 0)
                              {
                              if ( (Position.MarketPosition != MarketPosition.Short)
                              && (Times[1][0].TimeOfDay >= Timebegin.TimeOfDay)
                              && (Times[1][0].TimeOfDay < Timeend.TimeOfDay) )
                              {
                              if ( Trade01short == true )
                              {
                              EnterShort(0, Convert.ToInt32(Position1), @"shortentry1");
                              if ( Trade02short == true )
                              {
                              EnterShort(0, Convert.ToInt32(Position2), @"shortentry2");
                              }                
                              }                
                              }
                              }
              
              
                              if (CurrentBar % 2 == 1)
                              {
                              if ( (Position.MarketPosition != MarketPosition.Long)
                              && (Times[1][0].TimeOfDay >= Timebegin.TimeOfDay)
                              && (Times[1][0].TimeOfDay < Timeend.TimeOfDay) )
                              {
                              if ( Trade01long == true
                              && Position.MarketPosition != MarketPosition.Long )
                              {
                              EnterLong(0, Convert.ToInt32(Position1), @"longentry1");
                              if ( Trade02long == true )
                              {
                              EnterLong(0, Convert.ToInt32(Position2), @"longentry2");
                              }                                                
                              }
                              }
                              }
              
              
                              if ( ( CurrentBar - 1 ) % 2 == 1)
                              {
                              conditionshort = true;
                              conditionlong = false;                
                              }
              
              
                              if ( ( CurrentBar - 1 ) % 2 == 0)
                              {
                              conditionlong = true;
                              conditionshort = false;                
                              }
              
              
                          }
                          else if(BarsInProgress == 1)
                          {
              
              
              
                              if ( (conditionshort == true)
                              && (Times[1][0].TimeOfDay >= Timeopen.TimeOfDay)
                              && (Times[1][0].TimeOfDay < Timeopen.AddMinutes(4).TimeOfDay)
                              && (Position.MarketPosition != MarketPosition.Short) )
                              {
                              if ( Trade01short == true )
                              {
                              EnterShort(0, Convert.ToInt32(Position1), @"shortentry1");
                              if ( Trade02short == true )
                              {
                              EnterShort(0, Convert.ToInt32(Position2), @"shortentry2");
                              }                
                              }                
                              }
              
              
                              if ( (conditionlong == true)
                              && (Times[1][0].TimeOfDay >= Timeopen.TimeOfDay)
                              && (Times[1][0].TimeOfDay < Timeopen.AddMinutes(4).TimeOfDay)
                              && (Position.MarketPosition != MarketPosition.Long) )
                              {
                              if ( Trade01long == true )
                              {
                              EnterLong(0, Convert.ToInt32(Position1), @"longentry1");
                              if ( Trade02long == true )
                              {
                              EnterLong(0, Convert.ToInt32(Position2), @"longentry2");
                              }                                                
                              }
                              }
              
              
              
                              if ((Times[1][0].TimeOfDay >= Timeclose.TimeOfDay)
                              && (Times[1][0].TimeOfDay < Timeclose.AddMinutes(4).TimeOfDay)
                              && (Position.MarketPosition == MarketPosition.Short))
                              {
                              if ( Position.Quantity == Convert.ToInt32(Position1) )
                              {
                              ExitShort(0, Convert.ToInt32(Position1), @"shcltiexoren01", @"shortentry1");
                              }
                              if ( Position.Quantity == ( Convert.ToInt32(Position1) + Convert.ToInt32(Position2) ) )
                              {
                              ExitShort(0, Convert.ToInt32(Position1), @"shcltiexoren01", @"shortentry1");
                              ExitShort(0, Convert.ToInt32(Position2), @"shcltiexprtaen01", @"shortentry2");
                              }
                              }
              
              
                              if ((Times[1][0].TimeOfDay >= Timeclose.TimeOfDay)
                              && (Times[1][0].TimeOfDay < Timeclose.AddMinutes(4).TimeOfDay)
                              && (Position.MarketPosition == MarketPosition.Long))
                              {
                              if ( Position.Quantity == Convert.ToInt32(Position1) )
                              {
                              ExitLong(0, Convert.ToInt32(Position1), @"locltiexoren01", @"longentry1");                    
                              }
                              if ( Position.Quantity == ( Convert.ToInt32(Position1) + Convert.ToInt32(Position2) ) )
                              {
                              ExitLong(0, Convert.ToInt32(Position1), @"locltiexoren01", @"longentry1");
                              ExitLong(0, Convert.ToInt32(Position2), @"locltiexprtaen01", @"longentry2");
                              }                
                              }
              
              
              
                          }
              
              
                      }​

              ¿how are time filters - limits supposed to work? ¿can nt provide a working sample for a strategy that will open positions at 09:30, liquidate all positions at 16:00 and only trade between those times?

              Comment


                #8
                Hello rtwave,

                Thank you for your patience.

                As my colleague mentioned, "You would need to use prints to see if just the time condition portion of your condition is becoming true to know if the problem relates to your other logic." This should help you to better understand the behavior of your script and when it is evaluating the time filters based on when OnBarUpdate() is called. I see you have Calculate set to Calculate.OnBarClose, so OnBarUpdate() will only be called on the close of each BarsInProgress. Additionally, bars are timestamped with the closing time of the bar. In your time filter comparisons in your script, I see you are comparing the following with Timeopen and Timeclose:
                Times[1][0].TimeOfDay

                This only compares the TimeOfDay from the added 10-minute bars series, and this value is only updated at the close of each 10-minute bar. I suggest adding prints both outside of your current conditions as well as inside of your current conditions to get a better understanding of what values are being used and when your conditions are evaluating to true. For more information on using prints to debug your scripts:


                There is already a reference sample that demonstrates the concept of using time filters to limit trading hours that may be found here:


                The logic could be modified to start at 9:30 and end at 16:00, then another check could be added to close/liquidate all positions if it is outside of those times as follows:
                Code:
                if ((ToTime(Time[0]) < 93000 || ToTime(Time[0]) > 160000) && Position.MarketPosition != MarketPosition.Flat)
                {
                // if long, exit long
                if (Position.MarketPosition == MarketPosition.Long)
                ExitLong();
                // if short, exit short
                if (Position.MarketPosition == MarketPosition.Short)
                ExitShort();
                }​
                This is very similar to information I have already provided previously in this thread. It may help to simplify your start and end times to an int representation of the time in the format Hmmss so that you can use the ToTime() method as shown in the snippets and samples I have shared. For more information on ToTime():


                Please let us know if we may be of further assistance.
                Emily C.NinjaTrader Customer Service

                Comment


                  #9





                  people with nt,




                  i have a strategy, sampletimefiltersa, a second strategy, sampletimefiltersb, and i'm developing a third version, sampletimefiltersc.




                  the first two strategies are ready and the two are identical, they have the same engine to generate short and long positions:



                  if (CurrentBar % 2 == 0)
                  {
                  EnterShort(Convert.ToInt32(Position1), @"shortentry1");
                  }



                  if (CurrentBar % 2 == 1)
                  {
                  EnterLong(Convert.ToInt32(Position1), @"longentry1");
                  }



                  i'm evaluating them by backtesting over the exact same data, from the 1st of december 2023 to the 21st of january 2024. the primary series is 93 minute bars, the secondary series is 10 minute bars. the code supposedly should be identical, the settings are identical but the results are quite different.



                  and this time i do have the prints that nt always alludes to.



                  the difference i'm experimenting with is the bars index that positions are sent to, version a uses EnterShort(Convert.ToInt32(Position1), @"shortentry1"); while version b uses EnterShort(0, Convert.ToInt32(Position1), @"shortentry1"); . and for version c i intend to use the onorder execution update structures.




                  i share all the files related to version a as attachments.
                  Attached Files
                  Last edited by rtwave; 01-21-2024, 08:40 PM.

                  Comment


                    #10


                    these are the files for version b.

                    Attached Files

                    Comment


                      #11


                      and these two reports capture the situation for everyone who will not be bothered to check the files and the strategies:


                      version a:

                      Performance,All trades,Long trades,Short trades,
                      Total net profit,($15160.00),($850.00),($14310.00),
                      Gross profit,$52450.00,$29830.00,$22620.00,
                      Gross loss,($67610.00),($30680.00),($36930.00),
                      Commission,$0.00,$0.00,$0.00,
                      Profit factor,0.78,0.97,0.61,
                      Max. drawdown,($17770.00),($10900.00),($14310.00),
                      Sharpe ratio,-0.53,-0.06,-0.54,
                      Sortino ratio,-1.01,-0.09,-1.20,
                      Ulcer index,0.08,0.04,0.09,
                      R squared,0.68,0.09,0.84,
                      Probability,95.38%,52.94%,98.92%,
                      ,,,,
                      Start date,01-Dec-23,,,
                      End date,01-Jan-25,,,
                      ,,,,
                      Total # of trades,406,204,202,
                      Percent profitable,52.22%,59.80%,44.55%,
                      # of winning trades,212,122,90,
                      # of losing trades,194,82,112,
                      # of even trades,0,0,0,​



                      version b:


                      Performance,All trades,Long trades,Short trades,
                      Total net profit,($9350.00),$2990.00,($12340.00),
                      Gross profit,$47910.00,$28380.00,$19530.00,
                      Gross loss,($57260.00),($25390.00),($31870.00),
                      Commission,$0.00,$0.00,$0.00,
                      Profit factor,0.84,1.12,0.61,
                      Max. drawdown,($19650.00),($10000.00),($14960.00),
                      Sharpe ratio,-0.52,0.32,-0.51,
                      Sortino ratio,-1.14,0.91,-1.02,
                      Ulcer index,0.09,0.05,0.09,
                      R squared,0.55,0.05,0.82,
                      Probability,83.66%,28.56%,96.97%,
                      ,,,,
                      Start date,01-Dec-23,,,
                      End date,01-Jan-25,,,
                      ,,,,
                      Total # of trades,270,136,134,
                      Percent profitable,58.52%,67.65%,49.25%,
                      # of winning trades,158,92,66,
                      # of losing trades,112,44,68,
                      # of even trades,0,0,0,​




                      i just used 8000 ticks for the stop loss orders to disable them in both cases. everything is identical as far as i can tell.


                      ¿what can nt comment regarding such a situation? the returns are different, even the total number of trades is wildly different. ¿does nt have any idea of what could be happening? as i understand, both strategies send all positions to bars index 0 so there is no reason for any discrepancy.


                      and i will add version c as soon as i can complete it, i wouldn't be surprised if results for that version were in turn wildly different to the other two versions.

                      Comment


                        #12


                        version c is ready.



                        surprisingly, it seems like it is a perfect match with version b.



                        Performance,All trades,Long trades,Short trades,
                        Total net profit,($9350.00),$2990.00,($12340.00),
                        Gross profit,$47910.00,$28380.00,$19530.00,
                        Gross loss,($57260.00),($25390.00),($31870.00),
                        Commission,$0.00,$0.00,$0.00,
                        Profit factor,0.84,1.12,0.61,
                        Max. drawdown,($19650.00),($10000.00),($14960.00),
                        Sharpe ratio,-0.52,0.32,-0.51,
                        Sortino ratio,-1.14,0.91,-1.02,
                        Ulcer index,0.09,0.05,0.09,
                        R squared,0.55,0.05,0.82,
                        Probability,83.66%,28.56%,96.97%,
                        ,,,,
                        Start date,01-Dec-23,,,
                        End date,01-Jan-25,,,
                        ,,,,
                        Total # of trades,270,136,134,
                        Percent profitable,58.52%,67.65%,49.25%,
                        # of winning trades,158,92,66,
                        # of losing trades,112,44,68,
                        # of even trades,0,0,0,​


                        now it is up to nt to explain why version a is so different to the versions where bars index 0 is explicitly designated and how it would be possible to have all 3 versions operate in the exact same manner.


                        from what i have seen, the time filters seem to work as intended in versions b and c and possibly also in version a. and the engine that alternates short to long to short positions seems to work to perfection.
                        Attached Files
                        Last edited by rtwave; 01-22-2024, 02:15 AM.

                        Comment


                          #13
                          Hello rtwave,

                          Thank you for your note.

                          In version a of your strategy, you have conditions that submit orders to the added data series when BarsInProgress == 1:
                          Code:
                          else if(BarsInProgress == 1)
                          {
                              
                              
                              
                              Print("t0 " + Times[0][0] + " - t1 " + Times[1][0] + " - conditionshort " + conditionshort + " - conditionlong " + conditionlong + " - marketposition " + Position.MarketPosition );
                              
                              
                              
                              
                              if ( (conditionshort == true)
                              && (Times[1][0].TimeOfDay >= Timeopen.TimeOfDay)
                              && (Times[1][0].TimeOfDay < Timeopen.AddMinutes(4).TimeOfDay)
                              && (Position.MarketPosition != MarketPosition.Short) )
                              {
                              if ( Trade01short == true )
                              {
                              EnterShort(Convert.ToInt32(Position1), @"shortentry1");
                              }
                              if ( Trade02short == true )
                              {
                              EnterShort(Convert.ToInt32(Position2), @"shortentry2");
                              }                
                              }
                              
                              
                              if ( (conditionlong == true)
                              && (Times[1][0].TimeOfDay >= Timeopen.TimeOfDay)
                              && (Times[1][0].TimeOfDay < Timeopen.AddMinutes(4).TimeOfDay)
                              && (Position.MarketPosition != MarketPosition.Long) )
                              {
                              if ( Trade01long == true )
                              {
                              EnterLong(Convert.ToInt32(Position1), @"longentry1");
                              }
                              if ( Trade02long == true )
                              {
                              EnterLong(Convert.ToInt32(Position2), @"longentry2");
                              }
                              }
                              
                              
                              
                              if ((Times[1][0].TimeOfDay >= Timeclose.TimeOfDay)
                              && (Times[1][0].TimeOfDay < Timeclose.AddMinutes(4).TimeOfDay)
                              && (Position.MarketPosition == MarketPosition.Short))
                              {
                              if ( Position.Quantity == Convert.ToInt32(Position1) )
                              {
                              ExitShort(Convert.ToInt32(Position1), @"shcltiexorentry1", @"shortentry1");
                              }
                              if ( Position.Quantity == ( Convert.ToInt32(Position1) + Convert.ToInt32(Position2) ) )
                              {
                              ExitShort(Convert.ToInt32(Position1), @"shcltiexorentry1", @"shortentry1");
                              ExitShort(Convert.ToInt32(Position2), @"shcltiexorentry2", @"shortentry2");
                              }
                              }
                              
                              
                              if ((Times[1][0].TimeOfDay >= Timeclose.TimeOfDay)
                              && (Times[1][0].TimeOfDay < Timeclose.AddMinutes(4).TimeOfDay)
                              && (Position.MarketPosition == MarketPosition.Long))
                              {
                              if ( Position.Quantity == Convert.ToInt32(Position1) )
                              {
                              ExitLong(Convert.ToInt32(Position1), @"locltiexorentry1", @"longentry1");                    
                              }
                              if ( Position.Quantity == ( Convert.ToInt32(Position1) + Convert.ToInt32(Position2) ) )
                              {
                              ExitLong(Convert.ToInt32(Position1), @"locltiexorentry1", @"longentry1");
                              ExitLong(Convert.ToInt32(Position2), @"locltiexorentry2", @"longentry2");
                              }                
                              }
                              
                              
                              
                          }​
                          This is different from the other two strategies that explicitly submit orders to the primary series only, using BarsInProgressIndex 0. For more information on multi-series scripts as well as advanced order handling concepts, please see the following links:Please let us know if we may be of further assistance.
                          Emily C.NinjaTrader Customer Service

                          Comment


                            #14

                            people with nt,



                            thank you. this is one of the best replies i have read from nt during the time have been a member of these fora.


                            this is clear, informative and does solve the problem that has been raised.




                            just to be perfectly clear:


                            version a sends all entries generated inside the if(BarsInProgress == 0) section to the primary series and those generated inside the if(BarsInProgress == 1) section to the secondary series. so it would be possible to create an identical strategy without stop loss orders using the EnterShort(0,commands and designating the primary and secondary series inside each section as appropriate. ¿is this correct? and then, from what i understand, all the orders generated by SetStopLoss commands are only sent to the primary series, so it is impossible to have stop loss orders for entries generated inside the if(BarsInProgress == 1) section. ¿is this correct?


                            ¿is there be anything i could be missing in relation to these different structures?

                            Comment


                              #15
                              version a sends all entries generated inside the if(BarsInProgress == 0) section to the primary series and those generated inside the if(BarsInProgress == 1) section to the secondary series.
                              Yes, that is correct.

                              Code:
                              so it would be possible to create an identical strategy without stop loss orders using the EnterShort(0,commands and designating the primary and secondary series inside each section as appropriate. ¿is this correct?
                              Are you referring to an "identical strategy" as in a strategy that behaves the same as versions b and c? I am not sure what you mean by "without stop orders" either. This needs to be clarified so I can ensure I understand you before confirming or denying this point.

                              all the orders generated by SetStopLoss commands are only sent to the primary series, so it is impossible to have stop loss orders for entries generated inside the if(BarsInProgress == 1) section. ¿is this correct?
                              The logic you have in place for SetStopLoss() in version a is as follows:
                              Code:
                                              SetStopLoss(@"shortentry1", CalculationMode.Ticks, Stopsize, false);
                                              SetStopLoss(@"shortentry2", CalculationMode.Ticks, Stopsize, false);            
                                              SetStopLoss(@"longentry1", CalculationMode.Ticks, Stopsize, false);
                                              SetStopLoss(@"longentry2", CalculationMode.Ticks, Stopsize, false);
                              ​
                              If you had entries inside of the BarsInProgress == 1 section that have the aforementioned entry signals, then stop loss orders could still be generated for entries generated inside of that section of code. What exactly are you looking to achieve by separating your logic between your BarsInProgress == 0 and BarsInProgress == 1 sections?

                              I look forward to your reply.
                              Emily C.NinjaTrader Customer Service

                              Comment

                              Latest Posts

                              Collapse

                              Topics Statistics Last Post
                              Started by fx.practic, 10-15-2013, 12:53 AM
                              5 responses
                              5,404 views
                              0 likes
                              Last Post Bidder
                              by Bidder
                               
                              Started by Shai Samuel, 07-02-2022, 02:46 PM
                              4 responses
                              95 views
                              0 likes
                              Last Post Bidder
                              by Bidder
                               
                              Started by DJ888, Yesterday, 10:57 PM
                              0 responses
                              7 views
                              0 likes
                              Last Post DJ888
                              by DJ888
                               
                              Started by MacDad, 02-25-2024, 11:48 PM
                              7 responses
                              159 views
                              0 likes
                              Last Post loganjarosz123  
                              Started by Belfortbucks, Yesterday, 09:29 PM
                              0 responses
                              8 views
                              0 likes
                              Last Post Belfortbucks  
                              Working...
                              X