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

Simple Accumulator Code: 1 if met, else 0; need help

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

    Simple Accumulator Code: 1 if met, else 0; need help

    Hello, I was curious if someone would be able to help me sort out a simple bit of code that I'm trying to code.

    Goal: Calculate two moving averages, then calculate the slopes of those moving averages; if the slopes are less than a threshold assign a 0 value else 1; add the 1s and 0s; plot the result in a bar histogram to get an indication of whether your conditions were satisfied.

    I'm getting wrapped around the axel how everything talks and communicates with everything (ie, doubles, arrays, DataSeries, Value.Set, Values[0], plots, etc). My head is spinning and I need help.

    I guess that I'll have to start off step-wise by trying to confirm how all of the various inputs will need to talk and communicate with one another. Here are my assumptions:

    1. In the Initialize() section, I need to add a new plot of the Accumulator, and I am assuming that I will add this plot via:

    Add(new Plot(Color.Blue, PlotStyle.Bar, "Accumulator"));

    and I am assuming that this bit of code now defines the plot for Values[0]...but I don't understand where to add values to Values[0].

    2. In the OnBarUpdate() section, I need to have the:

    if(CurrentBar < 1)
    {
    return;
    }

    but I am not sure why. I think this is because if there are not enough bars to do the math, that we just need to return nothing...as we don't have enough information yet. Is that correct?

    3. Within the OnBarUpdate() section, I then have determined that I need to have a BarsInProgress sub-section where my magic is going to happen, and I am assuming that I will add this within the overall OnBarUpdate() section by adding in the code:

    if(BarsInProgress == 1)
    {
    //magic
    }

    On to magic.

    4. I have then determined, that within the BarsInProgress == 1 sub-section, that I need to have an additional section that looks at FirstTickOfBar. I have assumed that this is where I need to populate my EMA8 and EMA20 arrays. However, before populating my arrays, I needed to define them, so I defined them as:

    private double[] = EMA8Array = new double[8];
    private double[] = EMA20Array = new double[20];

    Is that right? Do these arrays need to be defined with 8 and 20 spots--or will just 2 or another number suffice? I probably need a little help on why 8/20 versus something else.

    I think I would then need to populate the EMA8Array via:

    EMA8Array[8] = EMA8Array[7];
    EMA8Array[7] = EMA8Array[6];
    EMA8Array[6] = EMA8Array[5];
    EMA8Array[5] = EMA8Array[4];
    EMA8Array[4] = EMA8Array[3];
    EMA8Array[3] = EMA8Array[2];
    EMA8Array[2] = EMA8Array[1];
    EMA8Array[1] = EMA8Array[0];

    and I would populate the EMA20Array in a similar fashion:

    EMA20Array[20] = EMA20Array[19];
    EMA20Array[19] = EMA20Array[18];
    EMA20Array[18] = EMA20Array[17];
    EMA20Array[17] = EMA20Array[16];
    EMA20Array[16] = EMA20Array[15];
    EMA20Array[15] = EMA20Array[14];
    EMA20Array[14] = EMA20Array[13];
    EMA20Array[13] = EMA20Array[12];
    EMA20Array[12] = EMA20Array[11];
    EMA20Array[11] = EMA20Array[10];
    EMA20Array[10] = EMA20Array[9];
    EMA20Array[9] = EMA20Array[8];
    EMA20Array[8] = EMA20Array[7];
    EMA20Array[7] = EMA20Array[6];
    EMA20Array[6] = EMA20Array[5];
    EMA20Array[5] = EMA20Array[4];
    EMA20Array[4] = EMA20Array[3];
    EMA20Array[3] = EMA20Array[2];
    EMA20Array[2] = EMA20Array[1];
    EMA20Array[1] = EMA20Array[0];

    Is the above necessary? Do I need to do this? Why or why not?

    5. The next step would be to define variables for the moving averages. Let's assume that I am trying to calculate an EMA with a period of 8 based on closes and an EMA with a period of 20 based on the closes. Given that the moving averages will not be integers, I'm assuming that they will need to be type double (as opposed to type int) and that I will define them as

    private double EMA8;
    private double EMA20;

    Is this correct?

    6. The next step would be actually calculating the moving averages, but this is where I take a second wrap around the axel, as I am not sure if these should be defined as

    EMA8 = EMA(Closes[1], 8);
    EMA20 = EMA(Closes[1], 20);

    or

    EMA8 = EMA(Closes[1], 8).Value[0];
    EMA20 = EMA(Closes[1], 20).Value[0];

    If they should be defined using the .Value[0] code, I don't understand why. Maybe someone can help me?

    7. The next step would then be to pass the EMA8 and EMA20 values into the arrays, and I think I would do this by:

    EMA8Array[0] = EMA8;
    EMA20Array[0] = EMA20;

    Is this right?

    8. Now for another turn around the axel: I have read that if you create a new DataSeries and that your chart has 200 bars, that the DataSeries will also have 200 values. So I created new DataSeries by:

    private DataSeries EMA8Series;
    private DataSeries EMA20Series;

    I then think that I need to populate these DataSeries by:

    EMA8Series[0] = EMA8Array[0];
    EMA20Series[0] = EMA20Array[0];

    But this is what is confusing to me, because I think of the arrays as holding values on a tick by tick basis (ie, what was the EMA value one tick ago) and the DataSeries as holding the EMA values that were in place when the previous bar closed. Is that right? How should I be thinking about how doubles talk to arrays talk to DataSeries? And how are tick movements intracandle different from differences between bars (ie, intercandle)? How should I be thinking about how these values are being stored? I'm really confused about this part, ie, intracandle vs. intercandle. I need help.

    9. I then came across a bit of code that I need to set the DataSeries by:

    EMA8Series.Set(1, EMA8Array[1]);
    EMA8Series.Set(2, EMA8Array[2]);
    EMA20Series.Set(1, EMA20Array[1]);
    EMA20Series.Set(2, EMA20Array[2]);

    But I flat don't understand this. I'm hoping that someone can explain to me what the above code would do.

    10. Now I would calculate my slopes. But first I created two double variables to hold the slope values:

    private double EMA8SlopeValue;
    private double EMA20SlopeValue;

    and then I would assign values to the slope values via:

    EMA8SlopeValue = radToDegrees * (Math.Atan((EMA8Series[0] - EMA8Series[1]) * 2.5 / ATR(Closes[1], 3)[0]));
    EMA20SlopeValue = radToDegrees * (Math.Atan((EMA20Series[0] - EMA20Series[1]) * 2.5 / ATR(Closes[1], 3)[0]));

    NOTE: I set up a Constant of:

    private const double radToDegrees = 180/Math.PI;

    So now, I should have slope values in the EMA8SlopeValue and EMA20SlopeValue double variables, which in theory I should be able to now test off of.

    11. The next step would be to see if the slope values meet or exceed my slope thresholds, and if they meet my condition I assign a 1 or a 0 to a slope accumulator value. However, I first had to create two more int variables to hold my slope accumulator values:

    private int EMA8SlopeAccumulatorValue;
    private int EMA20SlopeAccumulatorValue;

    I then ran my if statements and assigned a 1 or 0:

    if(EMA8SlopeValue < 25 && EMA8SlopeValue > -25)
    EMA8AccumulatorValue = 0;
    else
    EMA8AccumulatorValue = 1;

    if(EMA20SlopeValue < 20 && EMA20SlopeValue > -20)
    EMA20AccumulatorValue = 0;
    else
    EMA20AccumulatorValue = 1;

    So now, in theory I should have either a 1 or a 0 in my slope accumulator values.

    12. Now I need to add the slope accumulator values up, and give that result to the Accumulator plot DataSeries, but that just ain't workin':

    Accumulator.Set(EMA8AccumulatorValue + EMA20AccumulatorValue);

    So I am able to compile the code, and I get no compile errors. But then I reload the indicator on my chart, and I get zip: it's blank. So now I am here, trying to get some help. I think this is easy, but I just think I am missing some very fundamental understandings of how all of these things relate to one another. I did such a thorough post with the hope that others will be able to learn something from the 10,000' view on how all of these items interrelate.

    I really appreciate any help anyone can offer.

    I am standing by to answer questions.

    Thanks,

    Aventeren

    #2
    Log Ouput

    All--

    I just opened the Log under the Control Center > Log. Evidently I am getting the following error:

    "Error calling "OnBarUpdate' method for indicator 'Name' on bar 21: Index was outside the bounds of the array.

    So this makes me think this has something to do with how I have defined and populated my arrays.

    Hopefully this bit of info will help...

    Thanks,

    Aventeren

    Comment


      #3
      Hello aventeren,

      Thank you for your post.

      I am currently creating a comprehensive reply for you.

      Thank you for your patience.
      Chelsea B.NinjaTrader Customer Service

      Comment


        #4
        Originally posted by NinjaTrader_ChelseaB View Post
        Hello aventeren,

        Thank you for your post.

        I am currently creating a comprehensive reply for you.

        Thank you for your patience.
        Thanks, Chelsea; standing by.

        Comment


          #5
          Hello

          1) Yes, that add will create a new plot to which you can set values using this method:
          Values[0].Set(99.99);

          Below is a link to the help guide that shows an example of setting Values for a plot.
          http://www.ninjatrader.com/support/h...nt7/values.htm


          2) The example in the help guide from the link above uses if (CurrentBar < 1) return; because it is using Values[1][1] in a condition. Trying to access a bar that doesn't exist will cause an error and will disable your strategy.

          If you are going to be using historical data, be sure not to call a bar that does not exist.

          For example if you need a bar 30 bars ago such as Close[30], be sure there are at least 30 bars of historical data.

          if (CurrentBar < 29)
          return;

          Just as a tip, the index for bars ago starts with 0.


          3) I understand, and your usage of this looks correct as well. As long as there is a secondary data series that has been added to the script.

          For example:
          Add(PeriodType.Minute, 2);

          The code you have will insure that the magic only happens when the second data series is processing.


          4) For this I am not quite sure what you are attempting to do here. Are you wanting to have a double array of SMA values?

          For example:
          private double[] eMA8Array = new double[8];

          eMA8Array[0] = EMA(8)[0];

          Once in the array how will these be used? Why do you need to save these values to an array instead of using EMA(period)[barsAgo] directly?

          Also using a capital here would mean you are wanting a public double array. More on that in the next question.


          5) Your declaration here would be for a public double as the first character is a capital. If you would like a private double the first character of your variable will need to be lower case.

          Also, I am still not quite certain why you are saving these values to an array and then to a variable instead of accessing the value directly.


          6) The usage to return the default plot value from an indicator would be:
          eMA8 = EMA(Closes[1], 8)[0];


          7) Again this seems to be an extra step, however, assuming the variable names are correct, this would save the double values to the first index of eMA8Array and eMA20Array.


          8) Once you have created the data series variable you will need to add the dataseries to the script as well in the Initialize()

          For example:

          Add(eMASeries);

          Then to set it use:

          eMASeries.Set(99.99);


          9) The code EMA8Series.Set(2, EMA8Array[2]); would set the EMA8Series value to the value of EMA8Array[2] two bars ago.

          So printing EMA8Series[2] would give you the value of EMA8Series[2].


          10) All of this seems correct.


          11) This is all correct as well.


          12) This also seems correct as long as there is a plot named Accumulator that has been added to the script.



          The best way to debug your code is with lots and lots of print statements. Print statements will output to the Output window (Tools -> Output Window).

          I usually start at the beginning and print the values I am about to use. Then I print the values after I have set them to a dataseries or passed them to another variable.

          I print all of the values of every step so that I may track the progress of the script.


          Please let me know if I can be of any further assistance for you.
          Chelsea B.NinjaTrader Customer Service

          Comment


            #6
            Chelsea--

            Thanks for a very thorough response. I am hopeful that others in the future will find this exchange helpful.

            I'm going to buzz through your responses--with my responses. Here we go.

            1. Cool; thanks.

            2. Because my largest moving average period will be 20, I changed this to:

            if(CurrentBars[0] < 19)
            return;

            Hopefully that will improve things.

            3. Good eye. I do intend to use this as a multi-time frame indicator (ie, not only looking at the current chart's conditions and accumulator value, but also the chart conditions and accumulator values on higher time frames. So yes, I did already have the following code in the Initialize() section:

            Add(PeriodType.Range, 4);

            4. Now we're getting into the good stuff--this is where I am hoping to streamline and improve my coding...and more importantly, my understanding of how all of these items work.

            First, the easy follow-on question: does using _EMA8Array alleviate the issue caused by using a capital letter (ie, EMA8Array)? I have seen some other programmers do this, and this appears like a slick way of still using capitals...but just with the "_" before the capital letters. Will that work?

            Second, on to the array piece. To be honest, this is where I really wanted your input. At the end of the day, all I need to do is to be able to access values in the past. I found an indicator that accomplished this by the above method, but it seems like a weird way of accomplishing my goal. If I in fact can just use EMA(8)[BarsAgo] that would be rad, as it would cut a bunch or unnecessary code--which I like. So I'll give this a shot. Thanks!

            5. Again, spot on. I'm going to look into using the values directly via the [BarsAgo] concept.

            6. So setting

            _EMA8 = EMA(Closes[1], 8)[0];

            basically just populates the current _EMA8 (denominated by the [0])? And then I can just pull this value by calling EMA(Closes[1],8)[0]? Heck, why do I even need the EMA8 value then? Maybe I can further eliminate code and variables by just hard coding the EMA(Closes[1],8)[0] for the current EMA and EMA(Closes[1],8)[1] for the previous EMA? That would be nice...it would cut a ton of noise from my code.

            However, here is a key question, does EMA(Closes[1],8)[1] refer to the EMA 1 tick ago or 1 bar ago? If it references the EMA 1 bar ago, I think I'm in the clear. However if it only references the EMA 1 tick ago, I'm going to need to figure out a different way to access the EMA value from 1 bar ago--because the EMA from 1 tick ago isn't all that useful to me.

            7. Depending on your response to item 6, I would agree that this may not be necessary--which again, would be great!

            8. I think my original question still stands. Although you helped me with the "how", I was really looking for a better understanding of the "why", ie, how does a DataSeries talk to an array? Is the data held intercandle (bar[0] vs bar[1]) or intracandle (tick[0] vs tick[1])?

            If I am able to call the correct EMA values (which for me, correct would mean EMA(Closes[1],8)[1] is the EMA from the last bar...not the last tick), then I think that I could do away with this DataSeries. Do you agree? At the end of the day, all I need is the current EMA value and the EMA value at the close of the last bar so that I can calculate a slope.

            But to say that I understand the DataSeries piece would be a HUGE stretch. I still don't get them.

            9. Okay, thanks.

            10. Okay, thanks.

            11. Okay, thanks.

            12. Okay, thanks. I did add a plot called Accumulator in the Initialize() section via:

            Add(new Plot(Color.Blue, PlotStyle.Bar, "Accumulator")); //defines the plot for Values[0]

            Again, thanks for a very through response! I look forward to your follow up answers to my follow up questions.

            Thanks,

            Aventeren

            Comment


              #7
              Originally posted by aventeren View Post
              Chelsea--

              Thanks for a very thorough response. I am hopeful that others in the future will find this exchange helpful.

              I'm going to buzz through your responses--with my responses. Here we go.

              1. Cool; thanks.

              2. Because my largest moving average period will be 20, I changed this to:

              if(CurrentBars[0] < 19)
              return;

              Hopefully that will improve things.

              3. Good eye. I do intend to use this as a multi-time frame indicator (ie, not only looking at the current chart's conditions and accumulator value, but also the chart conditions and accumulator values on higher time frames. So yes, I did already have the following code in the Initialize() section:

              Add(PeriodType.Range, 4);

              4. Now we're getting into the good stuff--this is where I am hoping to streamline and improve my coding...and more importantly, my understanding of how all of these items work.

              First, the easy follow-on question: does using _EMA8Array alleviate the issue caused by using a capital letter (ie, EMA8Array)? I have seen some other programmers do this, and this appears like a slick way of still using capitals...but just with the "_" before the capital letters. Will that work?

              Second, on to the array piece. To be honest, this is where I really wanted your input. At the end of the day, all I need to do is to be able to access values in the past. I found an indicator that accomplished this by the above method, but it seems like a weird way of accomplishing my goal. If I in fact can just use EMA(8)[BarsAgo] that would be rad, as it would cut a bunch or unnecessary code--which I like. So I'll give this a shot. Thanks!

              5. Again, spot on. I'm going to look into using the values directly via the [BarsAgo] concept.

              6. So setting

              _EMA8 = EMA(Closes[1], 8)[0];

              basically just populates the current _EMA8 (denominated by the [0])? And then I can just pull this value by calling EMA(Closes[1],8)[0]? Heck, why do I even need the EMA8 value then? Maybe I can further eliminate code and variables by just hard coding the EMA(Closes[1],8)[0] for the current EMA and EMA(Closes[1],8)[1] for the previous EMA? That would be nice...it would cut a ton of noise from my code.

              However, here is a key question, does EMA(Closes[1],8)[1] refer to the EMA 1 tick ago or 1 bar ago? If it references the EMA 1 bar ago, I think I'm in the clear. However if it only references the EMA 1 tick ago, I'm going to need to figure out a different way to access the EMA value from 1 bar ago--because the EMA from 1 tick ago isn't all that useful to me.

              7. Depending on your response to item 6, I would agree that this may not be necessary--which again, would be great!

              8. I think my original question still stands. Although you helped me with the "how", I was really looking for a better understanding of the "why", ie, how does a DataSeries talk to an array? Is the data held intercandle (bar[0] vs bar[1]) or intracandle (tick[0] vs tick[1])?

              If I am able to call the correct EMA values (which for me, correct would mean EMA(Closes[1],8)[1] is the EMA from the last bar...not the last tick), then I think that I could do away with this DataSeries. Do you agree? At the end of the day, all I need is the current EMA value and the EMA value at the close of the last bar so that I can calculate a slope.

              But to say that I understand the DataSeries piece would be a HUGE stretch. I still don't get them.

              9. Okay, thanks.

              10. Okay, thanks.

              11. Okay, thanks.

              12. Okay, thanks. I did add a plot called Accumulator in the Initialize() section via:

              Add(new Plot(Color.Blue, PlotStyle.Bar, "Accumulator")); //defines the plot for Values[0]

              Again, thanks for a very through response! I look forward to your follow up answers to my follow up questions.

              Thanks,

              Aventeren
              When I first saw your scheme, I was wondering why you were doing so much redundant work. Your statement about the DataSeries pretty much tells me why.

              Let me see if I can help here. Think of a DataSeries as just that: a series of Data values (doubles) held in a List<> type of structure, indexed one-to-one with the bars on the chart. That immediately tells you that you already have something akin to an ArrayList, which is necessarily already indexed, so there is no need to take its values and place them in an Array so that you can massage the data. The data is already indexed in a dynamic Array. Just use it.

              An index of y will always refer to a value held in the DataSeries that corresponds to the bar that is y bars ago. So DataSeriesValues[1] is always the value of DataSeriesValues 1 bar ago.

              It may also be the value 1 tick ago, but if and only if CalculateOnBarClose is true, simply because, by the very name of the property, there can be only one tick per bar in that case, and it comes when the bar closes. If CalculateOnBarClose is false, then you can only access the value 1 tick ago, by explicitly storing it: the value Close[0] will always represent the most recent tick.
              Last edited by koganam; 05-28-2013, 10:22 AM. Reason: Corrected spelling.

              Comment


                #8
                Hello aventeren,

                Thanks for your post.

                4) An underscore would allow you to prevent issues with case on a private variable.

                6) EMA(Closes[1],8)[1]

                It depends on what your secondary data series is as to whether this will use the tick or minute interval.

                By supplying Closes[1] as the data series you are asking for the EMA of 1 bar ago for the secondary data series. This means if the secondary data series is a minute interval it will be the EMA of a minute ago. If the secondary data series is a range interval, the range interval will be used and the EMA will return the value of the EMA of a full range bar ago.

                8) kognam's post here is correct.

                When I first saw your scheme, I was wondering why you were doing so much redundat work. Your statement about the DataSeries pretty much tells me why.

                Let me see if I can help here. Think of a DataSeries as just that: a series of Data values (doubles) held in a List<> type of structure, indexed one-to-one with the bars on the chart. That immediately tells you that you already have something akin to an ArrayList, which is necessarily already indexed, so there is no need to take its values and place them in an Array so that you can massage the data. The data is already indexed in a dynamic Array. Just use it.

                An index of y will always refer to a value held in the DataSeries that corresponds to the bar that is y bars ago. So DataSeriesValues[1] is always the value of DataSeriesValues 1 bar ago.

                It may also be the value 1 tick ago, but if and only if CalculateOnBarClose is true, simply because, by the very name of the property, there can be only one tick per bar in that case, and it comes when the bar closes. If CalculateOnBarClose is false, then you can only access the value 1 tick ago, by explicitly storing it: the value Close[0] will always represent the most recent tick.
                Please let me know if this does not answer your question and I will try and provide further explanation.
                Chelsea B.NinjaTrader Customer Service

                Comment


                  #9
                  All the calculations needed for your indicator can be done in one line.
                  Forget about multi timeframe. First do it on main TF.
                  Same code can be duplicated to the second, etc' TF's.
                  For example EMA(8)[0] will give you the correct value if its inside the correct BarsInProgress.

                  Baruch

                  Comment

                  Latest Posts

                  Collapse

                  Topics Statistics Last Post
                  Started by frslvr, 04-11-2024, 07:26 AM
                  8 responses
                  111 views
                  1 like
                  Last Post NinjaTrader_BrandonH  
                  Started by stafe, 04-15-2024, 08:34 PM
                  10 responses
                  43 views
                  0 likes
                  Last Post stafe
                  by stafe
                   
                  Started by rocketman7, Today, 09:41 AM
                  3 responses
                  8 views
                  0 likes
                  Last Post NinjaTrader_Jesse  
                  Started by traderqz, Today, 09:44 AM
                  2 responses
                  5 views
                  0 likes
                  Last Post NinjaTrader_Gaby  
                  Started by rocketman7, Today, 02:12 AM
                  7 responses
                  31 views
                  0 likes
                  Last Post NinjaTrader_ChelseaB  
                  Working...
                  X