Announcement

Collapse
No announcement yet.

Partner 728x90

Collapse

ISeries<double> Open, High, Low, Close work in one indicator, but not another... Why?

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

    ISeries<double> Open, High, Low, Close work in one indicator, but not another... Why?

    Hi there, fellow Ninjas! I have run into many problems along my journey, but this one has continued to stump me! Please read on and I would appreciate any help you all can offer. Thanks in advance!

    I have one indicator called DayRange. It has some methods, one of which is Blue(). If you go inside Blue, it uses NinjaTrader's ISeries<double> Open and Close without issue. When I call DayRange from a strategy I can successfully say
    var blue = DayRange().Blue();
    and everything comes back how I would expect. Note that I do not have to type
    var blue = DayRange().Blue(Open, Close)
    and pass those ISeries into my function.

    Now here's where I get confused...

    I have another function called Candle. When I type
    var body = Candle().Body();
    I get the old
    "Strategy 'G0901': Error on calling 'OnBarUpdate' method on bar 10: You are accessing an index with a value that is invalid since it is out-of-range. I.E. accessing a series [barsAgo] with a value of 5 when there are only 4 bars on the chart."

    If I type
    var body = Candle().Body(Open, Close);
    and pass the ISeries<double> values Open and Close into the method, then it works as expected. So the function would look like this

    public double Candle(ISeries<double> Open, ISeries<double> Close)
    {
    return Math.Abs(Open[0] - Close[0]);
    }

    I've put the two files side by side and made all of the "extras" (everything outside of the function) as identical as I think I can. Obviously I'm missing something, does anyone know what that might be? What makes a class/Indicator/whatever grab those NinjaTrader ISeries and make them available for me to call? I would love to know. Thanks again in advance.

    Best Regards,
    Nate.

    #2
    Hi Nate G,

    if you'd like to develop more efficiently I'd recommend installing Visual Studio. VS will automatically pause where the error occurs if NT code was compiled in debug mode and VS is attached to the NT process. For details how to do this here is the reference https://ninjatrader.com/support/help..._debugging.htm or a video https://www.youtube.com/watch?v=olIwH8XtKJs

    If you don't want to install VS, enable debug mode (right click in the NT editor, described in the previous references) and surround your code with a try/catch block

    Code:
    try
    {
         // your code
    }
    catch(Exception ex)
    {
        Print(ex.StackTrace);
        throw(ex);
    }
    Now you'll get the exact line number where the exception was thrown.

    Comment


      #3
      Hello Nate G,

      The error you are getting is pretty standard if you try to use a BarsAgo without data available or in this case it could be due to being in the wrong context.

      It sounds like you made some custom classes/structures so that may play a role here. What I would suggest for this question is to make a very small sample of your method/class/structure and how you called it so I can see the context that is being called from.

      The properties like Close and Open are populated by the scripts events like OnBarUpdate. An example where this would not be populated would be called from a custom method like a button event or even OnRender because that is a render pass and not a NinjaScript event like OnBarUpdate. Another case would be a custom class, that is just a class and has no information about your indicators properties.

      There are other ways to access the data depending on the use case, it is also possible to structure what you are doing differently so that it works.


      I look forward to being of further assistance.
      JesseNinjaTrader Customer Service

      Comment


        #4
        Mojo, thank you for that! I am yet to figure out debug mode and Try Catch blocks. I've just been putting Print("whatever line number) statements in to identify where my code breaks. Dumb but it has gotten me this far. At that point I have to drill down into the class that borked. I knew I should learn Try Catch blocks, but just have not take the time to do it. I will check those links out and see where that gets me. Thank you again! Also, I am using VS2019. Not sure how I'd handle Ninja's compiler, but I'm finally getting the hang of VS2019 and liking it.

        Jesse, I get the impression that I am able to call such things as Open[], High[], Low[], and Close[] because I am calling OnBarUpdate() at some point in my DayRange() Indicator. If I did not call OnBarUpdate, would I just not get access to those ISeries<>? Is that the deciding factor? I've pasted a stripped down version of my DayRange() Indicator. I'm also pasting a little bit of my Candle class below that as well (it's definitely a class with methods moreso than an actual indicator).

        namespace NinjaTrader.NinjaScript.Indicators
        {
        public class DayRange : Indicator
        {
        private string stringVar1;
        private double someDoubleThing1;

        protected override void OnStateChange()
        {
        if (State == State.SetDefaults)
        {
        Description = "Plot and return key price levels";
        Name = "DayRange";
        IsOverlay = true;
        IsSuspendedWhileInactive = true;
        IsAutoScale = false;

        AddPlot(new Stroke(Brushes.RoyalBlue, 3), PlotStyle.Line, "Blue"); // Values[1][0]
        AddPlot(new Stroke(Brushes.Red, 3), PlotStyle.Line, "Red"); // Values[2][0]
        AddPlot(new Stroke(Brushes.SandyBrown, 3), PlotStyle.Line, "Brown"); // Values[3][0]
        }
        else if (State == State.DataLoaded)
        {
        atr = ATR(14);
        emaFast = EMA(EMAFastWindow);
        emaSlow = EMA(EMASlowWindow);
        }
        }

        protected override void OnBarUpdate()
        {
        if (CurrentBar < 2) return;

        if (Blue(CurrentBar) > 0)
        {
        Values[1][0] = Blue(CurrentBar);
        Values[2][0] = Red(CurrentBar);
        Values[3][0] = Brown(CurrentBar);
        }

        public double Blue(int CurrentBar)
        {
        MasterInstrument masterInstrument = new MasterInstrument();
        return masterInstrument.RoundToTickSize(RangeMin(CurrentB ar) + Range(CurrentBar) * 0.50);
        }

        public double RangeMin(int CurrentBar)
        {
        // a bunch of logic that uses Low[]
        return min;
        }

        public double RangeMax(int CurrentBar)
        {
        // a bunch of logic that uses High[]
        return max;
        }

        public double Range(int CurrentBar)
        {
        return RangeMax(CurrentBar) - RangeMin(CurrentBar);
        }
        }
        __________________________________________________ ______________________

        Below, you'll see that I tried to cheat here by simply adding an OnBarUpdate() section. Currently it effectively does nothing. Do I need to put some code in that block to get it to really call in the ISeries I'm after? My intention is that I want a class with some methods that I can call and they will return properties of a candle of a given index. Body, high-to-low range, color. So it doesn't need to be an indicator at all. Should I just accept the fact that if I'm not using OnBarUpdate() that I just need pass the correct parameters and that's that? Part of this is I'd like to follow best practices, and I'd also like to be consistent so when I have many classes and methods down the road, everything is consistent and clear.

        namespace NinjaTrader.NinjaScript.Indicators
        {
        public class Candle : Indicator
        {
        protected override void OnStateChange()
        {
        if (State == State.SetDefaults)
        {
        Description = "Returns a candle's properties";
        Name = "Candle";
        IsOverlay = false;
        IsSuspendedWhileInactive = true;
        IsAutoScale = false;
        }
        else if (State == State.DataLoaded)
        {
        }
        }

        protected override void OnBarUpdate()
        {
        }

        public double Body(int index)
        {
        return Math.Abs(Close[index] - Open[index]);
        }

        Comment


          #5
          Hello

          Thanks for providing the sample that helps.

          In this case this is due to making a public method, that specifically won't be able to be used when calling it from a different script as you are expecting. You would need to use the Update() method in your method: https://ninjatrader.com/support/help...nt8/update.htm

          Some scripts use this for special cases like the ZigZag in its LowBar method. In most cases you would want to avoid this because it does take more resources to use Update. If possible I would suggest to just make a Plot of this data if the purpose of this indicator is just a utility. For example:

          Instead of:
          Code:
          public double Body(int index)
          {
          return Math.Abs(Close[index] - Open[index]);
          }
          You could do:
          Code:
          protected override void OnBarUpdate()
          {
              Body[0] = Math.Abs(Close[0] - Open[0]); //this assumes you create a plot and public property named Body.
          }
          Then in the other script you can access by the plot name Candle().Body[0], the Index would be replaced with the BarsAgo. This stores a value for every bar which can later be referenced by using the plot.


          For a utility class that just contains shared code that depends on the scope you need. In most cases you can use a partial class for this type of use case if you are just referencing NinjaScript properties or doing simple tasks like math. Here is a quick example of a partial class.

          Create a new indicator
          Remove the code leaving just the using statements
          Paste the following:
          Code:
          namespace NinjaTrader.NinjaScript.Indicators
          {
                 public partial class Indicator
              {
                  public double Body(int index)
                  {
                  return Math.Abs(Close[index] - Open[index]);
                  }
              }
          }
          Now in any indicator you can call Body(1) and that would return the return Math.Abs(Close[1] - Open[1]);

          This is not a useful approach if you mean to export the file or share this later on, this would be good for personal use in your local platform. If you want to share it you could create a normal class and pass "this" to the class method.

          Code:
          public double Body(Indicator instance, int index)
                  {
                  return Math.Abs(instance.Close[index] - instance.Open[index]);
                  }
          Last edited by NinjaTrader_Jesse; 07-03-2020, 11:27 AM.
          JesseNinjaTrader Customer Service

          Comment


            #6
            Wow Jesse... that was thorough. Thank you! I will play around with all of that and see where it takes me.

            Nate.

            Comment

            Latest Posts

            Collapse

            Topics Statistics Last Post
            Started by neilzep, Today, 08:55 PM
            0 responses
            5 views
            0 likes
            Last Post neilzep
            by neilzep
             
            Started by javier.filgueira, Today, 03:29 PM
            3 responses
            10 views
            0 likes
            Last Post javier.filgueira  
            Started by Da vinci, Today, 03:15 PM
            1 response
            7 views
            0 likes
            Last Post NinjaTrader_ChrisL  
            Started by Da vinci, Today, 02:51 PM
            1 response
            14 views
            0 likes
            Last Post NinjaTrader_ChrisL  
            Started by emini.ninja, Today, 02:50 PM
            2 responses
            16 views
            0 likes
            Last Post emini.ninja  
            Working...
            X