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

Method to multiply elements of a series by its lagged elements gives wrong results.

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

    Method to multiply elements of a series by its lagged elements gives wrong results.

    I am trying to write a method to be used within a strategy that will multiply the elements of a single Tseries by the lagged (bars ago) elements of the same series and then add them up for a given number of elements and a given lag. The method seems to work OK if it is only called ONE time within the strategy but if it is called more than once using different passed parameter values for each call it produces erroneous results. It’s as though there is some sort of undesirable “crosstalk” occurring between the independent method calls that corrupts all of the calculations.

    Here is the code:

    At the top of the script I have these declarations defining three custom series that are needed within the method:

    private Series<double> CandlePatterns;
    private Series<double> CandlePatterns1;
    private Series<double> CandlePatterns2;

    Then in OnStateChange within the block else if (State==State.DataLoaded) I have the following three statements:

    CandlePatterns = new Series<double>(this);
    CandlePatterns1 = new Series<double>(this);
    CandlePatterns2 = new Series<double>(this);

    (Side question: What does the key word “this” mean/do in this context?)

    Next, in a separate block, I have the code for the actual method. I placed this code block after OneStateChange and before OnBarUpdate.

    private double LagMultiply(int lag, int length, int BarsAgo)
    {

    // First ensure that enough candles are available to make the calculations:

    if (CurrentBars[0] < length + lag + BarsAgo
    return -1000.0;

    CandlePatterns[0] = Convert.ToDouble( Math.Sign( Close[0] - Open[0] ) ) ;
    // A Green Candle (Close [0] > Open[0] will produce +1 , A Red Candle (Close[0] < Open[0] ) will produce -1

    CandlePatterns1[0] = CandlePatterns[0] * CandlePatterns[lag];
    // Tseries Element multiplication with the corresponding lagged element of the same series for the given lag value.

    CandlePatterns2[0] = SUM(CandlePatterns1, length)[0];
    // Summing up the multiplied element values for a given input length

    return CandlePatterns2[BarsAgo];
    // Return the desired result at a the desired "bars ago" value.
    }

    I then have the following print statement(s) to test the calculated results

    Print("LagMultiply(0, 5, 0) = " +LagMultiply(0, 5, 0));

    This sets the lag to 0, uses a length of 5 elements, and returns the current result. Since the series CandlePatterns elements are either +1 (green candle) or -1 (red candle) setting the lag to 0 will produce a result of 5 which is also the maximum value it could possibly take since it is just multiplying the corresponding vector elements with themselves ( i.e. magnitude squared).

    Using Playback mode with downloaded NQ 12-23 data, while also keeping the time fixed/stationary in order to produce repeatable results on subsequent runs, the NinjaScript output are as follows:

    LagMultiply(0, 5, 0) = 5

    Setting the lag to 3 produces the following output:
    LagMultiply(3, 5, 0) = 1

    Setting the lag to 3 and the BarsAgo to 14 produces the following output:
    LagMultiply(3, 5, 14) = -3

    Setting the lag to 0, the length to 10, and BarsAgo to 0 produces the following output:
    LagMultiply(0, 10, 0) = 10

    Setting the lag to 1, the length to 10, and BarsAgo to 0 produces the following output:
    LagMultiply(1, 10, 0) = 0

    Setting the lag to 1, the length to 10, and BarsAgo to 4 produces the following output:
    LagMultiply(1, 10, 4) = 2

    All of the above results were produced using a SINGLE print statement (i.e. a single call to the method). I simply recompiled the script each time I changed the input parameter values to the method. These results are reasonable, and I believe are also accurate.

    The PROBLEM comes about when there are MULTIPLE CALLS to the METHOD with each call using different input parameter values. The results become corrupted and I don’t understand what is going on. Shouldn’t each call be independent of all the other calls? Why should multiple calls to this same method produce different (and incorrect) results? For example, using two print statements instead of just one,

    Print("LagMultiply(0, 5, 0) = " +LagMultiply(0, 5, 0));
    Print("LagMultiply(3, 5, 0) = " +LagMultiply(3, 5, 0));

    now produces different results from the single calls above with obviously incorrect results (compare to the above):
    LagMultiply(0, 5, 0) = 1241
    LagMultiply(3, 5, 0) = 1241

    As does:
    LagMultiply(0, 5, 0) = 1308
    LagMultiply(1, 10, 0) = 0

    Or three calls
    LagMultiply(0, 5, 0) = 1241
    LagMultiply(3, 5, 0) = 1241
    LagMultiply(3, 5, 14) = 1223

    Or four calls
    LagMultiply(0, 5, 0) = 5
    LagMultiply(3, 5, 0) = 5
    LagMultiply(3, 5, 14) = 10
    LagMultiply(0, 10, 0) = 10

    Or five calls
    LagMultiply(0, 5, 0) = 1308
    LagMultiply(3, 5, 0) = 1308
    LagMultiply(3, 5, 14) = 1299
    LagMultiply(0, 10, 0) = 1307
    LagMultiply(1, 10, 0) = 1307

    Or six calls
    LagMultiply(0, 5, 0) = 1308
    LagMultiply(3, 5, 0) = 1308
    LagMultiply(3, 5, 14) = 1299
    LagMultiply(0, 10, 0) = 1307
    LagMultiply(1, 10, 0) = 1307
    LagMultiply(1, 10, 4) = 1305

    Strangely, even the very first call to the method, in a sequence of multiple calls to it, produces a different result than the corresponding single call did. How can the very first call to this method, of the sequence of multiple calls to it, already be corrupted even before the subsequent calls were made? Why are the multiple calls impacting the results?I’m confounded. What am I misunderstanding?

    Can you please help me resolve this issue? I suspect that the way in which I structured the LagMultiply method and/or the custom series used within the method are somehow incompatible with the way the Tseries are constructed or referenced/indexed and that this is causing the corruption of the results when I place multiple calls to this same method within the strategy.

    Thank you for your advice, guidance, and solutions. It will be very much appreciated.

    Regards


    #2
    Hello Dr Kerry,

    'this' references the NinjaScript class, in this case the NinjaScript class is being supplied as the owner of the series.


    The CandlePatterns series are class level. If the method is modifying the series, those modifications will persist throughout each call to the method.

    Perhaps you want local method level arrays instead that return a value from the method instead of assigning values to class level variables from the method?


    Chelsea B.NinjaTrader Customer Service

    Comment


      #3
      Originally posted by NinjaTrader_ChelseaB View Post
      Hello Dr Kerry,

      'this' references the NinjaScript class, in this case the NinjaScript class is being supplied as the owner of the series.
      https://ninjatrader.com/support/help...t8/seriest.htm

      The CandlePatterns series are class level. If the method is modifying the series, those modifications will persist throughout each call to the method.

      Perhaps you want local method level arrays instead that return a value from the method instead of assigning values to class level variables from the method?

      Hello Chelsea,

      Thank you very much for your helpful advice.

      Are you suggesting that I place these statements inside the method:

      private Series<double> CandlePatterns;
      private Series<double> CandlePatterns1;
      private Series<double> CandlePatterns2;

      rather than at the very top of the script? This does make sense as it would keep the series localized to the method as opposed to being at the class level as you say.

      Would I also need these statements to be placed inside the method too?

      CandlePatterns = new Series<double>(this);
      CandlePatterns1 = new Series<double>(this);
      CandlePatterns2 = new Series<double>(this);

      Please advise on the proper way to declare such series within the method itself (or should I just use a conventional array ).




      Thank you again very much.

      Kerry
      Last edited by Dr Kerry; 09-23-2023, 02:49 AM.

      Comment


        #4
        Hello Kerry,

        From your description, it sounds like you are writing values from multiple methods to the same class level series which may be causing confusion.

        My suggestion was to use a method level array (or List).
        W3Schools offers free online tutorials, references and exercises in all the major languages of the web. Covering popular subjects like HTML, CSS, JavaScript, Python, SQL, Java, and many, many more.

        Create a new List, add elements to it, and loop over its elements with for and foreach.
        Chelsea B.NinjaTrader Customer Service

        Comment


          #5
          Originally posted by NinjaTrader_ChelseaB View Post
          Hello Kerry,

          From your description, it sounds like you are writing values from multiple methods to the same class level series which may be causing confusion.

          My suggestion was to use a method level array (or List).
          W3Schools offers free online tutorials, references and exercises in all the major languages of the web. Covering popular subjects like HTML, CSS, JavaScript, Python, SQL, Java, and many, many more.

          https://www.dotnetperls.com/list
          Hello Chelsea,

          Thank you again! Yes, I defined arrays within the method and loaded them with the values from the time series, then proceeded to do the calculations using the array elements and return these. That did work and resolved all of the issues. To do this though, I needed to use a "for loop" to write the time series values into the array elements. I always understood this to be a very slow / time consuming process especially when trying to do this under real-time trading conditions. That is why I was trying to work with the time series directly rather than first writing the time series values into the array. Is there a better, more time efficient, way to load an array with the values from a time series rather than the brute force "for loop" that I used?

          Thanks once again.

          Kerry

          Comment


            #6
            Hello Kerry,

            I'm not aware of another way other than using a loop.

            This thread will remain open for any community members that would like to provide advice on advanced custom C# to achieve this.
            Chelsea B.NinjaTrader Customer Service

            Comment


              #7
              Originally posted by NinjaTrader_ChelseaB View Post
              Hello Kerry,

              I'm not aware of another way other than using a loop.

              This thread will remain open for any community members that would like to provide advice on advanced custom C# to achieve this.
              Chelsea,

              I am very familiar with the Wolfram language (a.k.a. Mathematica) which I use in my professional work. It has a very rich assortment of multi-dimensional array manipulation capabilities. One of the most basic, however, is to refer to a set of array elements as opposes to just one-at-a-time. If, in Mathematica, there were two arrays Data and TimeData I can write the first ten elements of TimeData into Data using just one line without the need to invoke slow looping instructions by just writing:

              Data[[1;;10]] = TimeData[[1;;10]];

              Which copies the first ten elements of TimeData into Data. Is there nothing similar to this in C#?

              Regards,

              Kerry

              Comment


                #8
                Hello Kerry,

                There may be, but I am not familiar with it.

                Note, a Series<double> object is not the same thing a List<double> object or double[] array.
                Chelsea B.NinjaTrader Customer Service

                Comment


                  #9
                  Originally posted by NinjaTrader_ChelseaB View Post
                  Hello Kerry,

                  There may be, but I am not familiar with it.

                  Note, a Series<double> object is not the same thing a List<double> object or double[] array.
                  Chelsea,

                  I was doing a bit of searching and apparently C# has a range operator which is just " .. " that allows the selection of a range of elements in an array:

                  So writing Data[0..5] would return the first five elements of the array Data.

                  See: https://www.telerik.com/blogs/c-8-indices-and-range

                  or

                  https://zetcode.com/csharp/array/ (Scroll down to the "Array Slices" topic)​

                  Nevertheless, this did not work in NinjaScript. I tried it with an array and also a Series<Double> and it didn't like it in either one. From what I have read the range operator was introduced in 2019 in C# version 8. What version of C# is NinjaScript built upon?


                  Thank you again!

                  Kerry

                  Comment


                    #10
                    Hello Kerry,

                    At this time NinjaTrader uses C# 5 with .NET 4.8.


                    That said, the range would return an array, which is still not Series object.
                    Chelsea B.NinjaTrader Customer Service

                    Comment


                      #11
                      Originally posted by NinjaTrader_ChelseaB View Post
                      Hello Kerry,

                      At this time NinjaTrader uses C# 5 with .NET 4.8.


                      That said, the range would return an array, which is still not Series object.
                      Hello Chelsea,

                      Are there any plans or a schedule to update NinjaScript to the latest version of C#? The link that you shared is a post from 2017. Six years is a lifetime in the tech world. There are certainly many more language features that are not currently available to us that should be.

                      Regards,

                      Kerry

                      Comment


                        #12
                        Hello Kerry,

                        It has been requested and is something the development team is looking into.

                        Unfortunately, I am not able to provide information about upcoming releases.
                        Chelsea B.NinjaTrader Customer Service

                        Comment


                          #13
                          Mathematica is certainly a rich, high-level language, but this often implies that it's in fact slower than the "less rich," lower-level languages. If you looked at the Mathematica code behind Span (i.e. the Data[[1 ;; 10]] notation you mentioned), there is almost certainly going to be a for-loop, and that only after data checking, such as the simple check to ensure elements 1 through 10 even exist, that the span fits the assignment, etc. There is a lot going on under the hood and I would hazard a guess that your own for-loop would be faster than Span.

                          Anyway, like you, I'm eager to use the Data[1..10] notation in C#8. Much of my experience is with MATLAB, but its way of slicing is similar to Mathematica's. I ended up writing my own for NinjaScript. I have it posted in a forum entry on futures.io (now nexusfi, apparently):
                          https://nexusfi.com/ninjatrader/5820...tml#post891600
                          Last edited by benJephunneh; 10-08-2023, 07:21 PM.

                          Comment

                          Latest Posts

                          Collapse

                          Topics Statistics Last Post
                          Started by llanqui, Today, 10:32 AM
                          0 responses
                          2 views
                          0 likes
                          Last Post llanqui
                          by llanqui
                           
                          Started by StockTrader88, 03-06-2021, 08:58 AM
                          45 responses
                          3,992 views
                          3 likes
                          Last Post johntraderuser2  
                          Started by TAJTrades, Today, 09:46 AM
                          0 responses
                          8 views
                          0 likes
                          Last Post TAJTrades  
                          Started by rhyminkevin, Yesterday, 04:58 PM
                          5 responses
                          62 views
                          0 likes
                          Last Post dp8282
                          by dp8282
                           
                          Started by realblubb, Today, 09:28 AM
                          0 responses
                          8 views
                          0 likes
                          Last Post realblubb  
                          Working...
                          X