mikewlange
5/17/2017 - 5:31 PM

Lin Reg Slope w/ Exp Weighting

Lin Reg Slope w/ Exp Weighting


#region Using declarations
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Xml.Serialization;
using NinjaTrader.Cbi;
using NinjaTrader.Data;
using NinjaTrader.Gui.Chart;
#endregion

// This namespace holds all indicators and is required. Do not change it.
namespace NinjaTrader.Indicator
{
    /// <summary>
    /// Linear regression slope - w/ exponential weighting option
    /// </summary>
    [Description("Linear regression slope - w/ exponential weighting option")]
    public class mlLinRegSlope : Indicator
    {
        #region Variables
        // Wizard generated variables
            private int period = 8; // Default setting for Period
            private bool exponential = false; // Default setting for Exponential
			private int returnval = 0; // Default setting for returnval
        // exponential moving regression slope variables
			private int nn = 0;
			private double n, w, sumX, sumX2, sumY1, sumXY1, correction;
		// super fast linear regression slope variables
			private double m1, m2, sumP, sumIP;
		// public results, updated each bar
			public double slope, yvalue, err;
        #endregion

        /// <summary>
        /// This method is used to configure the indicator and is called once before any bar data is loaded.
        /// </summary>
        protected override void Initialize()
        {
            Add(new Plot(Color.FromKnownColor(KnownColor.MediumBlue), PlotStyle.Line, "SlopeSFX"));
            Add(new Line(Color.FromKnownColor(KnownColor.DarkOliveGreen), 0, "Zero"));
            CalculateOnBarClose	= true; 
            Overlay				= false;
            PriceTypeSupported	= true;
        }

        /// <summary>
        /// Called on each bar update event (incoming tick)
        /// </summary>
        protected override void OnBarUpdate()
        {
			double rtn;
			int ix;
			if (exponential) {

                // Super optimised calulations. very fast.
				double denom, sumY = 0.0, sumXY = 0.0;
				if (period != nn || CurrentBar < 1) {
					nn = period;
					n = (nn-1.0)*0.75 + 1.0;
					sumX = 0.5 * n*(n-1.0);
					sumX2 = (n-1.0)*n*(2.0*n-1.0)/6.0;
					sumY = Input[0] * n;
					sumXY = sumX*Input[0];
					w = 2.0 / (n + 1.0);
					correction = (n+1.0) / (3.0*n);
					if (CurrentBar < 1) {
						sumY1 = sumY;
						sumXY1 = sumXY;
					}
				} else {
					sumY = w*Input[0]*n + (1.0-w)*sumY1;
					sumXY = Input[0]*(n-1.0) + sumXY1*(n-2.0)/n;
					sumY1 = sumY;
					sumXY1 = sumXY;
				}
				denom = n*sumX2 - sumX*sumX;
				if (denom < 0.00001) denom = 0.00001;
				slope = correction * n*(n*sumXY - sumX*sumY) / denom;
				yvalue = sumY/n + slope * 0.5*n;
			}
			else {

				int ix1;

				if (CurrentBar < period || nn != period || CurrentBar % 10000 == 0) {
					nn = period;
 					m1 = 6.0 / ((double)period * ((double)period + 1.0));
					m2 = 2.0 / ((double)period - 1.0);
					sumP = 0.0; sumIP = 0.0;

					for (ix = 0; ix < period; ++ix) {
						ix1 = (ix < CurrentBar) ? ix : CurrentBar;
						sumP += Input[ix1];
						sumIP += (ix1 * Input[ix1]);
					}
				} else {

					sumIP += (sumP - period * Input[period]);
					sumP += (Input[0] - Input[period]);
				}
				slope = m1 * (sumP - m2 * sumIP);
				yvalue = sumP/period + slope * period * 0.5;
			}
			switch (returnval) {
				case 3:
					rtn = 0.0;
					if (CurrentBar > 1) {
						for (ix = 0; ix < ((CurrentBar <= period) ? CurrentBar+1 : period); ++ix) {
							rtn = (Input[ix] - (-slope * ix + yvalue));
							err += rtn*rtn;
						}
						rtn = err = Math.Sqrt(err/ix);
					}
					break;
				case 2: rtn = yvalue; break;
				default: rtn = slope; break;
			}
			SlopeSFX.Set(rtn);         // result
        }
        #region Properties
        [Browsable(false)]	// this line prevents the data series from being displayed in the indicator properties dialog, do not remove
        [XmlIgnore()]		// this line ensures that the indicator can be saved/recovered as part of a chart template, do not remove
        public DataSeries SlopeSFX
        {
            get { return Values[0]; }
        }

        [Description("Lookback interval")]
        [Category("Parameters")]
        public int Period
        {
            get { return period; }
            set { period = Math.Max(1, value); }
        }

        [Description("true=exponential moving slope, false=normal weighting")]
        [Category("Parameters")]
        public bool Exponential
        {
            get { return exponential; }
            set { exponential = value; }
        }

		[Description("Return value 1=slope, 2=LinReg value, 3=average error")]
        [Category("Parameters")]
        public int Returnval
        {
            get { return returnval; }
            set { returnval = Math.Max(1, value); }
        }
        #endregion
    }
}

