#region Using declarations using System.Collections.Generic; using System.ComponentModel; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Xml.Serialization; using NinjaTrader.Gui.Chart; using NinjaTrader.Data; #endregion //This namespace holds Indicators in this folder and is required. Do not change it. namespace NinjaTrader.NinjaScript.Indicators { public class VolatilityRegime : Indicator { private const int VIXBars = 1; protected override void OnStateChange() { if (State == State.SetDefaults) { Description = @""; Name = "Volatility Regime"; Calculate = Calculate.OnBarClose; IsOverlay = true; DisplayInDataBox = true; DrawOnPricePanel = true; ScaleJustification = ScaleJustification.Right; IsSuspendedWhileInactive = true; RankPeriod = 252; // Approximately 1 year in trading days. } else if (State == State.Configure) { // TODO: Base number of days to request on a configurable date range. AddDataSeries("^VIX", new BarsPeriod { BarsPeriodType = BarsPeriodType.Day, Value = 1 }, 2000, "US Equities RTH", Bars.IsResetOnNewTradingDay); } else if (State == State.DataLoaded) { PercentRank = new Series(this); } else if (State == State.Historical) { SetZOrder(-1); // Display behind bars on chart. } } protected override void OnBarUpdate() { if (VIXBars != BarsInProgress) return; // Calculate percent rank of VIX closing prices over lookback period. if (CurrentBar >= RankPeriod) { List vixCloses = new List(); for (int i = RankPeriod; i > 0; i--) vixCloses.Add(Closes[VIXBars][i]); double currentVixClose = Closes[VIXBars][0]; int rank = vixCloses.Count(x => x <= currentVixClose); // # of closes <= current price. PercentRank[0] = (double)rank / RankPeriod; } else { PercentRank[0] = 0; // Insufficient data. } } public override string DisplayName { get { return Name; } } [Browsable(false)] [XmlIgnore] public Series PercentRank { get; set; } #region Properties [NinjaScriptProperty] [Range(1, int.MaxValue)] [Display(Name = "Rank Period", Description = "Period for the percent rank lookback", Order = 1, GroupName = "Volatility Regime")] public int RankPeriod { get; set; } #endregion } } #region NinjaScript generated code. Neither change nor remove. namespace NinjaTrader.NinjaScript.Indicators { public partial class Indicator : NinjaTrader.Gui.NinjaScript.IndicatorRenderBase { private VolatilityRegime[] cacheVolatilityRegime; public VolatilityRegime VolatilityRegime(int rankPeriod) { return VolatilityRegime(Input, rankPeriod); } public VolatilityRegime VolatilityRegime(ISeries input, int rankPeriod) { if (cacheVolatilityRegime != null) for (int idx = 0; idx < cacheVolatilityRegime.Length; idx++) if (cacheVolatilityRegime[idx] != null && cacheVolatilityRegime[idx].RankPeriod == rankPeriod && cacheVolatilityRegime[idx].EqualsInput(input)) return cacheVolatilityRegime[idx]; return CacheIndicator(new VolatilityRegime(){ RankPeriod = rankPeriod }, input, ref cacheVolatilityRegime); } } } namespace NinjaTrader.NinjaScript.MarketAnalyzerColumns { public partial class MarketAnalyzerColumn : MarketAnalyzerColumnBase { public Indicators.VolatilityRegime VolatilityRegime(int rankPeriod) { return indicator.VolatilityRegime(Input, rankPeriod); } public Indicators.VolatilityRegime VolatilityRegime(ISeries input , int rankPeriod) { return indicator.VolatilityRegime(input, rankPeriod); } } } namespace NinjaTrader.NinjaScript.Strategies { public partial class Strategy : NinjaTrader.Gui.NinjaScript.StrategyRenderBase { public Indicators.VolatilityRegime VolatilityRegime(int rankPeriod) { return indicator.VolatilityRegime(Input, rankPeriod); } public Indicators.VolatilityRegime VolatilityRegime(ISeries input , int rankPeriod) { return indicator.VolatilityRegime(input, rankPeriod); } } } #endregion