Announcement

Collapse
No announcement yet.

Partner 728x90

Collapse

Plotting a higher time frame indicator from a strategy

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

    Plotting a higher time frame indicator from a strategy

    Hi,

    I'm attempting to plot an indicator that uses a higher timeframe as an input but running into issues. I can access the data from the indicator but I can't figure out how to plot it on the chart.

    After looking into the issue, I now know that AddChartIndicator() doesn't work with indicators that use a data series that is not the primary data series. In some other forum threads I've seen some references to using AddPlot() within the strategy to display the data from the indicator but, most of the documentation for AddPlot() revolves around using it within an indicator. I've played around with AddPlot() but haven't been able to wrap my head around I should be using it.

    The sample strategy below is being applied to a 1 minute chart and attempting to plot an Aroon indicator using a 15 minute data series. With the sample code below, how would I display the Aroon15Min indicator on the chart? As it is written, AddChartIndicator(Aroon15Min) generates a blank indicator panel that does not plot any of the data.

    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.Indicators;
    using NinjaTrader.NinjaScript.DrawingTools;
    #endregion
    
    //This namespace holds Strategies in this folder and is required. Do not change it.
    namespace NinjaTrader.NinjaScript.Strategies
    {
        public class HigherTimeframeIndicator : Strategy
        {
            private Aroon Aroon15Min;
            
            private Aroon AroonPrimary;
    
            protected override void OnStateChange()
            {
                if (State == State.SetDefaults)
                {
                    Description                                    = @"Enter the description for your new custom Strategy here.";
                    Name                                        = "HigherTimeframeIndicator";
                    Calculate                                    = Calculate.OnBarClose;
                    EntriesPerDirection                            = 1;
                    EntryHandling                                = EntryHandling.AllEntries;
                    IsExitOnSessionCloseStrategy                = true;
                    ExitOnSessionCloseSeconds                    = 30;
                    IsFillLimitOnTouch                            = false;
                    MaximumBarsLookBack                            = MaximumBarsLookBack.TwoHundredFiftySix;
                    OrderFillResolution                            = OrderFillResolution.Standard;
                    Slippage                                    = 0;
                    StartBehavior                                = StartBehavior.WaitUntilFlat;
                    TimeInForce                                    = TimeInForce.Gtc;
                    TraceOrders                                    = false;
                    RealtimeErrorHandling                        = RealtimeErrorHandling.StopCancelClose;
                    StopTargetHandling                            = StopTargetHandling.PerEntryExecution;
                    BarsRequiredToTrade                            = 20;
                    // Disable this property for performance gains in Strategy Analyzer optimizations
                    // See the Help Guide for additional information
                    IsInstantiatedOnEachOptimizationIteration    = true;
                    OverboughtThreshold                    = 70;
                    OversoldThreshold                    = 30;
                }
                else if (State == State.Configure)
                {
                    AddDataSeries(Data.BarsPeriodType.Minute, 15);
                }
                else if (State == State.DataLoaded)
                {    
                    Aroon15Min                    = Aroon(Closes[1], 14);
                    Aroon15Min.Plots[0].Brush     = Brushes.DarkCyan;
                    Aroon15Min.Plots[1].Brush     = Brushes.SlateBlue;
                    AddChartIndicator(Aroon15Min);
                    
                    AroonPrimary                = Aroon(Close, 14);
                    AroonPrimary.Plots[0].Brush = Brushes.DarkCyan;
                    AroonPrimary.Plots[1].Brush = Brushes.SlateBlue;
                    AddChartIndicator(AroonPrimary);
                }
            }
    
            protected override void OnBarUpdate()
            {
                if (BarsInProgress != 0)
                    return;
    
                if (CurrentBars[0] < 1
                || CurrentBars[1] < 0)
                    return;
    
                 // Set 1
                if ((Aroon15Min.Up[0] >= OverboughtThreshold)
                     && (AroonPrimary.Up[0] >= OverboughtThreshold))
                {
                    EnterLong(Convert.ToInt32(DefaultQuantity), @"Long");
                }
                
                 // Set 2
                if ((Position.MarketPosition == MarketPosition.Long)
                     && (Aroon15Min.Up[0] < OverboughtThreshold)
                     && (AroonPrimary.Up[0] < OverboughtThreshold))
                {
                    ExitLong(Convert.ToInt32(DefaultQuantity), @"ExitLong", @"Long");
                }
                
            }
    
            #region Properties
            [NinjaScriptProperty]
            [Range(1, int.MaxValue)]
            [Display(Name="OverboughtThreshold", Order=1, GroupName="Parameters")]
            public int OverboughtThreshold
            { get; set; }
    
            [NinjaScriptProperty]
            [Range(1, int.MaxValue)]
            [Display(Name="OversoldThreshold", Order=2, GroupName="Parameters")]
            public int OversoldThreshold
            { get; set; }
            #endregion
    
        }
    }
    ​

    #2
    Hello,

    Thank you for your post.

    AddChartIndicator cannot be used in this way. The Help Guide page for AddChartIndicator() states this and also notes a workaround. You will need to explicitly reference the added series in the indicator's code.

    "An indicator being added via AddChartIndicator() cannot use any additional data series hosted by the calling strategy, but can only use the strategy's primary data series. If you wish to use a different data series for the indicator's input, you can add the series in the indicator itself and explicitly reference it in the indicator code (please make sure though the hosting strategy has the same AddDataSeries() call included as well)"



    Please let us know if you have any further questions. ​

    Comment


      #3
      Hi Gaby, thanks for the quick response.

      I effectively duplicated and modified a version of the Aroon indicator that explicitly added the 15 minute data series. I also modified the code within the duplicated indicator to use the data from the 15 minute data series. When the modified indicator is used within the strategy and AddChartIndicator is used, it works as expected and plots the data from the modified indicator.

      While this approach works, I'm planning to use a number of different indicators on a variety of higher timeframes across several strategies. Unless I'm missing something, this means I would have to duplicate and modify each indicator I plan to use as well as duplicate it again for each timeframe I plan to reference. So, hypothetically, if I wanted to use this approach on the 15Min, 1Hr, and 4Hr timeframes, I would need to duplicate and modify the Aroon indicator 3 times: an Aroon15Min, Aroon1Hr, and an Aroon4Hr.

      Is there another approach I can use to pull the data from an indicator and manually plot it from a strategy? Even though AddChartIndicator doesn't work with an indicator that uses a non-primary data series, an indicator that uses a non-primary data series still outputs the correct data. Taking the data from the indicator and plotting it from within the strategy seems like a better route to take rather than duplicating a bunch of indicators and potentially introducing bugs by modifying their internal code.

      Thanks.

      Comment


        #4
        Hello linreid,

        Thank you for your post.

        There is no other workaround to plot the indicator from a strategy other than using AddChartIndicator() unfortunately. And since you can't use additional data series, creating a separate script which directly calls the added series is necessary.

        Comment


          #5
          There is in fact another work around. I'm posting this for the benefit of anyone else who is trying to accomplish the same thing.

          This approach uses AddPlot() within the Strategy and updates the values of the plots with the output of the higher time frame indicator. Below is the updated sample strategy I posted above:

          Code:
          namespace NinjaTrader.NinjaScript.Strategies
          
          {
          
          public class HigherTimeframeIndicator : Strategy
          
          {
          
                  private Aroon AroonPrimary;
          
                  private Aroon Aroon15Min;
          
          
          
          
                  protected override void OnStateChange()
          
          {
          
          if (State == State.SetDefaults)
          
          {
          
          Description = @"Enter the description for your new custom Strategy here.";
          
          Name = "HigherTimeframeIndicator";
          
          Calculate = Calculate.OnBarClose;
          
          EntriesPerDirection = 1;
          
          EntryHandling = EntryHandling.AllEntries;
          
          IsExitOnSessionCloseStrategy = true;
          
          ExitOnSessionCloseSeconds = 30;
          
          IsFillLimitOnTouch = false;
          
          MaximumBarsLookBack = MaximumBarsLookBack.TwoHundredFiftySix;
          
          OrderFillResolution = OrderFillResolution.Standard;
          
          Slippage = 0;
          
          StartBehavior = StartBehavior.WaitUntilFlat;
          
          TimeInForce = TimeInForce.Gtc;
          
          TraceOrders = false;
          
          RealtimeErrorHandling = RealtimeErrorHandling.StopCancelClose;
          
          StopTargetHandling = StopTargetHandling.PerEntryExecution;
          
          BarsRequiredToTrade = 20;
          
          // Disable this property for performance gains in Strategy Analyzer optimizations
          
          // See the Help Guide for additional information
          
          IsInstantiatedOnEachOptimizationIteration = true;
          
          OverboughtThreshold = 70;
          
          OversoldThreshold = 30;
          
          
          
          
          // Set IsOverlay to false so Strategy Plots are drawn in a separate panel and not overlayed on price chart
          
          IsOverlay = false;
          
          
          
          
                          // Add Strategy plots
          
                          AddPlot(Brushes.PaleGreen, "Aroon15MinUp");
          
                          AddPlot(Brushes.PaleVioletRed, "Aroon15MinDown");
          
                          AddLine(Brushes.DarkGray, 30, "Aroon15MinLowerBound");
          
                          AddLine(Brushes.DarkGray, 70, "Aroon15MinUpperBound");
          
          
          
          
                      }
          
          else if (State == State.Configure)
          
          {
          
          // Add 15min data series
          
          AddDataSeries(Data.BarsPeriodType.Minute, 15);
          
          }
          
          else if (State == State.DataLoaded)
          
          {
          
          // Instantiate the Aroon indicator using the primary data series and use AddChartIndicator
          
                          AroonPrimary = Aroon(Close, 14);
          
                          AroonPrimary.Plots[0].Brush = Brushes.DarkCyan;
          
                          AroonPrimary.Plots[1].Brush = Brushes.SlateBlue;
          
                          AddChartIndicator(AroonPrimary);
          
          
          
          
                          // Instantiate the Aroon indicator using the 15min data series.
          
          // Don't use AddChartIndicator
          
                          Aroon15Min = Aroon(Closes[1], 14);
          
          }
          
          }
          
          
          
          
          protected override void OnBarUpdate()
          
          {
          
          if (BarsInProgress != 0)
          
          return;
          
          
          
          
          if (CurrentBars[0] < 1
          
          || CurrentBars[1] < 0)
          
          return;
          
          
          
          
                      // Update the values of the Strategy plots using the output of the Aroon 15min indicator
          
                      Aroon15MinUp[0] = Aroon15Min.Up[0];
          
                      Aroon15MinDown[0] = Aroon15Min.Down[0];
          
          
          
          
          
          
          
                      // Set 1
          
                      if ((Aroon15Min.Up[0] >= OverboughtThreshold)
          
          && (AroonPrimary.Up[0] >= OverboughtThreshold))
          
          {
          
          EnterLong(Convert.ToInt32(DefaultQuantity), @"Long");
          
          }
          
          
          
          // Set 2
          
          if ((Position.MarketPosition == MarketPosition.Long)
          
          && (Aroon15Min.Up[0] < OverboughtThreshold)
          
          && (AroonPrimary.Up[0] < OverboughtThreshold))
          
          {
          
          ExitLong(Convert.ToInt32(DefaultQuantity), @"ExitLong", @"Long");
          
          }
          
          
          
          }
          
          
          
          
          // Add public series to the strategy which will be updated with the values from the Aroon 15min indicator
          
                  [Browsable(false)]
          
                  [XmlIgnore]
          
                  public Series<double> Aroon15MinUp
          
                  {
          
                      get { return Values[0]; }
          
                  }
          
          
          
          
                  [Browsable(false)]
          
                  [XmlIgnore]
          
                  public Series<double> Aroon15MinDown
          
                  {
          
                      get { return Values[1]; }
          
                  }
          
          
          
          
                  #region Properties
          
                  [NinjaScriptProperty]
          
          [Range(1, int.MaxValue)]
          
          [Display(Name="OverboughtThreshold", Order=1, GroupName="Parameters")]
          
          public int OverboughtThreshold
          
          { get; set; }
          
          
          
          
          [NinjaScriptProperty]
          
          [Range(1, int.MaxValue)]
          
          [Display(Name="OversoldThreshold", Order=2, GroupName="Parameters")]
          
          public int OversoldThreshold
          
          { get; set; }
          
          #endregion
          
          
          
          
          }
          
          }
          ​

          Comment


            #6
            Great workaround, thanks for sharing.

            Comment

            Latest Posts

            Collapse

            Topics Statistics Last Post
            Started by NullPointStrategies, Today, 05:17 AM
            0 responses
            50 views
            0 likes
            Last Post NullPointStrategies  
            Started by argusthome, 03-08-2026, 10:06 AM
            0 responses
            126 views
            0 likes
            Last Post argusthome  
            Started by NabilKhattabi, 03-06-2026, 11:18 AM
            0 responses
            69 views
            0 likes
            Last Post NabilKhattabi  
            Started by Deep42, 03-06-2026, 12:28 AM
            0 responses
            42 views
            0 likes
            Last Post Deep42
            by Deep42
             
            Started by TheRealMorford, 03-05-2026, 06:15 PM
            0 responses
            46 views
            0 likes
            Last Post TheRealMorford  
            Working...
            X