#region NinjaScript generated code. Neither change nor remove.
// This namespace holds all indicators and is required. Do not change it.
namespace NinjaTrader.Indicator
{
    public partial class Indicator : IndicatorBase
    {
        private mlLinRegSlope[] cachemlLinRegSlope = null;

        private static mlLinRegSlope checkmlLinRegSlope = new mlLinRegSlope();

        /// <summary>
        /// Linear regression slope - super fast calc with exponential weighting option
        /// </summary>
        /// <returns></returns>
        public mlLinRegSlope mlLinRegSlope(bool exponential, int period, int returnval)
        {
            return mlLinRegSlope(Input, exponential, period, returnval);
        }

        /// <summary>
        /// Linear regression slope - super fast calc with exponential weighting option
        /// </summary>
        /// <returns></returns>
        public mlLinRegSlope mlLinRegSlope(Data.IDataSeries input, bool exponential, int period, int returnval)
        {
            if (cachemlLinRegSlope != null)
                for (int idx = 0; idx < cachemlLinRegSlope.Length; idx++)
                    if (cachemlLinRegSlope[idx].Exponential == exponential && cachemlLinRegSlope[idx].Period == period && cachemlLinRegSlope[idx].Returnval == returnval && cachemlLinRegSlope[idx].EqualsInput(input))
                        return cachemlLinRegSlope[idx];

            lock (checkmlLinRegSlope)
            {
                checkmlLinRegSlope.Exponential = exponential;
                exponential = checkmlLinRegSlope.Exponential;
                checkmlLinRegSlope.Period = period;
                period = checkmlLinRegSlope.Period;
                checkmlLinRegSlope.Returnval = returnval;
                returnval = checkmlLinRegSlope.Returnval;

                if (cachemlLinRegSlope != null)
                    for (int idx = 0; idx < cachemlLinRegSlope.Length; idx++)
                        if (cachemlLinRegSlope[idx].Exponential == exponential && cachemlLinRegSlope[idx].Period == period && cachemlLinRegSlope[idx].Returnval == returnval && cachemlLinRegSlope[idx].EqualsInput(input))
                            return cachemlLinRegSlope[idx];

                mlLinRegSlope indicator = new mlLinRegSlope();
                indicator.BarsRequired = BarsRequired;
                indicator.CalculateOnBarClose = CalculateOnBarClose;
#if NT7
                indicator.ForceMaximumBarsLookBack256 = ForceMaximumBarsLookBack256;
                indicator.MaximumBarsLookBack = MaximumBarsLookBack;
#endif
                indicator.Input = input;
                indicator.Exponential = exponential;
                indicator.Period = period;
                indicator.Returnval = returnval;
                Indicators.Add(indicator);
                indicator.SetUp();

                mlLinRegSlope[] tmp = new mlLinRegSlope[cachemlLinRegSlope == null ? 1 : cachemlLinRegSlope.Length + 1];
                if (cachemlLinRegSlope != null)
                    cachemlLinRegSlope.CopyTo(tmp, 0);
                tmp[tmp.Length - 1] = indicator;
                cachemlLinRegSlope = tmp;
                return indicator;
            }
        }
    }
}

// This namespace holds all market analyzer column definitions and is required. Do not change it.
namespace NinjaTrader.MarketAnalyzer
{
    public partial class Column : ColumnBase
    {
        /// <summary>
        /// Linear regression slope - super fast calc with exponential weighting option
        /// </summary>
        /// <returns></returns>
        [Gui.Design.WizardCondition("Indicator")]
        public Indicator.mlLinRegSlope mlLinRegSlope(bool exponential, int period, int returnval)
        {
            return _indicator.mlLinRegSlope(Input, exponential, period, returnval);
        }

        /// <summary>
        /// Linear regression slope - super fast calc with exponential weighting option
        /// </summary>
        /// <returns></returns>
        public Indicator.mlLinRegSlope mlLinRegSlope(Data.IDataSeries input, bool exponential, int period, int returnval)
        {
            return _indicator.mlLinRegSlope(input, exponential, period, returnval);
        }
    }
}

// This namespace holds all strategies and is required. Do not change it.
namespace NinjaTrader.Strategy
{
    public partial class Strategy : StrategyBase
    {
        /// <summary>
        /// Linear regression slope - super fast calc with exponential weighting option
        /// </summary>
        /// <returns></returns>
        [Gui.Design.WizardCondition("Indicator")]
        public Indicator.mlLinRegSlope mlLinRegSlope(bool exponential, int period, int returnval)
        {
            return _indicator.mlLinRegSlope(Input, exponential, period, returnval);
        }

        /// <summary>
        /// Linear regression slope - super fast calc with exponential weighting option
        /// </summary>
        /// <returns></returns>
        public Indicator.mlLinRegSlope mlLinRegSlope(Data.IDataSeries input, bool exponential, int period, int returnval)
        {
            if (InInitialize && input == null)
                throw new ArgumentException("You only can access an indicator with the default input/bar series from within the 'Initialize()' method");

            return _indicator.mlLinRegSlope(input, exponential, period, returnval);
        }
    }
}
#endregion