Announcement

Collapse
No announcement yet.

Partner 728x90

Collapse

show daily ATR in existing ATR indicator panel 1

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

    show daily ATR in existing ATR indicator panel 1

    Hi all,

    for example, I have the chart MES 03-21 opened and 15min time interval. I have an ATR indicator in panel 1, right under my chart window. This indicator uses the same data series as my current time interval selected for this chart (15min). But I want that ATR indicator in panel 1 to show additionally the ATR related to daily data. I am aware that this will be a straight horizontal line, that is no problem for me. Or maybe it would be enough to display the daily ATR as text on the top right corner of that panel 1. How can I achieve this? I tried following: pressing CTRL+F for accessing the data series menu. Then I add another data series by entering the same instrument name MES 03-21 and change the time interval for this secondary data series to 1day. But this generates a new panel and I see the bar chart in it. I don't want to see a complete daily chart in an extra panel, I just want to have the daily ATR value displayed somehow.

    Any help appreciated. Thank you!
    Patricia

    #2
    Hello patricia70,

    Thanks for your post.

    You can add the daily bar series to the 15-minute chart and "hide" the data series by setting it to "line On close" chart style, then set the color of the line to "Transparent". You would also need to turn off text and markers for that data series and finally set the series to panel 1 to avoid a blank panel. The daily bars will be in panel 1 but will not be visible.

    Next, you would add the ATR and change its input series to the hidden daily bars.

    To see the current value of the ATR, you would need to change its calculate setting to OnPriceChange as otherwise, it will only draw to yesterday.

    Note: Make sure you are added enough Daily bars for the daily ATR to be correctly calculated.

    Here is a generic video of the same process but done the long way for clarity: https://www.youtube.com/watch?v=XRGx...UEYKym&index=3


    To see just a numeric value of the ATR, if you are looking at several instruments, I would suggest using the market analyzer with an indicator column and selecting the ATR set to daily bars.

    If you want to see the daily ATR numerically on the chart, you would need to create an indicator that uses the ATR as an input and adds Daily bars that are fed to the ATR and the indicator would use Draw.TextFixed() to display the value of the ATR in any of the 4 corners of the chart.

    Comment


      #3
      Hi Paul and thanks a bunch for that helpful information. I will stick to the last one you suggested, that means I will try to add a secondary series and draw the result as fixed text into the bottom right corner. Here's my code:

      Code:
      protected override void OnStateChange()
      {
      if (State == State.SetDefaults)
      {
      Description = @"my indicator";
      Name = "ATRtest";
      Calculate = Calculate.OnBarClose;
      IsOverlay = true;
      DisplayInDataBox = true;
      DrawOnPricePanel = true;
      DrawHorizontalGridLines = true;
      DrawVerticalGridLines = true;
      PaintPriceMarkers = true;
      ScaleJustification = NinjaTrader.Gui.Chart.ScaleJustification.Right;
      IsSuspendedWhileInactive = true;
      Period = 14;
      }
      else if (State == State.Configure)
      {
      // Adds daily data series to the indicator
      AddDataSeries(BarsPeriodType.Day, 1);
      }
      else if (State == State.DataLoaded)
      {
      }
      }
      
      protected override void OnBarUpdate()
      {
      // we need at least 14 bars for both data series to continue
      if (CurrentBars[0] < Period || CurrentBars[1] < Period)
      return;
      
      double ATRdaily = ATR(BarsArray[1], Period)[0];
      int highestBarsAgo = HighestBar(High, Bars.BarsSinceNewTradingDay);
      int lowestBarsAgo = LowestBar(Low, Bars.BarsSinceNewTradingDay);
      double todaysRange = High[highestBarsAgo]-Low[lowestBarsAgo];
      Draw.TextFixed(this, "daily ATR value", "daily ATR = " + ATRdaily + "\nrange today = " + todaysRange, TextPosition.BottomRight, ChartControl.Properties.ChartText, ChartControl.Properties.LabelFont, Brushes.Blue, Brushes.Transparent, 0);
      }
      Seems to work but I'm not sure yet, if this is a good approach. Is it really necessary to do the logic in the OnBarUpdate block? Would it make sense to shift this logic to OnStateChange instead or should I leave the code as shown above? Looking forward to any optimization hint.

      Thanks again and kind regards
      Patricia.

      Comment


        #4
        Hello patricia70,

        Thanks for your reply.

        What you have should work.

        The methods for HighestBar/LowestBar might be less efficient than keeping track of the lows and highs directly. The methods, on each call to OnBarUpdate() will basically repeat the lookback somewhat needlessly.

        What you can do is to create a couple of double variables and on each call to OnBarUpdate() check to see if the high or low are greater then the previous values. Something like:

        if (Bars.IsFirstBarOfSession)
        {
        dailyHigh = double.MinValue; // reset values on first bar of new session, to ensure first high will be used.
        dailyLow = double.MaxValue;
        // reset values on first bar of new session, to ensure first low will be used.
        }

        if (High[0] > dailyHigh)
        {
        dailyHigh = High[0]; // save new high
        }
        if (Low[0] < dailyLow)
        {
        dailyLow = Low[0]; // save new low
        }


        double todaysRange = dailyHigh - dailyLow; // (You can add /TickSize if you want this in ticks (after first subtracting the high-low))

        Note: dailyHigh and dailyLow would be double type variables created at the class level.

        This simple code works because the script runs the bars in sequence from the beginning of the data series to the current bar.

        Comment


          #5
          Thanks a bunch Paul, really appreciate your help. Finally this is the resulting code:

          Code:
          public class myIndicator : Indicator
          {
          private Text mytexttool;
          private Brush axisColor;
          private Gui.Tools.SimpleFont chartFont;
          double dailyHigh;
          double dailyLow;
          
          protected override void OnStateChange()
          {
          if (State == State.SetDefaults)
          {
          Description = @"my indicator";
          Name = "myIndicator";
          Calculate = Calculate.OnPriceChange;
          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;
          Period = 14;
          }
          else if (State == State.Configure)
          {
          // Adds daily data series to the indicator
          AddDataSeries(BarsPeriodType.Day, 1);
          }
          else if (State == State.DataLoaded)
          {
          if (ChartControl != null)
          {
          chartFont = ChartControl.Properties.LabelFont;
          axisColor = ChartControl.Properties.AxisPen.Brush;
          }
          }
          }
          
          protected override void OnBarUpdate()
          {
          // we need at least 14 bars for both data series to continue
          if (CurrentBars[0] < Period || CurrentBars[1] < Period)
          return;
          
          if (Bars.IsFirstBarOfSession)
          {
          dailyHigh = double.MinValue; // reset values on first bar of new session, to ensure first high will be used.
          dailyLow = double.MaxValue; // reset values on first bar of new session, to ensure first low will be used.
          }
          
          if (High[0] > dailyHigh)
          {
          dailyHigh = High[0]; // save new high
          }
          if (Low[0] < dailyLow)
          {
          dailyLow = Low[0]; // save new low
          }
          
          double todaysRange = dailyHigh - dailyLow;
          double dATR = ATR(BarsArray[1], Period)[0];
          
          Draw.TextFixed (this, "line1-desc", "dailyATR:\t\t", TextPosition.TopRight, axisColor, chartFont, Brushes.Transparent, Brushes.Transparent, 0);
          Draw.TextFixed (this, "line1-val",""+Bars.Instrument.MasterInstrument.FormatPrice(dATR, false) , TextPosition.TopRight, Brushes.Gold, chartFont , Brushes.Transparent, Brushes.Transparent,0 );
          Draw.TextFixed (this, "line2-desc", "\nintraday range:\t\t", TextPosition.TopRight, axisColor, chartFont, Brushes.Transparent, Brushes.Transparent, 0);
          Draw.TextFixed (this, "line2-val","\n"+todaysRange , TextPosition.TopRight, Brushes.CornflowerBlue, chartFont , Brushes.Transparent, Brushes.Transparent,0 );
          I hope this is ok. The only part I'm not really sure about is the line where I calculate the double "dATR". I think it would be enough that this calculation is done only once because it is referenced to the daily data series and the value won't change through the day. Is there a better place to place this line? I tried some few other blocks without success. If you say the code like that is ok, I'll keep it.

          Cheers!
          Patricia

          Comment


            #6
            Hello Patricia,

            Thanks for your reply.

            You could move the ATR check to the first bar of the session if you wish.


            Comment


              #7
              Originally posted by NinjaTrader_PaulH View Post
              You could move the ATR check to the first bar of the session if you wish.
              I already tried that before but without success. It is throwing the error CS0103 (dATR does not exist in current context). I searched the help files and found the corresponding explanation for that error however I do not understand how to fix this error. In my understanding the variable dATR is declared correctly. Here's the code:
              Code:
              protected override void OnBarUpdate()
              {
              // we need at least 14 bars for both data series to continue
              if (CurrentBars[0] < Period || CurrentBars[1] < Period)
              return;
              
              if (Bars.IsFirstBarOfSession)
              {
              dailyHigh = double.MinValue; // reset values on first bar of new session, to ensure first high will be used.
              dailyLow = double.MaxValue; // reset values on first bar of new session, to ensure first low will be used.
              double dATR = ATR(BarsArray[1], Period)[0];
              }
              
              if (High[0] > dailyHigh)
              {
              dailyHigh = High[0]; // save new high
              }
              if (Low[0] < dailyLow)
              {
              dailyLow = Low[0]; // save new low
              }
              
              double todaysRange = dailyHigh - dailyLow;
              // double dATR = ATR(BarsArray[1], Period)[0];
              
              Draw.TextFixed (this, "line1-desc", "dailyATR:\t\t", TextPosition.TopRight, axisColor, chartFont, Brushes.Transparent, Brushes.Transparent, 0);
              Draw.TextFixed (this, "line1-val",""+Bars.Instrument.MasterInstrument.FormatPr i ce(dATR, false) , TextPosition.TopRight, Brushes.Gold, chartFont , Brushes.Transparent, Brushes.Transparent,0 );
              Draw.TextFixed (this, "line2-desc", "\nintraday range:\t\t", TextPosition.TopRight, axisColor, chartFont, Brushes.Transparent, Brushes.Transparent, 0);
              I think I understand that dATR is unknown to the Draw.TextFixed command because it is only used on the first bar of a session and in all other bars it is simply not existing. That's why I suspect the Draw.TextFixed line failing. But how do I solve this problem? Should I just cut all the Draw.TextFixed lines from the lower section and paste them into FirstBarOfSession section, and only keep the range calculation on the bottom part, like that?

              Code:
              if (Bars.IsFirstBarOfSession)
              {
              dailyHigh = double.MinValue; // reset values on first bar of new session, to ensure first high will be used.
              dailyLow = double.MaxValue; // reset values on first bar of new session, to ensure first low will be used.
              double dATR = ATR(BarsArray[1], Period)[0];
              Draw.TextFixed (this, "line1-desc", "dailyATR:\t\t", TextPosition.TopRight, axisColor, chartFont, Brushes.Transparent, Brushes.Transparent, 0);
              Draw.TextFixed (this, "line1-val",""+Bars.Instrument.MasterInstrument.FormatPr i ce(dATR, false) , TextPosition.TopRight, Brushes.Gold, chartFont , Brushes.Transparent,
              }
              
              if (High[0] > dailyHigh)
              {
              dailyHigh = High[0]; // save new high
              }
              if (Low[0] < dailyLow)
              {
              dailyLow = Low[0]; // save new low
              }
              
              double todaysRange = dailyHigh - dailyLow;
              
              Draw.TextFixed (this, "line2-val","\n"+todaysRange , TextPosition.TopRight, Brushes.CornflowerBlue, chartFont , Brushes.Transparent, Brushes.Transparent,0 );
              Is that a good solution?
              Last edited by patricia70; 12-30-2020, 09:35 AM.

              Comment


                #8
                Hello patricia70,

                Thanks for your reply.

                When you declare your variables within a set of { } then you have created a "local" variable and using the variable outside of the { } will result in that current context error as the { } are the boundaries of the context.

                A better solution would be to declare your variables at the class level, IE: private double todaysRange; When created at the class level they can be used throughout your script.

                To clarify, here is an example of class level variables, created between the class name and OnStateChange:

                public class NinjaPriceAction : Indicator
                {
                private int barsback;
                private double prevhigh;
                private double prevlow;
                private double curhigh;
                private double curlow;
                private double offset;
                private double curATR;
                private double toffset;
                private ATR myATR;
                private Swing mySwing;
                private double tOffset;
                private int myBarUp, myBarDown;

                protected override void OnStateChange()

                Comment


                  #9
                  for convenience, you would therefore create your variables all on a class-by-class basis as you have shown. However, in many indicators and strategies I have seen so far, this is not the case. I see class-related declarations over and over again, but also many that appear below in the code in the most diverse sections.

                  So what criteria do you use to decide? How am I supposed to know if it's better to declare the variable at the top class-wise or rather in a single { } section?

                  Can you maybe say something about my posted code, if this would be ok or if there is something against it? At least it works already. I just don't know if I'm missing something important and it wouldn't be as recommendable as I implemented it.

                  Thanks a lot!

                  Comment


                    #10
                    Hello patricia70,

                    Thanks for your reply.

                    "So what criteria do you use to decide? How am I supposed to know if it's better to declare the variable at the top class-wise or rather in a single { } section?" Your questions would probably be best answered by reviewing a C# tutorial as this would not be a ninjascript question. In general, you would declare the variable in the context of the use.

                    If your posted code provides the results you need then that is fine.


                    Comment

                    Latest Posts

                    Collapse

                    Topics Statistics Last Post
                    Started by Geovanny Suaza, 02-11-2026, 06:32 PM
                    0 responses
                    576 views
                    0 likes
                    Last Post Geovanny Suaza  
                    Started by Geovanny Suaza, 02-11-2026, 05:51 PM
                    0 responses
                    334 views
                    1 like
                    Last Post Geovanny Suaza  
                    Started by Mindset, 02-09-2026, 11:44 AM
                    0 responses
                    101 views
                    0 likes
                    Last Post Mindset
                    by Mindset
                     
                    Started by Geovanny Suaza, 02-02-2026, 12:30 PM
                    0 responses
                    553 views
                    1 like
                    Last Post Geovanny Suaza  
                    Started by RFrosty, 01-28-2026, 06:49 PM
                    0 responses
                    551 views
                    1 like
                    Last Post RFrosty
                    by RFrosty
                     
                    Working...
                    X