#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.DrawingTools; #endregion //This namespace holds Indicators in this folder and is required. Do not change it. namespace NinjaTrader.NinjaScript.Indicators { public class LinearRegression : Indicator { private double sumX, sumY, sumXY, sumX2, averageY, slope, intercept; protected override void OnStateChange() { if (State == State.SetDefaults) { Description = @"Colors bars according to closes above / below a linear regression."; Name = "Linear Regression"; Calculate = Calculate.OnPriceChange; IsOverlay = true; ScaleJustification = ScaleJustification.Right; IsSuspendedWhileInactive = false; RegressionPeriod = 20; AboveThresholdColor = Brushes.LimeGreen; BelowThresholdColor = Brushes.Red; } } protected override void OnBarUpdate() { if (CurrentBar < RegressionPeriod) return; if (IsFirstTickOfBar) { CalculateLinearRegression(); double previousClose = Close[1]; double linearRegValue = intercept + slope * RegressionPeriod; if (previousClose > linearRegValue) { BarBrushes[0] = AboveThresholdColor; CandleOutlineBrushes[0] = AboveThresholdColor; } else if (previousClose < linearRegValue) { BarBrushes[0] = BelowThresholdColor; CandleOutlineBrushes[0] = BelowThresholdColor; } else { // Handle the rare occasion where the close is equivalent to the linear regression at this bar. BarBrushes[0] = BarBrushes[1]; CandleOutlineBrushes[0] = CandleOutlineBrushes[1]; } } } private void CalculateLinearRegression() { sumX = sumY = sumXY = sumX2 = 0; for (int i = 1; i < (RegressionPeriod + 1); i++) { sumX += i; sumY += Close[i]; sumXY += i * Close[i]; sumX2 += i * i; } double n = RegressionPeriod; slope = (n * sumXY - sumX * sumY) / (n * sumX2 - sumX * sumX); averageY = sumY / n; intercept = averageY - slope * (sumX / n); } public override string DisplayName { get { return Name; } } [NinjaScriptProperty] [Range(1, int.MaxValue)] [Display(Name = "Regression Period", GroupName = "Linear Regression", Order = 1)] public int RegressionPeriod { get; set; } [NinjaScriptProperty] [XmlIgnore] [Display(Name = "Above Regression", GroupName = "Linear Regression", Order = 2)] public Brush AboveThresholdColor { get; set; } [Browsable(false)] public string AboveThresholdColorSerialization { get { return Serialize.BrushToString(AboveThresholdColor); } set { AboveThresholdColor = Serialize.StringToBrush(value); } } [NinjaScriptProperty] [XmlIgnore] [Display(Name = "Below Regression", GroupName = "Linear Regression", Order = 3)] public Brush BelowThresholdColor { get; set; } [Browsable(false)] public string BelowThresholdColorSerialization { get { return Serialize.BrushToString(BelowThresholdColor); } set { BelowThresholdColor = Serialize.StringToBrush(value); } } } } #region NinjaScript generated code. Neither change nor remove. namespace NinjaTrader.NinjaScript.Indicators { public partial class Indicator : NinjaTrader.Gui.NinjaScript.IndicatorRenderBase { private LinearRegression[] cacheLinearRegression; public LinearRegression LinearRegression(int regressionPeriod, Brush aboveThresholdColor, Brush belowThresholdColor) { return LinearRegression(Input, regressionPeriod, aboveThresholdColor, belowThresholdColor); } public LinearRegression LinearRegression(ISeries input, int regressionPeriod, Brush aboveThresholdColor, Brush belowThresholdColor) { if (cacheLinearRegression != null) for (int idx = 0; idx < cacheLinearRegression.Length; idx++) if (cacheLinearRegression[idx] != null && cacheLinearRegression[idx].RegressionPeriod == regressionPeriod && cacheLinearRegression[idx].AboveThresholdColor == aboveThresholdColor && cacheLinearRegression[idx].BelowThresholdColor == belowThresholdColor && cacheLinearRegression[idx].EqualsInput(input)) return cacheLinearRegression[idx]; return CacheIndicator(new LinearRegression(){ RegressionPeriod = regressionPeriod, AboveThresholdColor = aboveThresholdColor, BelowThresholdColor = belowThresholdColor }, input, ref cacheLinearRegression); } } } namespace NinjaTrader.NinjaScript.MarketAnalyzerColumns { public partial class MarketAnalyzerColumn : MarketAnalyzerColumnBase { public Indicators.LinearRegression LinearRegression(int regressionPeriod, Brush aboveThresholdColor, Brush belowThresholdColor) { return indicator.LinearRegression(Input, regressionPeriod, aboveThresholdColor, belowThresholdColor); } public Indicators.LinearRegression LinearRegression(ISeries input , int regressionPeriod, Brush aboveThresholdColor, Brush belowThresholdColor) { return indicator.LinearRegression(input, regressionPeriod, aboveThresholdColor, belowThresholdColor); } } } namespace NinjaTrader.NinjaScript.Strategies { public partial class Strategy : NinjaTrader.Gui.NinjaScript.StrategyRenderBase { public Indicators.LinearRegression LinearRegression(int regressionPeriod, Brush aboveThresholdColor, Brush belowThresholdColor) { return indicator.LinearRegression(Input, regressionPeriod, aboveThresholdColor, belowThresholdColor); } public Indicators.LinearRegression LinearRegression(ISeries input , int regressionPeriod, Brush aboveThresholdColor, Brush belowThresholdColor) { return indicator.LinearRegression(input, regressionPeriod, aboveThresholdColor, belowThresholdColor); } } } #endregion