#region Using declarations using NinjaTrader.Cbi; using NinjaTrader.Data; using NinjaTrader.Gui; using NinjaTrader.NinjaScript.MarketAnalyzerColumns; using System; using System.Collections.Generic; using System.ComponentModel; using System.ComponentModel.DataAnnotations; using System.Globalization; using System.Windows.Media; using System.Xml.Serialization; #endregion namespace NinjaTrader.NinjaScript.Indicators { public class VWAP : Indicator { private static int CHART_BARS = 0; private static int TICK_BARS = 1; private double TotalVolume; private double VolumeWeightedPrice; private double VolumeWeightedSquaredPrice; private double TotalVolumeTick; private double VolumeWeightedPriceTick; private double VolumeWeightedSquaredPriceTick; private DateTime MostRecentDate = DateTime.MinValue; protected override void OnStateChange() { if (State == State.SetDefaults) { Description = "Volume Weighted Average Price (VWAP)"; Name = "VWAP"; Calculate = Calculate.OnBarClose; IsOverlay = true; DisplayInDataBox = true; DrawOnPricePanel = true; ScaleJustification = Gui.Chart.ScaleJustification.Right; IsSuspendedWhileInactive = true; BarsRequiredToPlot = 0; Precision = VWAPPrecision.Chart; Price = VWAPPrice.HLC; // Typical Price StdDevMultiplier = 1.0; AddPlot(new Stroke(Brushes.Yellow, DashStyleHelper.Solid, 3), PlotStyle.Line, "VWAP"); AddPlot(new Stroke(Brushes.Transparent, DashStyleHelper.Solid, 3), PlotStyle.Line, "Upper Standard Deviation"); AddPlot(new Stroke(Brushes.Transparent, DashStyleHelper.Solid, 3), PlotStyle.Line, "Lower Standard Deviation"); } else if (State == State.Configure) { ClearOutputWindow(); if (Precision == VWAPPrecision.Tick) { AddDataSeries(Instrument.FullName, new BarsPeriod { BarsPeriodType = BarsPeriodType.Tick, Value = 1 }, Bars.TradingHours.Name); } } else if (State == State.DataLoaded) { ResetVWAP(); } } private double GetPrice(int bars, int index = 0) { switch (Price) { case VWAPPrice.Open: return Opens[bars][index]; case VWAPPrice.High: return Highs[bars][index]; case VWAPPrice.Low: return Lows[bars][index]; case VWAPPrice.Close: return Closes[bars][index]; case VWAPPrice.HL: return (Highs[bars][index] + Lows[bars][index]) / 2; case VWAPPrice.HLC: return (Highs[bars][index] + Lows[bars][index] + Closes[bars][index]) / 3; case VWAPPrice.OHLC: default: return (Opens[bars][index] + Highs[bars][index] + Lows[bars][index] + Closes[bars][index]) / 4; } } private void ResetVWAP() { TotalVolume = 0; VolumeWeightedPrice = 0; VolumeWeightedSquaredPrice = 0; TotalVolumeTick = 0; VolumeWeightedPriceTick = 0; VolumeWeightedSquaredPriceTick = 0; } protected override void OnBarUpdate() { if (Bars.IsFirstBarOfSession && IsFirstTickOfBar) { DateTime currentDate = Time[0].Date; if (MostRecentDate != currentDate) ResetVWAP(); if (CHART_BARS == BarsInProgress) { // Prevent visible jumps in VWAP when a new session begins. PlotBrushes[0][0] = Brushes.Transparent; PlotBrushes[1][0] = Brushes.Transparent; PlotBrushes[2][0] = Brushes.Transparent; } MostRecentDate = currentDate; } if (CHART_BARS == BarsInProgress) { double price = GetPrice(CHART_BARS); double vwap; double variance; double volumeWeightedPrice; double volumeWeightedSquaredPrice; double totalVolume; if (Precision == VWAPPrecision.Tick) { volumeWeightedPrice = VolumeWeightedPriceTick; volumeWeightedSquaredPrice = VolumeWeightedSquaredPriceTick; totalVolume = TotalVolumeTick; } else if (Calculate == Calculate.OnBarClose) { VolumeWeightedPrice += Volume[0] * price; VolumeWeightedSquaredPrice += Volume[0] * Math.Pow(price, 2); TotalVolume += Volume[0]; volumeWeightedPrice = VolumeWeightedPrice; volumeWeightedSquaredPrice = VolumeWeightedSquaredPrice; totalVolume = TotalVolume; } else { if (IsFirstTickOfBar && !Bars.IsFirstBarOfSession) { int previousBar = 1; double previousPrice = GetPrice(CHART_BARS, previousBar); VolumeWeightedPrice += Volume[previousBar] * previousPrice; VolumeWeightedSquaredPrice += Volume[previousBar] * Math.Pow(previousPrice, 2); TotalVolume += Volume[previousBar]; } volumeWeightedPrice = VolumeWeightedPrice + (Volume[0] * price); volumeWeightedSquaredPrice = VolumeWeightedSquaredPrice + (Volume[0] * Math.Pow(price, 2)); totalVolume = TotalVolume + Volume[0]; } vwap = volumeWeightedPrice / totalVolume; variance = (volumeWeightedSquaredPrice / totalVolume) - Math.Pow(vwap, 2); double stdDev = Math.Sqrt(variance); Value[0] = vwap; Values[1][0] = vwap + (StdDevMultiplier * stdDev); Values[2][0] = vwap - (StdDevMultiplier * stdDev); } else if (TICK_BARS == BarsInProgress) { double price = GetPrice(TICK_BARS); TotalVolumeTick += Volumes[TICK_BARS][0]; VolumeWeightedPriceTick += Volumes[TICK_BARS][0] * price; VolumeWeightedSquaredPriceTick += Volumes[TICK_BARS][0] * Math.Pow(price, 2); } } public override string DisplayName { get { return Name; } } [Browsable(false)] [XmlIgnore] public Series UpperStdDev { get { return Values[1]; } } [Browsable(false)] [XmlIgnore] public Series LowerStdDev { get { return Values[2]; } } #region Properties [TypeConverter(typeof(VWAPPrecisionConverter))] [PropertyEditor("NinjaTrader.Gui.Tools.StringStandardValuesEditorKey")] [Display(Name = "Precision", Description = "Precision with which VWAP is calculated", GroupName = "VWAP", Order = 1)] public VWAPPrecision Precision { get; set; } [TypeConverter(typeof(VWAPPriceConverter))] [PropertyEditor("NinjaTrader.Gui.Tools.StringStandardValuesEditorKey")] [Display(Name = "Average Price", Description = "How the average price of the bar is calculated", GroupName = "VWAP", Order = 2)] public VWAPPrice Price { get; set; } [Range(0.1, double.MaxValue)] [Display(Name = "Standard Deviation Multiplier", Description = "Multiplier for standard deviation bands", GroupName = "VWAP", Order = 3)] public double StdDevMultiplier { get; set; } #endregion } } public enum VWAPPrecision { Chart, Tick } public enum VWAPPrice { Open, High, Low, Close, HL, HLC, OHLC } public class VWAPPrecisionConverter : TypeConverter { private const string CHART = "Chart"; private const string TICK = "Tick"; public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context) { List values = new List() { CHART, TICK }; return new StandardValuesCollection(values); } public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) { switch (value.ToString()) { case CHART: return VWAPPrecision.Chart; case TICK: return VWAPPrecision.Tick; } return VWAPPrecision.Chart; } public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) { VWAPPrecision enumValue = (VWAPPrecision)Enum.Parse(typeof(VWAPPrecision), value.ToString()); switch (enumValue) { case VWAPPrecision.Chart: return CHART; case VWAPPrecision.Tick: return TICK; } return CHART; } 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; } } public class VWAPPriceConverter : TypeConverter { private const string OPEN = "Open"; private const string HIGH = "High"; private const string LOW = "Low"; private const string CLOSE = "Close"; private const string HIGH_LOW = "(High + Low) / 2"; private const string HIGH_LOW_CLOSE = "(High + Low + Close) / 3"; private const string OPEN_HIGH_LOW_CLOSE = "(Open + High + Low + Close) / 4"; public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context) { List values = new List() { OPEN, HIGH, LOW, CLOSE, HIGH_LOW, HIGH_LOW_CLOSE, OPEN_HIGH_LOW_CLOSE }; return new StandardValuesCollection(values); } public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) { switch (value.ToString()) { case OPEN: return VWAPPrice.Open; case HIGH: return VWAPPrice.High; case LOW: return VWAPPrice.Low; case CLOSE: return VWAPPrice.Close; case HIGH_LOW: return VWAPPrice.HL; case HIGH_LOW_CLOSE: return VWAPPrice.HLC; case OPEN_HIGH_LOW_CLOSE: return VWAPPrice.OHLC; } return VWAPPrice.OHLC; } public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) { VWAPPrice enumValue = (VWAPPrice)Enum.Parse(typeof(VWAPPrice), value.ToString()); switch (enumValue) { case VWAPPrice.Open: return OPEN; case VWAPPrice.High: return HIGH; case VWAPPrice.Low: return LOW; case VWAPPrice.Close: return CLOSE; case VWAPPrice.HL: return HIGH_LOW; case VWAPPrice.HLC: return HIGH_LOW_CLOSE; case VWAPPrice.OHLC: return OPEN_HIGH_LOW_CLOSE; } return OPEN_HIGH_LOW_CLOSE; } 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 VWAP[] cacheVWAP; public VWAP VWAP() { return VWAP(Input); } public VWAP VWAP(ISeries input) { if (cacheVWAP != null) for (int idx = 0; idx < cacheVWAP.Length; idx++) if (cacheVWAP[idx] != null && cacheVWAP[idx].EqualsInput(input)) return cacheVWAP[idx]; return CacheIndicator(new VWAP(), input, ref cacheVWAP); } } } namespace NinjaTrader.NinjaScript.MarketAnalyzerColumns { public partial class MarketAnalyzerColumn : MarketAnalyzerColumnBase { public Indicators.VWAP VWAP() { return indicator.VWAP(Input); } public Indicators.VWAP VWAP(ISeries input ) { return indicator.VWAP(input); } } } namespace NinjaTrader.NinjaScript.Strategies { public partial class Strategy : NinjaTrader.Gui.NinjaScript.StrategyRenderBase { public Indicators.VWAP VWAP() { return indicator.VWAP(Input); } public Indicators.VWAP VWAP(ISeries input ) { return indicator.VWAP(input); } } } #endregion