Add Fair Value Gap (FVG) indicator
This commit is contained in:
parent
cc9a741aa7
commit
5038889e97
453
indicators/FairValueGap.cs
Normal file
453
indicators/FairValueGap.cs
Normal file
@ -0,0 +1,453 @@
|
||||
#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 NinjaTrader.NinjaScript.Indicators;
|
||||
#endregion
|
||||
|
||||
//This namespace holds Indicators in this folder and is required. Do not change it.
|
||||
namespace NinjaTrader.NinjaScript.Indicators
|
||||
{
|
||||
public class FairValueGap
|
||||
{
|
||||
public DateTime StartTime { get; set; }
|
||||
|
||||
public DateTime EndTime { get; set; }
|
||||
|
||||
public double StartPrice { get; set; }
|
||||
|
||||
public double EndPrice { get; set; }
|
||||
}
|
||||
|
||||
[TypeConverter("NinjaTrader.NinjaScript.Indicators.FairValueGapsPropertyConverter")]
|
||||
public class FairValueGaps : Indicator
|
||||
{
|
||||
public const int CHART_BARS = 0;
|
||||
public const int OTHER_BARS = 1;
|
||||
|
||||
private List<FairValueGap> fairValueGaps;
|
||||
|
||||
protected override void OnStateChange()
|
||||
{
|
||||
if (State == State.SetDefaults)
|
||||
{
|
||||
Description = @"ICT Fair Value Gap (FVG)";
|
||||
Name = "Fair Value Gaps";
|
||||
Calculate = Calculate.OnPriceChange;
|
||||
IsOverlay = true;
|
||||
DisplayInDataBox = true;
|
||||
DrawOnPricePanel = true;
|
||||
DrawHorizontalGridLines = true;
|
||||
DrawVerticalGridLines = true;
|
||||
PaintPriceMarkers = true;
|
||||
ScaleJustification = ScaleJustification.Right;
|
||||
IsSuspendedWhileInactive = true;
|
||||
MinimumGap = 1.0;
|
||||
GapBars = CHART_BARS;
|
||||
BarType = BarsPeriodType.Minute;
|
||||
Period = 1;
|
||||
GapUpColor = Brushes.LimeGreen;
|
||||
GapUpOpacity = 25;
|
||||
GapDownColor = Brushes.Red;
|
||||
GapDownOpacity = 25;
|
||||
}
|
||||
else if (State == State.Configure)
|
||||
{
|
||||
fairValueGaps = new List<FairValueGap>();
|
||||
|
||||
if (GapBars != CHART_BARS)
|
||||
{
|
||||
AddDataSeries(Instrument.FullName, new BarsPeriod {
|
||||
BarsPeriodType = BarType, Value = Period }, Bars.TradingHours.Name);
|
||||
}
|
||||
}
|
||||
else if (State == State.Historical)
|
||||
{
|
||||
SetZOrder(-1);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnBarUpdate()
|
||||
{
|
||||
if (CurrentBar < 4)
|
||||
return;
|
||||
|
||||
if (GapBars == BarsInProgress && IsFirstTickOfBar)
|
||||
{
|
||||
double downGap = Lows[GapBars][3] - Highs[GapBars][1];
|
||||
if (downGap > MinimumGap)
|
||||
{
|
||||
fairValueGaps.Add(new FairValueGap
|
||||
{
|
||||
StartTime = Times[GapBars][3],
|
||||
StartPrice = Lows[GapBars][3],
|
||||
EndPrice = Highs[GapBars][1]
|
||||
});
|
||||
}
|
||||
|
||||
double upGap = Lows[GapBars][1] - Highs[GapBars][3];
|
||||
if (upGap > MinimumGap)
|
||||
{
|
||||
fairValueGaps.Add(new FairValueGap
|
||||
{
|
||||
StartTime = Times[GapBars][3],
|
||||
StartPrice = Highs[GapBars][3],
|
||||
EndPrice = Lows[GapBars][1]
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
var unfilledGaps = from fairValueGap in fairValueGaps
|
||||
where fairValueGap.EndTime == default(DateTime)
|
||||
select fairValueGap;
|
||||
foreach (FairValueGap unfilledGap in unfilledGaps)
|
||||
{
|
||||
if (unfilledGap.EndPrice < unfilledGap.StartPrice && Highs[BarsInProgress][0] >= unfilledGap.StartPrice)
|
||||
unfilledGap.EndTime = Times[BarsInProgress][0];
|
||||
else if (unfilledGap.EndPrice > unfilledGap.StartPrice && Lows[BarsInProgress][0] <= unfilledGap.StartPrice)
|
||||
unfilledGap.EndTime = Times[BarsInProgress][0];
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnRender(ChartControl chartControl, ChartScale chartScale)
|
||||
{
|
||||
base.OnRender(chartControl, chartScale);
|
||||
|
||||
SharpDX.Direct2D1.Brush fairValueGapUpBrush = GapUpColor.ToDxBrush(RenderTarget);
|
||||
fairValueGapUpBrush.Opacity = GapUpOpacity / 100f;
|
||||
|
||||
SharpDX.Direct2D1.Brush fairValueGapDownBrush = GapDownColor.ToDxBrush(RenderTarget);
|
||||
fairValueGapDownBrush.Opacity = GapDownOpacity / 100f;
|
||||
|
||||
// TODO: Only render gaps that would actually be visible on the screen.
|
||||
foreach (FairValueGap fairValueGap in fairValueGaps)
|
||||
{
|
||||
int fairValueGapStartX = chartControl.GetXByTime(fairValueGap.StartTime);
|
||||
|
||||
int fairValueGapEndX;
|
||||
if (fairValueGap.EndTime != default(DateTime))
|
||||
fairValueGapEndX = chartControl.GetXByTime(fairValueGap.EndTime);
|
||||
else
|
||||
fairValueGapEndX = ChartPanel.X + ChartPanel.W;
|
||||
|
||||
int fairValueGapStartY = chartScale.GetYByValue(Math.Max(fairValueGap.StartPrice, fairValueGap.EndPrice));
|
||||
int fairValueGapEndY = chartScale.GetYByValue(Math.Min(fairValueGap.StartPrice, fairValueGap.EndPrice));
|
||||
SharpDX.RectangleF fairValueGapRectangle = new SharpDX.RectangleF(fairValueGapStartX, fairValueGapStartY,
|
||||
fairValueGapEndX - fairValueGapStartX, fairValueGapEndY - fairValueGapStartY);
|
||||
RenderTarget.FillRectangle(fairValueGapRectangle,
|
||||
fairValueGap.EndPrice > fairValueGap.StartPrice ? fairValueGapUpBrush : fairValueGapDownBrush);
|
||||
}
|
||||
|
||||
fairValueGapUpBrush.Dispose();
|
||||
fairValueGapDownBrush.Dispose();
|
||||
}
|
||||
|
||||
public override string DisplayName
|
||||
{
|
||||
get { return Name; }
|
||||
}
|
||||
|
||||
#region Properties
|
||||
[NinjaScriptProperty]
|
||||
[Range(1, double.MaxValue)]
|
||||
[Display(Name = "Minimum Gap Size", Description = "Minimum size of gaps to consider (in points)", Order = 1, GroupName = "Fair Value Gaps")]
|
||||
public double MinimumGap
|
||||
{ get; set; }
|
||||
|
||||
[TypeConverter(typeof(GapBarsConverter))]
|
||||
[PropertyEditor("NinjaTrader.Gui.Tools.StringStandardValuesEditorKey")]
|
||||
[RefreshProperties(RefreshProperties.All)]
|
||||
[Display(Name = "Detect Gaps On", Description = "The bars used to detect gaps", Order = 2, GroupName = "Fair Value Gaps")]
|
||||
public int GapBars
|
||||
{ get; set; }
|
||||
|
||||
[TypeConverter(typeof(BarsPeriodTypeConverter))]
|
||||
[PropertyEditor("NinjaTrader.Gui.Tools.StringStandardValuesEditorKey")]
|
||||
[Display(Name = "Bar Type", Description = "Type of bars on which to detect gaps", Order = 3, GroupName = "Fair Value Gaps")]
|
||||
public BarsPeriodType BarType
|
||||
{ get; set; }
|
||||
|
||||
[NinjaScriptProperty]
|
||||
[Range(1, int.MaxValue)]
|
||||
[Display(Name = "Period", Description = "Period of the bars used to detect gaps", Order = 4, GroupName = "Fair Value Gaps")]
|
||||
public int Period
|
||||
{ get; set; }
|
||||
|
||||
[XmlIgnore]
|
||||
[NinjaScriptProperty]
|
||||
[Display(Name = "Gap Up", Description = "Color of the area of upward gaps", Order = 5, GroupName = "Fair Value Gaps")]
|
||||
public Brush GapUpColor
|
||||
{ get; set; }
|
||||
|
||||
[Browsable(false)]
|
||||
public string GapUpColorSerialization
|
||||
{
|
||||
get { return Serialize.BrushToString(GapUpColor); }
|
||||
set { GapUpColor = Serialize.StringToBrush(value); }
|
||||
}
|
||||
|
||||
[NinjaScriptProperty]
|
||||
[Range(0, 100)]
|
||||
[Display(Name = "Gap Up Opacity (%)", Description = "Opacity of the area of upward gaps", Order = 6, GroupName = "Fair Value Gaps")]
|
||||
public int GapUpOpacity
|
||||
{ get; set; }
|
||||
|
||||
[XmlIgnore]
|
||||
[NinjaScriptProperty]
|
||||
[Display(Name = "Gap Down", Description = "Color of the area of downward gaps", Order = 7, GroupName = "Fair Value Gaps")]
|
||||
public Brush GapDownColor
|
||||
{ get; set; }
|
||||
|
||||
[Browsable(false)]
|
||||
public string GapDownColorSerialization
|
||||
{
|
||||
get { return Serialize.BrushToString(GapDownColor); }
|
||||
set { GapDownColor = Serialize.StringToBrush(value); }
|
||||
}
|
||||
|
||||
[NinjaScriptProperty]
|
||||
[Range(0, 100)]
|
||||
[Display(Name = "Gap Down Opacity (%)", Description = "Opacity of the area of downward gaps", Order = 8, GroupName = "Fair Value Gaps")]
|
||||
public int GapDownOpacity
|
||||
{ get; set; }
|
||||
#endregion
|
||||
}
|
||||
|
||||
public class FairValueGapsPropertyConverter : IndicatorBaseConverter
|
||||
{
|
||||
public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object component, Attribute[] attrs)
|
||||
{
|
||||
FairValueGaps indicator = component as FairValueGaps;
|
||||
|
||||
PropertyDescriptorCollection properties = base.GetPropertiesSupported(context) ?
|
||||
base.GetProperties(context, component, attrs) : TypeDescriptor.GetProperties(component, attrs);
|
||||
|
||||
if (indicator == null || properties == null)
|
||||
return properties;
|
||||
|
||||
PropertyDescriptor barType = properties["BarType"];
|
||||
PropertyDescriptor period = properties["Period"];
|
||||
|
||||
properties.Remove(barType);
|
||||
properties.Remove(period);
|
||||
|
||||
if (indicator.GapBars == FairValueGaps.OTHER_BARS)
|
||||
{
|
||||
properties.Add(barType);
|
||||
properties.Add(period);
|
||||
}
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
public override bool GetPropertiesSupported(ITypeDescriptorContext context)
|
||||
{ return true; }
|
||||
}
|
||||
}
|
||||
|
||||
public class GapBarsConverter : TypeConverter
|
||||
{
|
||||
private const string CHART = "Chart Bars";
|
||||
private const string OTHER = "Other";
|
||||
|
||||
public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
|
||||
{
|
||||
List<string> values = new List<string>() { CHART, OTHER };
|
||||
return new StandardValuesCollection(values);
|
||||
}
|
||||
|
||||
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
|
||||
{
|
||||
switch (value.ToString())
|
||||
{
|
||||
case CHART:
|
||||
return FairValueGaps.CHART_BARS;
|
||||
case OTHER:
|
||||
return FairValueGaps.OTHER_BARS;
|
||||
}
|
||||
return FairValueGaps.CHART_BARS;
|
||||
}
|
||||
|
||||
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
|
||||
{
|
||||
switch ((int)value)
|
||||
{
|
||||
case FairValueGaps.CHART_BARS:
|
||||
return CHART;
|
||||
case FairValueGaps.OTHER_BARS:
|
||||
return OTHER;
|
||||
}
|
||||
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 BarsPeriodTypeConverter : TypeConverter
|
||||
{
|
||||
private const string MINUTE = "Minute";
|
||||
private const string SECOND = "Second";
|
||||
private const string DAY = "Day";
|
||||
private const string WEEK = "Week";
|
||||
private const string MONTH = "Month";
|
||||
private const string YEAR = "Year";
|
||||
private const string RANGE = "Range";
|
||||
private const string TICK = "Tick";
|
||||
private const string VOLUME = "Volume";
|
||||
|
||||
public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
|
||||
{
|
||||
List<string> values = new List<string>() { MINUTE, SECOND, DAY, WEEK, MONTH, YEAR, RANGE, TICK, VOLUME };
|
||||
return new StandardValuesCollection(values);
|
||||
}
|
||||
|
||||
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
|
||||
{
|
||||
switch (value.ToString())
|
||||
{
|
||||
case MINUTE:
|
||||
return BarsPeriodType.Minute;
|
||||
case SECOND:
|
||||
return BarsPeriodType.Second;
|
||||
case DAY:
|
||||
return BarsPeriodType.Day;
|
||||
case WEEK:
|
||||
return BarsPeriodType.Week;
|
||||
case MONTH:
|
||||
return BarsPeriodType.Month;
|
||||
case YEAR:
|
||||
return BarsPeriodType.Year;
|
||||
case RANGE:
|
||||
return BarsPeriodType.Range;
|
||||
case TICK:
|
||||
return BarsPeriodType.Tick;
|
||||
case VOLUME:
|
||||
return BarsPeriodType.Volume;
|
||||
}
|
||||
return BarsPeriodType.Minute;
|
||||
}
|
||||
|
||||
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
|
||||
{
|
||||
BarsPeriodType enumValue = (BarsPeriodType)Enum.Parse(typeof(BarsPeriodType), value.ToString());
|
||||
switch (enumValue)
|
||||
{
|
||||
case BarsPeriodType.Minute:
|
||||
return MINUTE;
|
||||
case BarsPeriodType.Second:
|
||||
return SECOND;
|
||||
case BarsPeriodType.Day:
|
||||
return DAY;
|
||||
case BarsPeriodType.Week:
|
||||
return WEEK;
|
||||
case BarsPeriodType.Month:
|
||||
return MONTH;
|
||||
case BarsPeriodType.Year:
|
||||
return YEAR;
|
||||
case BarsPeriodType.Range:
|
||||
return RANGE;
|
||||
case BarsPeriodType.Tick:
|
||||
return TICK;
|
||||
case BarsPeriodType.Volume:
|
||||
return VOLUME;
|
||||
}
|
||||
return MINUTE;
|
||||
}
|
||||
|
||||
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 FairValueGaps[] cacheFairValueGaps;
|
||||
public FairValueGaps FairValueGaps(double minimumGap, int period, Brush gapUpColor, int gapUpOpacity, Brush gapDownColor, int gapDownOpacity)
|
||||
{
|
||||
return FairValueGaps(Input, minimumGap, period, gapUpColor, gapUpOpacity, gapDownColor, gapDownOpacity);
|
||||
}
|
||||
|
||||
public FairValueGaps FairValueGaps(ISeries<double> input, double minimumGap, int period, Brush gapUpColor, int gapUpOpacity, Brush gapDownColor, int gapDownOpacity)
|
||||
{
|
||||
if (cacheFairValueGaps != null)
|
||||
for (int idx = 0; idx < cacheFairValueGaps.Length; idx++)
|
||||
if (cacheFairValueGaps[idx] != null && cacheFairValueGaps[idx].MinimumGap == minimumGap && cacheFairValueGaps[idx].Period == period && cacheFairValueGaps[idx].GapUpColor == gapUpColor && cacheFairValueGaps[idx].GapUpOpacity == gapUpOpacity && cacheFairValueGaps[idx].GapDownColor == gapDownColor && cacheFairValueGaps[idx].GapDownOpacity == gapDownOpacity && cacheFairValueGaps[idx].EqualsInput(input))
|
||||
return cacheFairValueGaps[idx];
|
||||
return CacheIndicator<FairValueGaps>(new FairValueGaps(){ MinimumGap = minimumGap, Period = period, GapUpColor = gapUpColor, GapUpOpacity = gapUpOpacity, GapDownColor = gapDownColor, GapDownOpacity = gapDownOpacity }, input, ref cacheFairValueGaps);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace NinjaTrader.NinjaScript.MarketAnalyzerColumns
|
||||
{
|
||||
public partial class MarketAnalyzerColumn : MarketAnalyzerColumnBase
|
||||
{
|
||||
public Indicators.FairValueGaps FairValueGaps(double minimumGap, int period, Brush gapUpColor, int gapUpOpacity, Brush gapDownColor, int gapDownOpacity)
|
||||
{
|
||||
return indicator.FairValueGaps(Input, minimumGap, period, gapUpColor, gapUpOpacity, gapDownColor, gapDownOpacity);
|
||||
}
|
||||
|
||||
public Indicators.FairValueGaps FairValueGaps(ISeries<double> input , double minimumGap, int period, Brush gapUpColor, int gapUpOpacity, Brush gapDownColor, int gapDownOpacity)
|
||||
{
|
||||
return indicator.FairValueGaps(input, minimumGap, period, gapUpColor, gapUpOpacity, gapDownColor, gapDownOpacity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace NinjaTrader.NinjaScript.Strategies
|
||||
{
|
||||
public partial class Strategy : NinjaTrader.Gui.NinjaScript.StrategyRenderBase
|
||||
{
|
||||
public Indicators.FairValueGaps FairValueGaps(double minimumGap, int period, Brush gapUpColor, int gapUpOpacity, Brush gapDownColor, int gapDownOpacity)
|
||||
{
|
||||
return indicator.FairValueGaps(Input, minimumGap, period, gapUpColor, gapUpOpacity, gapDownColor, gapDownOpacity);
|
||||
}
|
||||
|
||||
public Indicators.FairValueGaps FairValueGaps(ISeries<double> input , double minimumGap, int period, Brush gapUpColor, int gapUpOpacity, Brush gapDownColor, int gapDownOpacity)
|
||||
{
|
||||
return indicator.FairValueGaps(input, minimumGap, period, gapUpColor, gapUpOpacity, gapDownColor, gapDownOpacity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
Loading…
Reference in New Issue
Block a user