Announcement

Collapse
No announcement yet.

Partner 728x90

Collapse

Indicator Accessing Multiple Time Frame

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

    Indicator Accessing Multiple Time Frame

    Hi,

    I am trying to develop an indicator that uses multiple time frames. In the following code - the attempt is to have access to both the "active" time frame indicator in the chart or Market Analyzer and the higher TF indicator - Monthly in this case. Going baby steps - step 1 - replicate and plot the monthly Keltner Channel type indicator on a daily chart. The following code plots a Higher TF keltner channel on the chart - however, it is wrong - checked by plotting on a monthly chart using the regular indicator and the values are off quite a bit - so doesn't look like rounding error. Can someone point our the error and guide to the correct code. I am a total novice - so not sure where i could be wrong. Looking for code on how to correctly code HTF indicator and access the higher TF OHLC.

    Code:
    namespace NinjaTrader.NinjaScript.Indicators
    {
    	/// <summary>
    	///  
    	/// </summary>
    	public class AKShortSetUp : Indicator
    	{
    		private Series<double>		diff;
    		private Series<double>		htfClose;
    		private Series<double>		localHigh;
    		private	EMA					emaDiff;
    		private	EMA					emaTypical;
    
    		protected override void OnStateChange()
    		{
    			if (State == State.SetDefaults)
    			{
    				Description					= NinjaTrader.Custom.Resource.NinjaScriptIndicatorDescriptionKeltnerChannel;
    				Name						= "AKShortSetUp";
    				Period						= 20;
    				IsOverlay					= true;
    				IsSuspendedWhileInactive	= true;
    				OffsetMultiplier			= 0.5;
    
    				AddPlot(Brushes.DarkGray,		NinjaTrader.Custom.Resource.KeltnerChannelMidline);
    				AddPlot(Brushes.DodgerBlue,		NinjaTrader.Custom.Resource.NinjaScriptIndicatorUpper);
    				AddPlot(Brushes.DodgerBlue,		NinjaTrader.Custom.Resource.NinjaScriptIndicatorLower);
    			}
    			else if (State == State.Configure)
    			{
    				// Add a One Month Bars object to the strategy
    				AddDataSeries(Data.BarsPeriodType.Month, 1);	
    			}
    			else if (State == State.DataLoaded)
    			{
    				diff				= new Series<double>(this);
    				htfClose 			= new Series<double>(this);
    				localHigh			= new Series<double>(this);
    				emaDiff				= EMA(diff, Period);
    				emaTypical			= EMA(htfClose, Period);
    			}
    		}
    		
    
    
    		protected override void OnBarUpdate()
    		{
    			
    			if (BarsInProgress != 0)
    			{
        			return;
    			}	
    			
    			foreach(int CurrentBarForSeries in CurrentBars)
      			{
        			if (CurrentBarForSeries < 1)
        			{
          				return;
        			}
      			}
    			
    			diff[0]			= Highs[1][0] - Lows[1][0];
    			htfClose[0]		= Closes[1][0];
    
    			double middle	= emaTypical[0];
    			double offset	= emaDiff[0] * OffsetMultiplier;
    
    			double upper	= middle + offset;
    			double lower	= middle - offset;
    
    					
    			Midline[0]		= middle;
    			Upper[0]		= upper;
    			Lower[0]		= lower;
    		}
    
    		#region Properties
    		[Browsable(false)]
    		[XmlIgnore()]
    		public Series<double> Lower
    		{
    			get { return Values[2]; }
    		}
    
    		[Browsable(false)]
    		[XmlIgnore()]
    		public Series<double> Midline
    		{
    			get { return Values[0]; }
    		}
    
    		[Range(0.01, int.MaxValue), NinjaScriptProperty]
    		[Display(ResourceType = typeof(Custom.Resource), Name = "OffsetMultiplier", GroupName = "NinjaScriptParameters", Order = 0)]
    		public double OffsetMultiplier
    		{ get; set; }
    
    		[Range(1, int.MaxValue), NinjaScriptProperty]
    		[Display(ResourceType = typeof(Custom.Resource), Name = "Period", GroupName = "NinjaScriptParameters", Order = 1)]
    		public int Period
    		{ get; set; }
    
    		[Browsable(false)]
    		[XmlIgnore()]
    		public Series<double> Upper
    		{
    			get { return Values[1]; }
    		}
    		#endregion
    	}
    }

    #2
    Hello akbegin,

    You will need to supply the BarsArray[index of series] as the input series to the indicator.

    Below is a link to an example.
    https://ninjatrader.com/support/foru...ead.php?t=3572
    Chelsea B.NinjaTrader Customer Service

    Comment


      #3
      Thanks - I tweaked my code as below. Not sure if that what i was supposed to do. However, still not working. When on a monthly chart - the indicator gets plotted. however, when I change the timeframe to daily chart. I expected the indicator to still plot but i only see n/a values under midline, upper and lower.

      Code:
      public class AKShortSetUp : Indicator
      	{
      		private Series<double>		diff;
      		private Series<double>		htfClose;
      		private Series<double>		localHigh;
      		private	EMA					emaDiff;
      		private	EMA					emaTypical;
      
      		protected override void OnStateChange()
      		{
      			if (State == State.SetDefaults)
      			{
      				Description					= NinjaTrader.Custom.Resource.NinjaScriptIndicatorDescriptionKeltnerChannel;
      				Name						= "AKShortSetUp";
      				Period						= 20;
      				IsOverlay					= true;
      				IsSuspendedWhileInactive	= true;
      				OffsetMultiplier			= 0.5;
      
      				AddPlot(Brushes.DarkGray,		NinjaTrader.Custom.Resource.KeltnerChannelMidline);
      				AddPlot(Brushes.DodgerBlue,		NinjaTrader.Custom.Resource.NinjaScriptIndicatorUpper);
      				AddPlot(Brushes.DodgerBlue,		NinjaTrader.Custom.Resource.NinjaScriptIndicatorLower);
      			}
      			else if (State == State.Configure)
      			{
      				// Add a One Month Bars object to the strategy
      				AddDataSeries(Data.BarsPeriodType.Month, 1);	
      			}
      			else if (State == State.DataLoaded)
      			{
      				diff				= new Series<double>(SMA(BarsArray[1], 50));//(this);
      				htfClose 			= new Series<double>(SMA(BarsArray[1], 50));//;
      				localHigh			= new Series<double>(this);
      				emaDiff				= EMA(diff, Period);
      				emaTypical			= EMA(htfClose, Period);
      			}
      		}
      		
      
      
      		protected override void OnBarUpdate()
      		{
      			
      			/*if (BarsInProgress != 0)
      			{
          			return;
      			}*/	
      			
      			foreach(int CurrentBarForSeries in CurrentBars)
        			{
          			if (CurrentBarForSeries < 1)
          			{
            				return;
          			}
        			}
      			
      			
      			if (BarsInProgress == 0)
      			{
      				// Set DataSeries object to store the trading range of the primary bar
      				//primarySeries[0] = Close[0] - Open[0];
      				return;
      			}
      			else if (BarsInProgress == 1) 	// Executed on secondary bar updates only
      			{
      				// Set the DataSeries object to store the trading range of the secondary bar
      				//secondarySeries[0] = Close[0] - Open[0];
      				diff[0]			= High[0] - Low[0];
      				htfClose[0]		= Close[0];
      
      				double middle	= emaTypical[0];
      				double offset	= emaDiff[0] * OffsetMultiplier;
      
      				double upper	= middle + offset;
      				double lower	= middle - offset;
      
      						
      				Midline[0]		= middle;
      				Upper[0]		= upper;
      				Lower[0]		= lower;
      			}
      			
      			
      		}

      Comment


        #4
        Hello akbegin,

        I'm not quite certain what this code is meant to do.

        You have:
        diff = new Series<double>(SMA(BarsArray[1], 50));

        This calls BarsArray[1] and gives this to the SMA as an input series. This is then saved to the diff.

        The diff is then fed to an EMA:

        emaDiff = EMA(diff, Period);

        Do you have chart where you have a month series for the input of an SMA that is being used for the input of an EMA that you are comparing with?



        If you are trying to save an indicator to a variable this would be done like:

        In the scope of the class
        private SMA mySMA;

        In OnStateChange:
        else if (State == State.Configure)
        {
        AddDataSeries(Data.BarsPeriodType.Month, 1);
        }
        else if (State == State.DataLoaded)
        {
        mySMA = SMA(BarsArray[1], 50);
        }

        In OnBarUpdate:
        Print(mySMA[0]);
        Chelsea B.NinjaTrader Customer Service

        Comment


          #5
          what i am looking to achieve is -
          1. To have access (and plot) two keltner channels - one for the active timeframe on the chart and the other for the higher time frame.
          Step 2 - (haven't got close to this step) set up some alert conditions based on a combination of values from both time frame keltner channel values and the current OHLC of the instruments.

          Setting up the SMA to diff - I was following the example from samplesync seconddary series. to sync the two timeframe series.

          as i said before my ultimate aim is to manipulate the keltner channel indicator so that in addition to the local midline, upper and lower. I also have access to the HTF midline, upper and lower.

          Comment


            #6
            Hello akbegin,

            The example is showing that BarsArray[1] can be supplied as an input series.

            You would necessarily have to supply this to the SMA unless this is what you are actually wanting.

            Are you wanting an EMA of an SMA of BarsArray[1]?

            What are you comparing the values of emaDiff to that lets you know the values are incorrect in the script?
            Chelsea B.NinjaTrader Customer Service

            Comment


              #7
              Sorry - lets start over. here is what i am trying to do.

              How would i manipulate the Ketlner Channel indicator as provided by NinjaTrader (reproduced below) so that it plots both the local TF indicator and a higher TF indicator. And make available for the midline, upper and lower of both timeframes accessible in the code.

              Code:
              namespace NinjaTrader.NinjaScript.Indicators
              {
              	/// <summary>
              	/// Keltner Channel. The Keltner Channel is a similar indicator to Bollinger Bands.
              	/// Here the midline is a standard moving average with the upper and lower bands offset
              	/// by the SMA of the difference between the high and low of the previous bars.
              	/// The offset multiplier as well as the SMA period is configurable.
              	/// </summary>
              	public class KeltnerChannel : Indicator
              	{
              		private Series<double>		diff;
              		private	SMA					smaDiff;
              		private	SMA					smaTypical;
              
              		protected override void OnStateChange()
              		{
              			if (State == State.SetDefaults)
              			{
              				Description					= NinjaTrader.Custom.Resource.NinjaScriptIndicatorDescriptionKeltnerChannel;
              				Name						= NinjaTrader.Custom.Resource.NinjaScriptIndicatorNameKelterChannel;
              				Period						= 10;
              				IsOverlay					= true;
              				IsSuspendedWhileInactive	= true;
              				OffsetMultiplier			= 1.5;
              
              				AddPlot(Brushes.DarkGray,		NinjaTrader.Custom.Resource.KeltnerChannelMidline);
              				AddPlot(Brushes.DodgerBlue,		NinjaTrader.Custom.Resource.NinjaScriptIndicatorUpper);
              				AddPlot(Brushes.DodgerBlue,		NinjaTrader.Custom.Resource.NinjaScriptIndicatorLower);
              			}
              			else if (State == State.DataLoaded)
              			{
              				diff				= new Series<double>(this);
              				smaDiff				= SMA(diff, Period);
              				smaTypical			= SMA(Typical, Period);
              			}
              		}
              
              		protected override void OnBarUpdate()
              		{
              			diff[0]			= High[0] - Low[0];
              
              			double middle	= smaTypical[0];
              			double offset	= smaDiff[0] * OffsetMultiplier;
              
              			double upper	= middle + offset;
              			double lower	= middle - offset;
              
              			Midline[0]		= middle;
              			Upper[0]		= upper;
              			Lower[0]		= lower;
              		}
              
              		#region Properties
              		[Browsable(false)]
              		[XmlIgnore()]
              		public Series<double> Lower
              		{
              			get { return Values[2]; }
              		}
              
              		[Browsable(false)]
              		[XmlIgnore()]
              		public Series<double> Midline
              		{
              			get { return Values[0]; }
              		}
              
              		[Range(0.01, int.MaxValue), NinjaScriptProperty]
              		[Display(ResourceType = typeof(Custom.Resource), Name = "OffsetMultiplier", GroupName = "NinjaScriptParameters", Order = 0)]
              		public double OffsetMultiplier
              		{ get; set; }
              
              		[Range(1, int.MaxValue), NinjaScriptProperty]
              		[Display(ResourceType = typeof(Custom.Resource), Name = "Period", GroupName = "NinjaScriptParameters", Order = 1)]
              		public int Period
              		{ get; set; }
              
              		[Browsable(false)]
              		[XmlIgnore()]
              		public Series<double> Upper
              		{
              			get { return Values[1]; }
              		}
              		#endregion
              	}
              }

              Comment


                #8
                Hello akbegin,

                Attached is a simple example that demonstrates.

                (Edit Nov 3, 2030: Added HigherTimeFrameIndicatorPlotExample for anyone who doesn't want to plot the diff between the high and low, and instead wants the direct values from another indicator using a higher time frame)
                Attached Files
                Last edited by NinjaTrader_ChelseaB; 11-03-2020, 03:38 PM.
                Chelsea B.NinjaTrader Customer Service

                Comment


                  #9
                  thanks Chelsea - let me take a look and try to tweak it.

                  Comment


                    #10
                    NinjaTrader_ChelseaB May I ask how you would set up an indicator, not a strategy to accept either the standard chart timeframe or a user selected one. This is for an indicator that would then be used by a Strategy Builder input with the value[0] being an Int. I have the Int all set but need the selectiion component.

                    Comment


                      #11
                      Hello JMont1,

                      This would require custom inputs.

                      You could have a bool input to decide if the primary series is used or a hard-coded added series within the logic of OnBarUpdate().

                      Dynamically adding series using an input as a parameter to AddDataSeries() is not supported.

                      "Arguments supplied to AddDataSeries() should be hardcoded and NOT dependent on run-time variables which cannot be reliably obtained during State.Configure (e.g., Instrument, Bars, or user input). Attempting to add a data series dynamically is NOT guaranteed and therefore should be avoided. Trying to load bars dynamically may result in an error similar to: Unable to load bars series. Your NinjaScript may be trying to use an additional data series dynamically in an unsupported manner."
                      https://ninjatrader.com/support/help...dataseries.htm



                      A very complex route would be to use BarsRequests which can load data dynamically and all custom logic to work the data.
                      https://ninjatrader.com/support/foru...518#post742518
                      Chelsea B.NinjaTrader Customer Service

                      Comment

                      Latest Posts

                      Collapse

                      Topics Statistics Last Post
                      Started by smcllr, Today, 04:15 PM
                      1 response
                      8 views
                      0 likes
                      Last Post NinjaTrader_ShawnB  
                      Started by rtwave, Today, 02:33 PM
                      1 response
                      11 views
                      0 likes
                      Last Post NinjaTrader_Kate  
                      Started by mlprice12, Today, 01:43 PM
                      1 response
                      5 views
                      0 likes
                      Last Post NinjaTrader_Jim  
                      Started by coopgrafik, Today, 01:31 PM
                      3 responses
                      12 views
                      0 likes
                      Last Post NinjaTrader_Jesse  
                      Started by ARQERNES, Today, 12:08 PM
                      2 responses
                      16 views
                      0 likes
                      Last Post ARQERNES  
                      Working...
                      X