Announcement

Collapse
No announcement yet.

Partner 728x90

Collapse

Future expiry / rollover date and backtesting

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

    #16
    I've just tested with
    PHP Code:
        protected override void OnBarUpdate()
        {
    
          if (CurrentBars[0] < 55 || CurrentBars[1] < 4) return;
    
    
    
          NinjaTrader.Gui.Tools.SimpleFont myFont = new NinjaTrader.Gui.Tools.SimpleFont("Courier New", 12) { Size = 12, Bold = true };
    
          if (BarsInProgress == 0)
          {
    //       Draw.TextFixed(this, "tag1", "The current expiry is " + Bars.Instrument.MasterInstrument.GetNextExpiry(Dat eTime.Now).ToString("MM-yy"), TextPosition.BottomRight);
    
            Instrument Gold = Instrument.GetInstrument("GC");
            string goldExpiry = Gold.MasterInstrument.GetNextExpiry(DateTime.Now). ToString("MM-yy");
    
            Draw.TextFixed(this, "tag1", "The current expiry is1 " + goldExpiry, TextPosition.BottomLeft); 
    

    in
    PHP Code:
    #region Using declarations
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.ComponentModel.DataAnnotations;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Xml.Serialization;
    using NinjaTrader.Cbi;
    using NinjaTrader.Gui;
    using NinjaTrader.Gui.Chart;
    using NinjaTrader.Gui.SuperDom;
    using NinjaTrader.Gui.Tools;
    using NinjaTrader.Data;
    using NinjaTrader.NinjaScript;
    using NinjaTrader.Core.FloatingPoint;
    using NinjaTrader.NinjaScript.DrawingTools;
    #endregion
    
    //This namespace holds Indicators in this folder and is required. Do not change it.
    namespace NinjaTrader.NinjaScript.Indicators
    {
      public class DailyRanges : Indicator
      {
        private Series<double> CLSeries;
        private Series<double> ESSeries;
    
        protected override void OnStateChange()
        {
          if (State == State.SetDefaults)
          {
            Description                 = @"Enter the description for your new custom Indicator here.";
            Name                     = "DailyRanges";
            Calculate                 = Calculate.OnBarClose;
            IsOverlay                 = true;
            DisplayInDataBox               = true;
            DrawOnPricePanel               = true;
            DrawHorizontalGridLines           = true;
            DrawVerticalGridLines           = true;
            PaintPriceMarkers             = true;
            ScaleJustification             = NinjaTrader.Gui.Chart.ScaleJustification.Right;
            //Disable this property if your indicator requires custom values that cumulate with each new market data event.
            //See Help Guide for additional information.
            IsSuspendedWhileInactive           = true;
          }
          else if (State == State.Configure)
          {
    //       Instrument Gold = Instrument.GetInstrument("GC");
    //       AddDataSeries("GC "+Gold.MasterInstrument.GetNextExpiry(DateTime.Now ).ToString("MM-yy"), BarsPeriodType.Day, 1);
            AddDataSeries("CL 05-22", BarsPeriodType.Day, 1);
            AddDataSeries("ES 06-22", BarsPeriodType.Day, 1);
          }
          else if (State == State.DataLoaded)
          {
            CLSeries = new Series<double>(this, MaximumBarsLookBack.Infinite);
            ESSeries = new Series<double>(this, MaximumBarsLookBack.Infinite);
          }
        }
    
        protected override void OnBarUpdate()
        {
    
          if (CurrentBars[0] < 55 || CurrentBars[1] < 4) return;
    
    
    
          NinjaTrader.Gui.Tools.SimpleFont myFont = new NinjaTrader.Gui.Tools.SimpleFont("Courier New", 12) { Size = 12, Bold = true };
    
          if (BarsInProgress == 0)
          {
    //       Draw.TextFixed(this, "tag1", "The current expiry is " + Bars.Instrument.MasterInstrument.GetNextExpiry(Dat eTime.Now).ToString("MM-yy"), TextPosition.BottomRight);
    
            Instrument Gold = Instrument.GetInstrument("GC");
            string goldExpiry = Gold.MasterInstrument.GetNextExpiry(DateTime.Now). ToString("MM-yy");
    
            Draw.TextFixed(this, "tag1", "The current expiry is1 " + goldExpiry, TextPosition.BottomLeft);
    
            CLSeries[0] = Highs[1][0]-Lows[1][0];
    
            Draw.TextFixed(
              this,
              "GCSeries",
              "GC DRange: "+CLSeries[0],
              TextPosition.TopRight,
              Brushes.White,
              myFont,
              Brushes.Transparent,
              Brushes.Transparent,
              0);
    
            ESSeries[0] = Highs[2][0]-Lows[2][0];
    
            Draw.TextFixed(
              this,
              "ESSeries",
              new String('\n', 1)+"ES DRange: "+Instrument.MasterInstrument.RoundToTickSize(ESSe ries[0] / TickSize),
              TextPosition.TopRight,
              Brushes.White,
              myFont,
              Brushes.Transparent,
              Brushes.Transparent,
              0);
          }
        }
      }
    }
    
    #region NinjaScript generated code. Neither change nor remove.
    
    namespace NinjaTrader.NinjaScript.Indicators
    {
      public partial class Indicator : NinjaTrader.Gui.NinjaScript.IndicatorRenderBase
      {
        private DailyRanges[] cacheDailyRanges;
        public DailyRanges DailyRanges()
        {
          return DailyRanges(Input);
        }
    
        public DailyRanges DailyRanges(ISeries<double> input)
        {
          if (cacheDailyRanges != null)
            for (int idx = 0; idx < cacheDailyRanges.Length; idx++)
              if (cacheDailyRanges[idx] != null && cacheDailyRanges[idx].EqualsInput(input))
                return cacheDailyRanges[idx];
          return CacheIndicator<DailyRanges>(new DailyRanges(), input, ref cacheDailyRanges);
        }
      }
    }
    
    namespace NinjaTrader.NinjaScript.MarketAnalyzerColumns
    {
      public partial class MarketAnalyzerColumn : MarketAnalyzerColumnBase
      {
        public Indicators.DailyRanges DailyRanges()
        {
          return indicator.DailyRanges(Input);
        }
    
        public Indicators.DailyRanges DailyRanges(ISeries<double> input )
        {
          return indicator.DailyRanges(input);
        }
      }
    }
    
    namespace NinjaTrader.NinjaScript.Strategies
    {
      public partial class Strategy : NinjaTrader.Gui.NinjaScript.StrategyRenderBase
      {
        public Indicators.DailyRanges DailyRanges()
        {
          return indicator.DailyRanges(Input);
        }
    
        public Indicators.DailyRanges DailyRanges(ISeries<double> input )
        {
          return indicator.DailyRanges(input);
        }
      }
    }
    
    #endregion 
    

    and it still return 03-22 instead of 04-22 (on GC 04-22 1 min chart) on the BottomLeft Chart corner.
    How to make it return the correct 04-22 value? Thanks!

    Comment


      #17
      Hello PaulMohn,

      When posting on the forums, please do not create multiple posts. Instead, please edit your post so the last post is concise and only contains relevant information to your question.

      Multiple posts with large amounts of text make it more difficult to understand your exact issue, and makes it difficult for our support staff and for community members to help.

      I recently posted a method that could be used to fetch the symbol name including the next expiry in a separate thread yesterday, that may be helpful for your need. Please see below.

      https://ninjatrader.com/support/foru...83#post1195083
      JimNinjaTrader Customer Service

      Comment


        #18
        Hello Jim and thanks for the reply. I document each step of my solution so I can refer to the exact process later so i just have to remember the logic and not the syntax (when the syntax is absent from the doc or unclear in the doc). I also post the complete code so others can test it before their potentially improved solution-s. The less steps/the more effective/efficient the help the shorter/more concise the questions/solutions.

        Thank you for the method.

        It seems the
        PHP Code:
        Instrument Gold = Instrument.GetInstrument("GC");
        string goldExpiry = Gold.MasterInstrument. GetNextExpiry(DateTime.Now). ToString("MM-yy"); 
        
        /
        PHP Code:
        else if (State == State.Configure)
        {
           Instrument Gold = Instrument.GetInstrument("GC" );
           AddDataSeries("GC "+Gold.MasterInstrument.GetNextExpiry(DateTime.Now).ToString("MM-yy"), BarsPeriodType.Day, 1);
        } 
        

        approach would be shorter and simpler, potentially better to implement for many instuments.

        Why doesn't it return the correct expiry month (03-22 instead of 04-22 on a GC 04-22 1 min chart). How to make it return the correct expiry month? (I ask again because I haven't received answers to those questions and because it seems it would be more beneficial to get answers/solutions to those questions than using your method in case of use with a large number of instruments)


        I'm not sure how to use your method for my case.

        PHP Code:
        private string GetCurrentFuture(string name)
        {
          foreach (Instrument inst in Instrument.All)
          {
            if (inst.MasterInstrument.Name == name && inst.MasterInstrument.InstrumentType == InstrumentType.Future)
            {
              string instFullName = String.Format("{0} {1}-{2}",
                      name,
                      inst.MasterInstrument.GetNextExpiry(Core.Globals.N ow).Month.ToString("D2"),
                      inst.MasterInstrument.GetNextExpiry(Core.Globals.N ow).ToString("yy"));
              return instFullName;
            }
          }
          return name;
        } 
        

        In post#4 you say just giving the instrument name value to the method parameter with a string format

        Is that the correct use

        PHP Code:
        private string GetCurrentFuture(string "CL")
        {
          foreach (Instrument inst in Instrument.All)
          {
            if (inst.MasterInstrument.Name == name && inst.MasterInstrument.InstrumentType == InstrumentType.Future)
            {
              string instFullName = String.Format("{0} {1}-{2}",
                      name,
                      inst.MasterInstrument.GetNextExpiry(Core.Globals.N ow).Month.ToString("D2"),
                      inst.MasterInstrument.GetNextExpiry(Core.Globals.N ow).ToString("yy"));
              return instFullName;
            }
          }
          return name;
        } 
        

        If that's not correct would you please correct.

        If that's correct, is that how you intended to use it for my case?

        PHP Code:
        else if (State == State.Configure)
        {
           AddDataSeries(GetCurrentFuture(string "CL"), BarsPeriodType.Day, 1);
        } 
        

        If that is so, that means we need n number of GetCurrentFuture() method per n number of instrument, and the GetCurrentFuture() + it's needed AddDataSeries() corresponding line make for significantly longer (2/15 more lines) and less efficient (n use of loops) script than the

        PHP Code:
        else if (State == State.Configure)
        {
           Instrument Gold = Instrument.GetInstrument("GC" );
           AddDataSeries("GC "+Gold.MasterInstrument.GetNextExpiry(DateTime.Now).ToString("MM-yy"), BarsPeriodType.Day, 1);
        } 
        

        approach.

        Would you please have a fix for the
        PHP Code:
        else if (State == State.Configure)
        {
           Instrument Gold = Instrument.GetInstrument("GC" );
           AddDataSeries("GC "+Gold.MasterInstrument.GetNextExpiry(DateTime.Now).ToString("MM-yy"), BarsPeriodType.Day, 1);
        } 
        

        approach so it return the correct month expiry value? Thanks!


        I've tested your method correcting my previous syntax errors and ended up with the attached code
        using it in the AddDataSeries() method as
        PHP Code:
              else if (State == State.Configure)
              {
        //       Instrument Gold = Instrument.GetInstrument("GC");
        //       AddDataSeries("GC "+Gold.MasterInstrument.GetNextExpiry(DateTime.Now ).ToString("MM-yy"), BarsPeriodType.Day, 1);
                AddDataSeries(GetCurrentFuture("CL"), BarsPeriodType.Day, 1);
                AddDataSeries(GetCurrentFuture("ES"), BarsPeriodType.Day, 1);
              }
              else if (State == State.DataLoaded)
              {
                CLSeries = new Series<double>(this, MaximumBarsLookBack.Infinite);
                ESSeries = new Series<double>(this, MaximumBarsLookBack.Infinite);
              }
            }
        
            private string GetCurrentFuture(string name)
            {
            foreach (Instrument inst in Instrument.All)
            {
              if (inst.MasterInstrument.Name == name && inst.MasterInstrument.InstrumentType == InstrumentType.Future)
              {
              string instFullName = String.Format("{0} {1}-{2}",
                  name,
                  inst.MasterInstrument.GetNextExpiry(Core.Globals.N ow).Month.ToString("D2"),
                  inst.MasterInstrument.GetNextExpiry(Core.Globals.N ow).ToString("yy"));
              return instFullName;
              }
            }
            return name;
            } 
        

        but it doesn't display anything on the TopRight corner of the chart.

        Why isn't it working? Did you test it for my case to check if it worked? If not can you please check it on your end? Thanks!
        Attached Files
        Last edited by PaulMohn; 03-25-2022, 08:15 AM.

        Comment


          #19
          Hello Paul,

          There is a lot of information here that is a bit overwhelming. Please keep questions small and concise so we can better assist.

          When you are working with unlocked code, you will need to be familiar with C# and C# syntax.

          If you are struggling to write correct syntax using custom methods, I suggest getting more familiar with C# through some publicly available resources. Our support staff does not provide C# education, so I have included some links below that can help you get more familiar with C# and using custom methods.

          https://www.tutorialspoint.com/cshar...rp_methods.htm

          Learn Microsoft's popular C# programming language, used to make websites, mobile apps, video games, VR, and more.


          I also suggest keeping matters simple. I.E. focus on one question at a time. In this case, just focus on using the method in a separate script.

          First review the items above, and then implement the custom method I gave into a test script. Use a print to see what is coming out of the method so you can better understand how it would be used with other methods.

          After you are familiar using the method where you can provide "CL" and get "CL 05-22" it will be much clearer how to use that with AddDataSeries.
          JimNinjaTrader Customer Service

          Comment


            #20
            Hello Jim and thanks for the references. The issue here seems to be the calling of your custom method in the AddDataSeries() method, which I've never needed to do before and is not covered in the NT doc or the references you shared by an explicit example.

            I've tested printing as

            PHP Code:
                    AddDataSeries(GetCurrentFuture("CL"), BarsPeriodType.Day, 1);
                    AddDataSeries(GetCurrentFuture("ES"), BarsPeriodType.Day, 1);
                  }
                  else if (State == State.DataLoaded)
                  {
                    CLSeries = new Series<double>(this, MaximumBarsLookBack.Infinite);
                    ESSeries = new Series<double>(this, MaximumBarsLookBack.Infinite);
                  }
                }
            
                private string GetCurrentFuture(string name)
                {
                  foreach (Instrument inst in Instrument.All)
                  {
                    if (inst.MasterInstrument.Name == name && inst.MasterInstrument.InstrumentType == InstrumentType.Future)
                    {
                      string instFullName = String.Format("{0} {1}-{2}",
                              name,
                              inst.MasterInstrument.GetNextExpiry(Core.Globals.N ow).Month.ToString("D2"),
                              inst.MasterInstrument.GetNextExpiry(Core.Globals.N ow).ToString("yy"));
                      return instFullName;
                    }
                  }
                  return name;
                }
            
            
                protected override void OnBarUpdate()
                {
            
                  if (CurrentBars[0] < 55 || CurrentBars[1] < 4) return;
            
            
                  Print("GetCurrentFuture(string name) " + GetCurrentFuture("CL")); 
            

            But nothing Prints.

            Please see attached the exported script.
            Please see attached the screenshot.


            The references you shared

            Passing Parameters to a Method
            https://www.tutorialspoint.com/cshar...parameters.htm
            https://www.tutorialspoint.com/cshar...parameters.htm
            https://www.tutorialspoint.com/cshar...parameters.htm


            Thanks for those references.

            it seems for my use case the relevant one is
            C# - Passing Parameters by Value
            https://www.tutorialspoint.com/cshar...parameters.htm

            But the example given calls a class not a method, and assigns new values to the arguments of the method embedded in the called class, and does not use the arguments of its parameters as is, which would be the relevant use for my case. Therefore I cannot learn the relevant use from that reference.

            PHP Code:
            using System;
            
            namespace CalculatorApplication {
              class NumberManipulator {
                  public void swap(int x, int y) {
                    int temp;
            
                    temp = x; /* save the value of x */
                    x = y;     /* put y into x */
                    y = temp; /* put temp into y */
                  }
                  static void Main(string[] args) {
                    NumberManipulator n = new NumberManipulator();
            
                    /* local variable definition */
                    int a = 100;
                    int b = 200;
            
                    Console.WriteLine("Before swap, value of a : {0}", a);
                    Console.WriteLine("Before swap, value of b : {0}", b);
            
                    /* calling a function to swap the values */
                    n.swap(a, b);
            
                    Console.WriteLine("After swap, value of a : {0}", a);
                    Console.WriteLine("After swap, value of b : {0}", b);
            
                    Console.ReadLine();
                  }
              }
            } 
            

            C# - Methods
            https://www.tutorialspoint.com/cshar...rp_methods.htm
            • Parameter list − Enclosed between parentheses, the parameters are used to pass and receive data from a method. The parameter list refers to the type, order, and number of the parameters of a method. Parameters are optional; that is, a method may contain no parameters.
            Thanks for this reference.
            It seems my use of the string parameter is correct as "CL" when calling the GetCurrentFuture("CL") method in the AddDataSeries. Is it? If it is why doesn't it print/display on the chart? How to make it print/display on the chart? Thanks!
            Attached Files
            Last edited by PaulMohn; 03-25-2022, 10:20 AM.

            Comment


              #21
              Hello Paul,

              This is a custom method I wrote, and is not out-of-the-box NinjaScript. Being familiar enough with C# to test this out in it's simplest form will be the best way for you to move forward.

              Please just focus on using the method with a print without involving your current script.

              Confirm that when you provide "CL" that you get "CL 05-22"

              After confirming that, make a new script that uses the AddDataSeries overload that just takes an instrument name, and plug in my GetCurrentFuture() method.

              Add another print in OnBarUpdate for the instrument: Print(Instrument.FullName);

              Test the script on another symbol like MES 06-22.

              Observe the prints for MES 06-22 and CL 05-22 in the output window.
              JimNinjaTrader Customer Service

              Comment


                #22
                Many thanks for the steps Jim. Now it's working.

                However it wasn't working with the same code with my DailyRanges script.
                I notices the parentheses scopes were "less" spaces on my DailyRanges.cs script than with my new started from scratch jimExpirymethod.cs script.
                Would the less spaced scopes be the reason for not working (without any log tab nor compile error notice) in spite of correct syntax?
                I've added images of the process and the less spaced scope DailyRanges.cs script.

                Attached Files

                Comment


                  #23
                  Multiple Instruments working (added ES)
                  Attached Files

                  Comment


                    #24
                    Hello Paul,

                    Here is a publicly available resource on whitespace with C#:

                    https://www.oreilly.com/library/view...3%20statements.

                    I do not have enough information to know what is wrong. We see the prints and the text drawn. The script is working. If you are not getting a result you expect, the next steps are to better understand why you are getting the result you are. What you expect to see, and what you see that is not expected.

                    I have put some information below to help guide you:

                    "Defining the problem" is an important step in the debugging process to better understand your code.

                    I suggest to better describe what is not working so it is something specific that can be analyzed:
                    • What specifically isn't working? How can I test that repeatedly to see what is going on?
                    • If I add prints throughout the script, do I see any of them? By checking the prints: where does the execution stop?
                    A script must compile and be without runtime errors in order to see your prints. If your code hits a runtime error when you start to use it, adding prints to see where the code stops can help to move forward.

                    If the script is working and you see prints, and you do not see the results you expect, you will need to:
                    1. Identify specifically what is unexpected, and what you expect to see
                    2. Identify a procedure that can reproduce the symptom
                    3. Identify the code related to producing that result
                    4. Add prints to trace back how that result was calculated
                    Some things to think about since you are operating a Multi Time Frame script:
                    • What data series is OnBarUpdate processing on when I see the result I do not expect?
                    • What data series is being referenced when the symptom comes up?
                    • If I am working with Series objects, what data series are these synchronized to. What data series do I want them synchronized to?
                    • Are there enough bars in the specific data series I am referencing?
                    See below for working with Multi Time Frame scripts:

                    https://ninjatrader.com/support/help...nstruments.htm

                    Also see the Series documentation to better understand how to synchronize a Series object with an added data series.

                    Series - https://ninjatrader.com/support/help...ml?seriest.htm

                    Please consider the above as you are working on this over the weekend. If you need additional help:

                    Work up from the script that you put together that simply adds the data series, and step by step add the next piece of functionality until you see something you do not expect.

                    Since you are working with a Multi Time Frame script, also test implementing just on the primary series. (Are your issues related to using multiple data series?)

                    What do you add that causes the behavior to be unexpected?

                    What do you expect?

                    What do you see instead?
                    JimNinjaTrader Customer Service

                    Comment


                      #25
                      Thanks a lot for the investigation template process Jim. I'll try and use it over the weekend and for future projects as first resource.

                      Have a good Weekend!
                      Last edited by PaulMohn; 03-25-2022, 03:43 PM.

                      Comment


                        #26
                        Originally posted by NinjaTrader_ChelseaB View Post
                        Hello Klaus,

                        Are you wanting the <rolloverobject>.Date?
                        https://ninjatrader.com/support/help...collection.htm

                        You may find the RolloverIndications indicator helpful.
                        https://ninjatraderecosystem.com/use...indications-2/
                        NinjaTrader_ChelseaB, when time permits, there is a bug in the RolloverIndications script, which is otherwise quite the tour de force.

                        What appears to happen is, in OnBarUpdate, it calls InsertWPFControls(). In InsertWPFControls, it manipulates the chart window toolbar.

                        However, the indicator calculation thread pool threads that call OnBarUpdate are not UI threads, so a cross-thread exception can be generated under some conditions, which looks like this:

                        2023-03-29 18:05:01:977 ERROR: Indicator 'RolloverIndications': Error on calling 'OnBarUpdate' method on bar 1104: The calling thread cannot access this object because a different thread owns it.

                        To resolve this you could invoke over to the chart control's thread, or just restructure it so that these things don't happen in OnBarUpdate but in something like a dispatchertimer built from the chart control's thread.

                        It's a great indicator. The error I'm listing doesn't happen all the time. But, it does happen some of the time. Hope this helps.
                        Last edited by QuantKey_Bruce; 03-30-2023, 09:43 AM.
                        Bruce DeVault
                        QuantKey Trading Vendor Services
                        NinjaTrader Ecosystem Vendor - QuantKey

                        Comment


                          #27
                          Hello Bruce,

                          Thanks for reporting this!
                          I definitely overlooked those lines in OnBarUpdate().

                          I've got a dispatcher in there now which should resolve.
                          Chelsea B.NinjaTrader Customer Service

                          Comment

                          Latest Posts

                          Collapse

                          Topics Statistics Last Post
                          Started by RichardHK, 08-22-2024, 09:02 AM
                          4 responses
                          59 views
                          0 likes
                          Last Post RichardHK  
                          Started by HGTrader, Today, 09:31 AM
                          1 response
                          3 views
                          0 likes
                          Last Post NinjaTrader_Gaby  
                          Started by Gibranes, 10-12-2024, 04:02 AM
                          3 responses
                          14 views
                          0 likes
                          Last Post NinjaTrader_Jesse  
                          Started by dbennett3, Today, 09:18 AM
                          1 response
                          6 views
                          0 likes
                          Last Post NinjaTrader_Clayton  
                          Started by cupir2, Yesterday, 05:27 PM
                          1 response
                          14 views
                          0 likes
                          Last Post NinjaTrader_Jesse  
                          Working...
                          X