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

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.
    Note: In NinjaTrader 8 It is no longer needed to use an indicator to sync a secondary series. This can be done directly from the Series&lt;T&gt; (https://ninjatrader.com/support/helpGuides/nt8/NT%20HelpGuide%20English.html?seriest.htm) constructor. This post is left for historical purposes. Series objects are useful for
    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, 04: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.

                      Chelsea B.NinjaTrader Customer Service

                      Comment


                        #12
                        Hi
                        On a daily chart,
                        (a) I am trying to draw a daily moving average (displaced one day ahead) (DailyDotSeries)
                        (b) and then superimpose the weekly moving average (displaced one week ahead) on this daily chart (WeeklyDotSeries)

                        (DWMA = displaced weekly moving average)

                        I have hardcoded the respective daiy and weekly displacements.

                        My WeeklyDotSeries
                        gives me the WeeklyDotSeries close for next Friday
                        (which is correct, as I displace it one week ahead)

                        My problem is,
                        on the daily charts,
                        I want to draw this WeeklyDotSeries for next week,
                        so
                        I have to draw from this point BACKWARDS (FRI, Thur, Wed, Tue, Mon) .
                        but
                        it is drawing this point FORWARD instead (FRI, Mon, Tue, Wed, Thu),

                        I think I am not seeing something in
                        Values[1][0] = Values[1][1]

                        Wondering if you can provide any guidance?
                        What don't I see?

                        Thanks.

                        Apollo11

                        Attached Files

                        Comment


                          #13

                          Comment


                            #14
                            Hello Apollo11,

                            We have received your inquiry over email and have responded there.

                            Please follow up over email if you have additional questions.
                            JimNinjaTrader Customer Service

                            Comment


                              #15
                              Originally posted by NinjaTrader_ChelseaB View Post
                              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)
                              Hello.

                              I downloaded the HigherTimeFrameIndicatorPlotExample and then changed line 50 so that the higher timeframe is the daily, like so:
                              Code:
                              AddDataSeries(BarsPeriodType.Day, 1);
                              But if I pull up a second chart that has daily bars and apply the built-in EMA indicator with the same setting, I get different results

                              Click image for larger version

Name:	Daily EMA vs EMA on multiple timeframe.PNG
Views:	1571
Size:	57.0 KB
ID:	1197124

                              Shouldn't I be getting the same value instead of 14667.75 on one chart and 14671.50 on the other? If so, how do I change line 50 correctly?
                              Attached Files

                              Comment

                              Latest Posts

                              Collapse

                              Topics Statistics Last Post
                              Started by Christopher_R, Today, 12:29 AM
                              0 responses
                              8 views
                              0 likes
                              Last Post Christopher_R  
                              Started by sidlercom80, 10-28-2023, 08:49 AM
                              166 responses
                              2,235 views
                              0 likes
                              Last Post sidlercom80  
                              Started by thread, Yesterday, 11:58 PM
                              0 responses
                              3 views
                              0 likes
                              Last Post thread
                              by thread
                               
                              Started by jclose, Yesterday, 09:37 PM
                              0 responses
                              7 views
                              0 likes
                              Last Post jclose
                              by jclose
                               
                              Started by WeyldFalcon, 08-07-2020, 06:13 AM
                              10 responses
                              1,415 views
                              0 likes
                              Last Post Traderontheroad  
                              Working...
                              X