Add custom VWAP indicator

This commit is contained in:
moshferatu 2024-06-25 11:32:22 -07:00
parent c084cf682d
commit 78c9332976

331
indicators/VWAP.cs Normal file
View File

@ -0,0 +1,331 @@
#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;
#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 TotalVolumeTick;
private double VolumeWeightedPriceTick;
private double VWAPTick;
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.OHLC;
AddPlot(new Stroke(Brushes.Yellow, DashStyleHelper.Solid, 3), PlotStyle.Line, "VWAP");
}
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)
{
TotalVolume = 0;
VolumeWeightedPrice = 0;
TotalVolumeTick = 0;
VolumeWeightedPriceTick = 0;
VWAPTick = 0;
}
}
private double GetPrice(int bars)
{
switch (Price)
{
case VWAPPrice.Open:
return Opens[bars][0];
case VWAPPrice.High:
return Highs[bars][0];
case VWAPPrice.Low:
return Lows[bars][0];
case VWAPPrice.Close:
return Closes[bars][0];
case VWAPPrice.HL:
return (Highs[bars][0] + Lows[bars][0]) / 2;
case VWAPPrice.HLC:
return (Highs[bars][0] + Lows[bars][0] + Closes[bars][0]) / 3;
case VWAPPrice.OHLC:
default:
return (Opens[bars][0] + Highs[bars][0] + Lows[bars][0] + Closes[bars][0]) / 4;
}
}
protected override void OnBarUpdate()
{
if (CHART_BARS == BarsInProgress)
{
if (Precision == VWAPPrecision.Tick)
{
Value[0] = VWAPTick;
}
else if (Calculate == Calculate.OnBarClose || IsFirstTickOfBar)
{
TotalVolume += Volume[0];
VolumeWeightedPrice += Volume[0] * GetPrice(CHART_BARS);
Value[0] = VolumeWeightedPrice / TotalVolume;
}
else
{
Value[0] = (VolumeWeightedPrice + (Volume[0] * GetPrice(CHART_BARS))) / (TotalVolume + Volume[0]);
}
}
else if (TICK_BARS == BarsInProgress)
{
TotalVolumeTick += Volumes[TICK_BARS][0];
VolumeWeightedPriceTick += Volumes[TICK_BARS][0] * GetPrice(TICK_BARS);
VWAPTick = VolumeWeightedPriceTick / TotalVolumeTick;
}
}
public override string DisplayName
{
get { return Name; }
}
#region Properties
[TypeConverter(typeof(VWAPPrecisionConverter))]
[PropertyEditor("NinjaTrader.Gui.Tools.StringStandardValuesEditorKey")]
[Display(Name = "Precision", Description = "Precision with which VWAP is calculated", Order = 1, GroupName = "VWAP")]
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", Order = 2, GroupName = "VWAP")]
public VWAPPrice Price
{ 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 Period";
private const string TICK = "Tick";
public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
{
List<string> values = new List<string>() { 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<string> values = new List<string>() { 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[] cacheVWAPIndicator;
public VWAP VWAPIndicator()
{
return VWAPIndicator(Input);
}
public VWAP VWAPIndicator(ISeries<double> input)
{
if (cacheVWAPIndicator != null)
for (int idx = 0; idx < cacheVWAPIndicator.Length; idx++)
if (cacheVWAPIndicator[idx] != null && cacheVWAPIndicator[idx].EqualsInput(input))
return cacheVWAPIndicator[idx];
return CacheIndicator<VWAP>(new VWAP(), input, ref cacheVWAPIndicator);
}
}
}
namespace NinjaTrader.NinjaScript.MarketAnalyzerColumns
{
public partial class MarketAnalyzerColumn : MarketAnalyzerColumnBase
{
public Indicators.VWAP VWAPIndicator()
{
return indicator.VWAPIndicator(Input);
}
public Indicators.VWAP VWAPIndicator(ISeries<double> input )
{
return indicator.VWAPIndicator(input);
}
}
}
namespace NinjaTrader.NinjaScript.Strategies
{
public partial class Strategy : NinjaTrader.Gui.NinjaScript.StrategyRenderBase
{
public Indicators.VWAP VWAPIndicator()
{
return indicator.VWAPIndicator(Input);
}
public Indicators.VWAP VWAPIndicator(ISeries<double> input )
{
return indicator.VWAPIndicator(input);
}
}
}
#endregion