From e52ae0ebaa37c67415b69456cc4a143551a88b8c Mon Sep 17 00:00:00 2001 From: moshferatu Date: Thu, 12 Oct 2023 10:25:17 -0700 Subject: [PATCH] Add VIX Ratio (e.g., VIX / VIX3M) indicator --- indicators/VIXRatio.cs | 293 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 293 insertions(+) create mode 100644 indicators/VIXRatio.cs diff --git a/indicators/VIXRatio.cs b/indicators/VIXRatio.cs new file mode 100644 index 0000000..b911b48 --- /dev/null +++ b/indicators/VIXRatio.cs @@ -0,0 +1,293 @@ +#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; +using System.Globalization; +using System.Windows.Data; +#endregion + +//This namespace holds Indicators in this folder and is required. Do not change it. +namespace NinjaTrader.NinjaScript.Indicators +{ + [CategoryOrder("VIX Ratio", 1)] + [CategoryOrder("Plots", 2)] + public class VIXRatio : Indicator + { + private const int NumeratorBars = 1; + private const int DenominatorBars = 2; + + private EMA fastEMA; + private EMA slowEMA; + + protected override void OnStateChange() + { + if (State == State.SetDefaults) + { + Description = @"Only works with a data feed that provides the relevant VIX indices"; + Name = "VIX Ratio"; + Calculate = Calculate.OnBarClose; + BarsRequiredToPlot = 1; + IsOverlay = false; + DisplayInDataBox = true; + DrawOnPricePanel = true; + PaintPriceMarkers = false; + ScaleJustification = ScaleJustification.Right; + Numerator = VIXIndex.VIX; + Denominator = VIXIndex.VIX3M; + FastEMAPeriod = 7; + SlowEMAPeriod = 12; + AddPlot(new Stroke(Brushes.Yellow, 2), PlotStyle.Line, "VIX Ratio"); + AddPlot(new Stroke(Brushes.Green, 2), PlotStyle.Line, "Fast EMA"); + AddPlot(new Stroke(Brushes.Red, 2), PlotStyle.Line, "Slow EMA"); + } + else if (State == State.Configure) + { + AddDataSeries(Numerator.ToSymbol()); + AddDataSeries(Denominator.ToSymbol()); + } + else if (State == State.DataLoaded) + { + fastEMA = EMA(Ratio, FastEMAPeriod); + slowEMA = EMA(Ratio, SlowEMAPeriod); + } + } + + protected override void OnBarUpdate() + { + if (CurrentBars[NumeratorBars] < 1 || CurrentBars[DenominatorBars] < 1) + return; + + // Denominator bars should be processed last according to NT documentation on bar processing order. + if (BarsInProgress == DenominatorBars) + { + Ratio[0] = Closes[NumeratorBars][0] / Closes[DenominatorBars][0]; + + if (CurrentBar >= Math.Max(FastEMAPeriod, SlowEMAPeriod)) + { + FastEMA[0] = fastEMA[0]; + SlowEMA[0] = slowEMA[0]; + } + } + } + + public override string DisplayName + { + get { return Numerator.ToString() + " / " + Denominator.ToString(); } + } + + [NinjaScriptProperty] + [PropertyEditor("NinjaTrader.Gui.Tools.StringStandardValuesEditorKey")] + [TypeConverter(typeof(VIXIndexConverter))] + [Display(Name = "Numerator", Order = 1, GroupName = "VIX Ratio")] + public VIXIndex Numerator { get; set; } + + [NinjaScriptProperty] + [PropertyEditor("NinjaTrader.Gui.Tools.StringStandardValuesEditorKey")] + [TypeConverter(typeof(VIXIndexConverter))] + [Display(Name = "Denominator", Order = 2, GroupName = "VIX Ratio")] + public VIXIndex Denominator { get; set; } + + [NinjaScriptProperty] + [Range(1, int.MaxValue)] + [Display(Name = "Fast EMA Period", Order = 3, GroupName = "VIX Ratio")] + public int FastEMAPeriod { get; set; } + + [NinjaScriptProperty] + [Range(1, int.MaxValue)] + [Display(Name = "Slow EMA Period", Order = 4, GroupName = "VIX Ratio")] + public int SlowEMAPeriod { get; set; } + + [Browsable(false)] + [XmlIgnore] + public Series Ratio + { + get { return Values[0]; } + } + + [Browsable(false)] + [XmlIgnore] + public Series FastEMA + { + get { return Values[1]; } + } + + [Browsable(false)] + [XmlIgnore] + public Series SlowEMA + { + get { return Values[2]; } + } + } +} + +public enum VIXIndex +{ + VIX1D, + VIX9D, + VIX, + VIX3M, + VIX6M, + VIX1Y +} + +public static class VIXIndexExtensions +{ + public static string ToSymbol(this VIXIndex value) + { + switch (value) + { + case VIXIndex.VIX1D: + return "^VIX1D"; + case VIXIndex.VIX9D: + return "^VIX9D"; + case VIXIndex.VIX3M: + return "^VIX3M"; + case VIXIndex.VIX6M: + return "^VIX6M"; + case VIXIndex.VIX1Y: + return "^VIX1Y"; + default: + return "^VIX"; + } + } +} + +public class VIXIndexConverter : TypeConverter +{ + private const string VIX1D = "VIX1D"; + private const string VIX9D = "VIX9D"; + private const string VIX = "VIX"; + private const string VIX3M = "VIX3M"; + private const string VIX6M = "VIX6M"; + private const string VIX1Y = "VIX1Y"; + + public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context) + { + return new StandardValuesCollection(new List { VIX1D, VIX9D, VIX, VIX3M, VIX6M, VIX1Y }); + } + + public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) + { + switch (value.ToString()) + { + case VIX1D: + return VIXIndex.VIX1D; + case VIX9D: + return VIXIndex.VIX9D; + case VIX3M: + return VIXIndex.VIX3M; + case VIX6M: + return VIXIndex.VIX6M; + case VIX1Y: + return VIXIndex.VIX1Y; + default: + return VIXIndex.VIX; + } + } + + public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) + { + VIXIndex enumValue = (VIXIndex)Enum.Parse(typeof(VIXIndex), value.ToString()); + switch (enumValue) + { + case VIXIndex.VIX1D: + return VIX1D; + case VIXIndex.VIX9D: + return VIX9D; + case VIXIndex.VIX3M: + return VIX3M; + case VIXIndex.VIX6M: + return VIX6M; + case VIXIndex.VIX1Y: + return VIX1Y; + default: + return VIX; + } + } + + public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) + { return true; } + + public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) + { return true; } + + public override bool GetStandardValuesExclusive(ITypeDescriptorContext context) + { return true; } + + public override bool GetStandardValuesSupported(ITypeDescriptorContext context) + { return true; } +} + +#region NinjaScript generated code. Neither change nor remove. + +namespace NinjaTrader.NinjaScript.Indicators +{ + public partial class Indicator : NinjaTrader.Gui.NinjaScript.IndicatorRenderBase + { + private VIXRatio[] cacheVIXRatio; + public VIXRatio VIXRatio(VIXIndex numerator, VIXIndex denominator, int fastEMAPeriod, int slowEMAPeriod) + { + return VIXRatio(Input, numerator, denominator, fastEMAPeriod, slowEMAPeriod); + } + + public VIXRatio VIXRatio(ISeries input, VIXIndex numerator, VIXIndex denominator, int fastEMAPeriod, int slowEMAPeriod) + { + if (cacheVIXRatio != null) + for (int idx = 0; idx < cacheVIXRatio.Length; idx++) + if (cacheVIXRatio[idx] != null && cacheVIXRatio[idx].Numerator == numerator && cacheVIXRatio[idx].Denominator == denominator && cacheVIXRatio[idx].FastEMAPeriod == fastEMAPeriod && cacheVIXRatio[idx].SlowEMAPeriod == slowEMAPeriod && cacheVIXRatio[idx].EqualsInput(input)) + return cacheVIXRatio[idx]; + return CacheIndicator(new VIXRatio(){ Numerator = numerator, Denominator = denominator, FastEMAPeriod = fastEMAPeriod, SlowEMAPeriod = slowEMAPeriod }, input, ref cacheVIXRatio); + } + } +} + +namespace NinjaTrader.NinjaScript.MarketAnalyzerColumns +{ + public partial class MarketAnalyzerColumn : MarketAnalyzerColumnBase + { + public Indicators.VIXRatio VIXRatio(VIXIndex numerator, VIXIndex denominator, int fastEMAPeriod, int slowEMAPeriod) + { + return indicator.VIXRatio(Input, numerator, denominator, fastEMAPeriod, slowEMAPeriod); + } + + public Indicators.VIXRatio VIXRatio(ISeries input , VIXIndex numerator, VIXIndex denominator, int fastEMAPeriod, int slowEMAPeriod) + { + return indicator.VIXRatio(input, numerator, denominator, fastEMAPeriod, slowEMAPeriod); + } + } +} + +namespace NinjaTrader.NinjaScript.Strategies +{ + public partial class Strategy : NinjaTrader.Gui.NinjaScript.StrategyRenderBase + { + public Indicators.VIXRatio VIXRatio(VIXIndex numerator, VIXIndex denominator, int fastEMAPeriod, int slowEMAPeriod) + { + return indicator.VIXRatio(Input, numerator, denominator, fastEMAPeriod, slowEMAPeriod); + } + + public Indicators.VIXRatio VIXRatio(ISeries input , VIXIndex numerator, VIXIndex denominator, int fastEMAPeriod, int slowEMAPeriod) + { + return indicator.VIXRatio(input, numerator, denominator, fastEMAPeriod, slowEMAPeriod); + } + } +} + +#endregion