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

Passing Indicator Variable to Strategy

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

    Passing Indicator Variable to Strategy

    This is just a copy & paste of Regression Channel indicator, with a few lines of code to calculate the channel line slope as a string (either Up or Down), and want to pass that to a strategy.

    But when I call it from the strategy with the following code, the output is blank/empty:
    Code:
            string mySlope = zSTD(128,1).mySlopeX;
            Print("mySlope= " + mySlope);​

    Here is the updated indicator code:
    Code:
    //
    // Copyright (C) 2023, NinjaTrader LLC <www.ninjatrader.com>.
    // NinjaTrader reserves the right to modify or overwrite this NinjaScript component with each release.
    //
    #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.Data;
    using NinjaTrader.NinjaScript;
    using NinjaTrader.Core.FloatingPoint;
    using NinjaTrader.NinjaScript.DrawingTools;
    using SharpDX;
    using SharpDX.Direct2D1;
    
    #endregion
    
    //This namespace holds indicators in this folder and is required. Do not change it.
    namespace NinjaTrader.NinjaScript.Indicators
    {
        /// <summary>
        /// Linear regression is used to calculate a best fit line for the price data. In addition an upper and lower band is added by calculating the standard deviation of prices from the regression line.
        /// </summary>
        public class zSTD : Indicator
        {
            private Series<double> interceptSeries;
            private Series<double> slopeSeries;
            private Series<double> stdDeviationSeries;
    
            protected override void OnStateChange()
            {
                if (State == State.SetDefaults)
                {
                    Description                    = "zSTD";
                    Name                        = "zSTD";
                    IsAutoScale                    = false;
                    IsOverlay                    = true;
                    IsSuspendedWhileInactive    = true;
                    Period                        = 35;
                    Width                        = 2;
    
                    AddPlot(Brushes.DarkGray, NinjaTrader.Custom.Resource.NinjaScriptIndicatorMiddle);
                    AddPlot(Brushes.Magenta, NinjaTrader.Custom.Resource.NinjaScriptIndicatorUpper);
                    AddPlot(Brushes.Magenta, NinjaTrader.Custom.Resource.NinjaScriptIndicatorLower);
                }
                else if (State == State.DataLoaded)
                {
                    interceptSeries        = new Series<double>(this);
                    slopeSeries            = new Series<double>(this);
                    stdDeviationSeries    = new Series<double>(this);
                }
            }
    
            private string mySlope; // wanting to expose & pass this variable to strategy
    
            protected override void OnBarUpdate()
            {
                // First we calculate the linear regression parameters
    
                double sumX = (double) Period*(Period - 1)*.5;
                double divisor = sumX*sumX - (double) Period*Period*(Period - 1)*(2*Period - 1)/6;
                double sumXY = 0;
                double sumY = 0;
                int barCount = Math.Min(Period, CurrentBar);
    
                for (int count = 0; count < barCount; count++)
                {
                    sumXY += count*Input[count];
                    sumY += Input[count];
                }
    
                if (divisor.ApproxCompare(0) == 0 && Period == 0) return;
    
                double slope = (Period*sumXY - sumX*sumY)/divisor;
                double intercept = (sumY - slope*sumX)/Period;
    
                slopeSeries[0] = slope;
                interceptSeries[0] = intercept;
    
                // Next we calculate the standard deviation of the residuals (vertical distances to the regression line).
    
                double sumResiduals = 0;
    
                for (int count = 0; count < barCount; count++)
                {
                    double regressionValue = intercept + slope * (Period - 1 - count);
                    double residual = Math.Abs(Input[count] - regressionValue);
                    sumResiduals += residual;
                }
    
                double avgResiduals = sumResiduals / Math.Min(CurrentBar - 1, Period);
    
                sumResiduals = 0;
                for (int count = 0; count < barCount; count++)
                {
                    double regressionValue = intercept + slope * (Period - 1 - count);
                    double residual = Math.Abs(Input[count] - regressionValue);
                    sumResiduals += (residual - avgResiduals) * (residual - avgResiduals);
                }
    
                double stdDeviation = Math.Sqrt(sumResiduals / Math.Min(CurrentBar + 1, Period));
                stdDeviationSeries[0] = stdDeviation;
    
                double middle = intercept + slope * (Period - 1);
                Middle[0] = CurrentBar == 0 ? Input[0] : middle;
                Upper[0] = stdDeviation.ApproxCompare(0) == 0 || Double.IsInfinity(stdDeviation) ? Input[0] : middle + stdDeviation * Width;
                Lower[0] = stdDeviation.ApproxCompare(0) == 0 || Double.IsInfinity(stdDeviation) ? Input[0] : middle - stdDeviation * Width;
            }
    
            #region Properties
    
            [Browsable(false)]
            [XmlIgnore()]
            public Series<double> Lower
            {
                get { return Values[2]; }
            }
    
            [Browsable(false)]
            [XmlIgnore()]
            public Series<double> Middle
            {
                get { return Values[0]; }
            }
    
            [Range(2, int.MaxValue), NinjaScriptProperty]
            [Display(ResourceType = typeof(Custom.Resource), Name = "Period", GroupName = "NinjaScriptGeneral", Order = 0)]
            public int Period
            { get; set; }
    
            [Browsable(false)]
            [XmlIgnore()]
            public Series<double> Upper
            {
                get { return Values[1]; }
            }
    
            [Range(1, double.MaxValue), NinjaScriptProperty]
            [Display(ResourceType = typeof(Custom.Resource), Name = "Width", GroupName = "NinjaScriptGeneral", Order = 1)]
            public double Width
            { get; set; }
            
            // attempting to enable passing of indicator variable to strategy
            [Browsable(false)]
            [XmlIgnore()]
            public string mySlopeX {
                get {
                    Update(); // ensures exposed variable is up to date
                    return mySlope; // the desired variable to be exposed
                    }
                }
    
            #endregion
    
    
            #region Misc
            private int GetXPos(int barsBack)
            {
                return ChartControl.GetXByBarIndex(ChartBars,
                    Math.Max(0, Bars.Count - 1 - barsBack - (Calculate == Calculate.OnBarClose ? 1 : 0)));
            }
    
            private int GetYPos(double price, ChartScale chartScale)
            {
                return chartScale.GetYByValue(price);
            }
    
            protected override void OnRender(ChartControl chartControl, ChartScale chartScale)
            {
                if (Bars == null || ChartControl == null) return;
    
                RenderTarget.AntialiasMode = AntialiasMode.PerPrimitive;
    
                ChartPanel panel = chartControl.ChartPanels[ChartPanel.PanelIndex];
    
                int idx = BarsArray[0].Count - 1 - (Calculate == Calculate.OnBarClose ? 1 : 0);
                double intercept = interceptSeries.GetValueAt(idx);
                double slope = slopeSeries.GetValueAt(idx);
                double stdDev = stdDeviationSeries.GetValueAt(idx);
                int stdDevPixels = (int) Math.Round(((stdDev*Width)/(chartScale.MaxValue - chartScale.MinValue))*panel.H, 0);
                int xPos = GetXPos(Period - 1 - Displacement);
                int yPos = GetYPos(intercept, chartScale);
                int xPos2 = GetXPos(0 - Displacement);
                int yPos2 = GetYPos(intercept + slope*(Period - 1), chartScale);
                Vector2 startVector = new Vector2(xPos, yPos);
                Vector2 endVector = new Vector2(xPos2, yPos2);
    
                // Middle
                RenderTarget.DrawLine(startVector, endVector, Plots[0].BrushDX, Plots[0].Width, Plots[0].StrokeStyle);
                    if ( startVector.Y - endVector.Y > 0 ) { mySlope = "Up"; }
                    if ( startVector.Y - endVector.Y < 0 ) { mySlope = "Down"; }
                    Draw.TextFixed( this, "myText", mySlope, TextPosition.TopRight ); // works as expected
    
                // Upper
                RenderTarget.DrawLine(new Vector2(startVector.X, startVector.Y - stdDevPixels), new Vector2(endVector.X, endVector.Y - stdDevPixels), Plots[1].BrushDX, Plots[1].Width, Plots[1].StrokeStyle);
    
                // Lower
                RenderTarget.DrawLine(new Vector2(startVector.X, startVector.Y + stdDevPixels), new Vector2(endVector.X, endVector.Y + stdDevPixels), Plots[2].BrushDX, Plots[2].Width, Plots[2].StrokeStyle);
    
                RenderTarget.AntialiasMode = AntialiasMode.Aliased;
            }
            #endregion
        }
    }
    
    #region NinjaScript generated code. Neither change nor remove.
    
    namespace NinjaTrader.NinjaScript.Indicators
    {
        public partial class Indicator : NinjaTrader.Gui.NinjaScript.IndicatorRenderBase
        {
            private zSTD[] cachezSTD;
            public zSTD zSTD(int period, double width)
            {
                return zSTD(Input, period, width);
            }
    
            public zSTD zSTD(ISeries<double> input, int period, double width)
            {
                if (cachezSTD != null)
                    for (int idx = 0; idx < cachezSTD.Length; idx++)
                        if (cachezSTD[idx] != null && cachezSTD[idx].Period == period && cachezSTD[idx].Width == width && cachezSTD[idx].EqualsInput(input))
                            return cachezSTD[idx];
                return CacheIndicator<zSTD>(new zSTD(){ Period = period, Width = width }, input, ref cachezSTD);
            }
        }
    }
    
    namespace NinjaTrader.NinjaScript.MarketAnalyzerColumns
    {
        public partial class MarketAnalyzerColumn : MarketAnalyzerColumnBase
        {
            public Indicators.zSTD zSTD(int period, double width)
            {
                return indicator.zSTD(Input, period, width);
            }
    
            public Indicators.zSTD zSTD(ISeries<double> input , int period, double width)
            {
                return indicator.zSTD(input, period, width);
            }
        }
    }
    
    namespace NinjaTrader.NinjaScript.Strategies
    {
        public partial class Strategy : NinjaTrader.Gui.NinjaScript.StrategyRenderBase
        {
            public Indicators.zSTD zSTD(int period, double width)
            {
                return indicator.zSTD(Input, period, width);
            }
    
            public Indicators.zSTD zSTD(ISeries<double> input , int period, double width)
            {
                return indicator.zSTD(input, period, width);
            }
        }
    }
    
    #endregion
    
    ​

    #2
    Did you call AddChartIndicator?
    (I suspect not)

    You've chosen to assign your private mySlope string
    inside OnRender (why there?) so your strategy code
    requires that this indicator be added to the chart, so
    that ChartControl is not null.

    Hint:
    Calling Update() does nothing to ensure that mySlope
    is properly updated because mySlope is being set
    inside OnRender, not OnBarUpdate.

    Comment


      #3
      Hello squarewave,

      You need to set a value to mySlopeX from OnBarUpdate. The property uses the variable mySlope but that string is not being set anywhere inside OnBarUpdate. The string needs to be set to a value inside OnBarUpdate to expose that value to a strategy.
      JesseNinjaTrader Customer Service

      Comment


        #4
        Originally posted by bltdavid View Post
        Did you call AddChartIndicator?
        (I suspect not)
        Thank you, that fixed it for me!

        It's kinda crazy to me, all of this extra work just to get the slope of the regression "lines" and not the plots...

        Originally posted by bltdavid View Post
        You've chosen to assign your private mySlope string
        inside OnRender (why there?) so your strategy code
        requires that this indicator be added to the chart, so
        that ChartControl is not null.
        Thank you for providing this explanation, I didn't really have any specific reasoning for placing it there & didn't test otherwise.

        Originally posted by bltdavid View Post
        Hint:
        Calling Update() does nothing to ensure that mySlope
        is properly updated because mySlope is being set
        inside OnRender, not OnBarUpdate.
        Ahh, thanks for that explanation & clarification as well, makes sense!

        Comment

        Latest Posts

        Collapse

        Topics Statistics Last Post
        Started by Haiasi, 04-25-2024, 06:53 PM
        2 responses
        17 views
        0 likes
        Last Post Massinisa  
        Started by Creamers, Today, 05:32 AM
        0 responses
        5 views
        0 likes
        Last Post Creamers  
        Started by Segwin, 05-07-2018, 02:15 PM
        12 responses
        1,786 views
        0 likes
        Last Post Leafcutter  
        Started by poplagelu, Today, 05:00 AM
        0 responses
        3 views
        0 likes
        Last Post poplagelu  
        Started by fx.practic, 10-15-2013, 12:53 AM
        5 responses
        5,407 views
        0 likes
        Last Post Bidder
        by Bidder
         
        Working...
        X