298 lines
11 KiB
C#
298 lines
11 KiB
C#
#region Using declarations
|
|
using NinjaTrader.Gui;
|
|
using NinjaTrader.Gui.Chart;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.ComponentModel.DataAnnotations;
|
|
using System.Globalization;
|
|
using System.Xml.Serialization;
|
|
using System.Windows.Media;
|
|
#endregion
|
|
|
|
namespace NinjaTrader.NinjaScript.Indicators
|
|
{
|
|
[CategoryOrder("RSI Histogram", 1)]
|
|
[CategoryOrder("Appearance", 2)]
|
|
public class RSIHistogram : Indicator
|
|
{
|
|
public static RSIHistogramColorScheme DefaultColorScheme = RSIHistogramColorScheme.PreviousBar;
|
|
public static Brush DefaultPositiveBarColor = Brushes.LimeGreen;
|
|
public static Brush DefaultNegativeBarColor = Brushes.Red;
|
|
|
|
public static double DefaultUpperLevel = 20.0;
|
|
public static double DefaultLowerLevel = -20.0;
|
|
|
|
public static bool DefaultShowLevels = true;
|
|
public static Stroke DefaultLevelStroke = new Stroke(Brushes.Yellow, DashStyleHelper.Solid, 2);
|
|
|
|
private RSI RSIValue;
|
|
|
|
protected override void OnStateChange()
|
|
{
|
|
if (State == State.SetDefaults)
|
|
{
|
|
Description = @"Credit to @BestForexMethod on Twitter";
|
|
Name = "RSI Histogram";
|
|
|
|
Calculate = Calculate.OnPriceChange;
|
|
IsOverlay = false;
|
|
DisplayInDataBox = true;
|
|
DrawOnPricePanel = true;
|
|
DrawHorizontalGridLines = true;
|
|
DrawVerticalGridLines = true;
|
|
PaintPriceMarkers = true;
|
|
ScaleJustification = ScaleJustification.Right;
|
|
IsSuspendedWhileInactive = true;
|
|
|
|
ArePlotsConfigurable = false;
|
|
AreLinesConfigurable = false;
|
|
|
|
RSIPeriod = 8;
|
|
RSISmoothing = 3;
|
|
RSIModifier = 1.5;
|
|
|
|
ColorScheme = DefaultColorScheme;
|
|
PositiveBarColor = DefaultPositiveBarColor;
|
|
NegativeBarColor = DefaultNegativeBarColor;
|
|
|
|
ShowLevels = DefaultShowLevels;
|
|
|
|
UpperLevel = DefaultUpperLevel;
|
|
LowerLevel = DefaultLowerLevel;
|
|
|
|
UpperLevelStroke = DefaultLevelStroke;
|
|
LowerLevelStroke = DefaultLevelStroke;
|
|
|
|
AddPlot(new Stroke(Brushes.Transparent, 0), PlotStyle.Bar, "Histogram");
|
|
}
|
|
else if (State == State.Configure)
|
|
{
|
|
if (ShowLevels)
|
|
{
|
|
AddLine(UpperLevelStroke, UpperLevel, "Upper Level");
|
|
AddLine(LowerLevelStroke, LowerLevel, "Lower Level");
|
|
}
|
|
}
|
|
else if (State == State.DataLoaded)
|
|
{
|
|
RSIValue = RSI(RSIPeriod, RSISmoothing);
|
|
}
|
|
}
|
|
|
|
protected override void OnBarUpdate()
|
|
{
|
|
if (CurrentBar < 2)
|
|
return;
|
|
|
|
double rsiHistogramValue = (RSIValue[0] - 50) * RSIModifier;
|
|
|
|
// If no change in value, use previous bar color, regardless of color scheme.
|
|
if (rsiHistogramValue == Histogram[1])
|
|
PlotBrushes[0][0] = PlotBrushes[0][1];
|
|
else
|
|
{
|
|
if ((ColorScheme == RSIHistogramColorScheme.PositiveNegative && rsiHistogramValue > 0.0) ||
|
|
(ColorScheme == RSIHistogramColorScheme.PreviousBar && rsiHistogramValue > Histogram[1]))
|
|
PlotBrushes[0][0] = PositiveBarColor;
|
|
else
|
|
PlotBrushes[0][0] = NegativeBarColor;
|
|
}
|
|
|
|
Histogram[0] = rsiHistogramValue;
|
|
}
|
|
|
|
protected override void OnRender(ChartControl chartControl, ChartScale chartScale)
|
|
{
|
|
base.OnRender(chartControl, chartScale);
|
|
|
|
foreach (Plot plot in Plots)
|
|
{
|
|
plot.Width = (float)chartControl.GetBarPaintWidth(ChartBars);
|
|
}
|
|
}
|
|
|
|
public override string DisplayName
|
|
{
|
|
get { return Name; }
|
|
}
|
|
|
|
#region Properties
|
|
[NinjaScriptProperty]
|
|
[Range(1, int.MaxValue)]
|
|
[Display(Name = "RSI Period", Description = "Period used in RSI calculation", Order = 1, GroupName = "RSI Histogram")]
|
|
public int RSIPeriod
|
|
{ get; set; }
|
|
|
|
[NinjaScriptProperty]
|
|
[Range(1, int.MaxValue)]
|
|
[Display(Name = "RSI Smoothing", Description = "Smoothing used in RSI calculation", Order = 2, GroupName = "RSI Histogram")]
|
|
public int RSISmoothing
|
|
{ get; set; }
|
|
|
|
[NinjaScriptProperty]
|
|
[Range(0.1, double.MaxValue)]
|
|
[Display(Name = "RSI Modifier", Description = "Modifier used to scale RSI calculation", Order = 3, GroupName = "RSI Histogram")]
|
|
public double RSIModifier
|
|
{ get; set; }
|
|
|
|
[PropertyEditor("NinjaTrader.Gui.Tools.StringStandardValuesEditorKey")]
|
|
[TypeConverter(typeof(RSIHistogramColorSchemeConverter))]
|
|
[Display(Name = "Color Scheme", Description = "RSI histogram coloring scheme", Order = 4, GroupName = "RSI Histogram")]
|
|
public RSIHistogramColorScheme ColorScheme
|
|
{ get; set; }
|
|
|
|
[XmlIgnore]
|
|
[Display(Name = "Positive Bar Color", Description = "Color of bars with a positive value", Order = 5, GroupName = "RSI Histogram")]
|
|
public Brush PositiveBarColor
|
|
{ get; set; }
|
|
|
|
[XmlIgnore]
|
|
[Display(Name = "Negative Bar Color", Description = "Color of bars with a negative value", Order = 6, GroupName = "RSI Histogram")]
|
|
public Brush NegativeBarColor
|
|
{ get; set; }
|
|
|
|
[Display(Name = "Show Levels", Order = 1, GroupName = "Levels")]
|
|
public bool ShowLevels
|
|
{ get; set; }
|
|
|
|
[Range(double.MinValue, double.MaxValue)]
|
|
[Display(Name = "Upper Level", Description = "Upper level in histogram", Order = 2, GroupName = "Levels")]
|
|
public double UpperLevel
|
|
{ get; set; }
|
|
|
|
[Display(Name = "Upper Level Style", Description = "Upper level displayed in histogram", Order = 3, GroupName = "Levels")]
|
|
public Stroke UpperLevelStroke
|
|
{ get; set; }
|
|
|
|
[Range(double.MinValue, double.MaxValue)]
|
|
[Display(Name = "Lower Level", Description = "Lower level in histogram", Order = 4, GroupName = "Levels")]
|
|
public double LowerLevel
|
|
{ get; set; }
|
|
|
|
[Display(Name = "Lower Level Style", Description = "Lower level displayed in histogram", Order = 5, GroupName = "Levels")]
|
|
public Stroke LowerLevelStroke
|
|
{ get; set; }
|
|
|
|
[Browsable(false)]
|
|
[XmlIgnore]
|
|
public Series<double> Histogram
|
|
{
|
|
get { return Values[0]; }
|
|
}
|
|
#endregion
|
|
}
|
|
}
|
|
|
|
public enum RSIHistogramColorScheme
|
|
{
|
|
PositiveNegative,
|
|
PreviousBar
|
|
}
|
|
|
|
public class RSIHistogramColorSchemeConverter : TypeConverter
|
|
{
|
|
private const string POSITIVE_NEGATIVE = "Above / Below 0";
|
|
private const string PREVIOUS_BAR = "Based on Previous Bar";
|
|
|
|
public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
|
|
{
|
|
List<string> values = new List<string>() { POSITIVE_NEGATIVE, PREVIOUS_BAR };
|
|
return new StandardValuesCollection(values);
|
|
}
|
|
|
|
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
|
|
{
|
|
switch (value.ToString())
|
|
{
|
|
case POSITIVE_NEGATIVE:
|
|
return RSIHistogramColorScheme.PositiveNegative;
|
|
case PREVIOUS_BAR:
|
|
return RSIHistogramColorScheme.PreviousBar;
|
|
}
|
|
return RSIHistogramColorScheme.PreviousBar;
|
|
}
|
|
|
|
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
|
|
{
|
|
RSIHistogramColorScheme enumValue = (RSIHistogramColorScheme)Enum.Parse(typeof(RSIHistogramColorScheme), value.ToString());
|
|
switch (enumValue)
|
|
{
|
|
case RSIHistogramColorScheme.PositiveNegative:
|
|
return POSITIVE_NEGATIVE;
|
|
case RSIHistogramColorScheme.PreviousBar:
|
|
return PREVIOUS_BAR;
|
|
}
|
|
return PREVIOUS_BAR;
|
|
}
|
|
|
|
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 RSIHistogram[] cacheRSIHistogram;
|
|
public RSIHistogram RSIHistogram(int rSIPeriod, int rSISmoothing, double rSIModifier)
|
|
{
|
|
return RSIHistogram(Input, rSIPeriod, rSISmoothing, rSIModifier);
|
|
}
|
|
|
|
public RSIHistogram RSIHistogram(ISeries<double> input, int rSIPeriod, int rSISmoothing, double rSIModifier)
|
|
{
|
|
if (cacheRSIHistogram != null)
|
|
for (int idx = 0; idx < cacheRSIHistogram.Length; idx++)
|
|
if (cacheRSIHistogram[idx] != null && cacheRSIHistogram[idx].RSIPeriod == rSIPeriod && cacheRSIHistogram[idx].RSISmoothing == rSISmoothing && cacheRSIHistogram[idx].RSIModifier == rSIModifier && cacheRSIHistogram[idx].EqualsInput(input))
|
|
return cacheRSIHistogram[idx];
|
|
return CacheIndicator<RSIHistogram>(new RSIHistogram(){ RSIPeriod = rSIPeriod, RSISmoothing = rSISmoothing, RSIModifier = rSIModifier }, input, ref cacheRSIHistogram);
|
|
}
|
|
}
|
|
}
|
|
|
|
namespace NinjaTrader.NinjaScript.MarketAnalyzerColumns
|
|
{
|
|
public partial class MarketAnalyzerColumn : MarketAnalyzerColumnBase
|
|
{
|
|
public Indicators.RSIHistogram RSIHistogram(int rSIPeriod, int rSISmoothing, double rSIModifier)
|
|
{
|
|
return indicator.RSIHistogram(Input, rSIPeriod, rSISmoothing, rSIModifier);
|
|
}
|
|
|
|
public Indicators.RSIHistogram RSIHistogram(ISeries<double> input , int rSIPeriod, int rSISmoothing, double rSIModifier)
|
|
{
|
|
return indicator.RSIHistogram(input, rSIPeriod, rSISmoothing, rSIModifier);
|
|
}
|
|
}
|
|
}
|
|
|
|
namespace NinjaTrader.NinjaScript.Strategies
|
|
{
|
|
public partial class Strategy : NinjaTrader.Gui.NinjaScript.StrategyRenderBase
|
|
{
|
|
public Indicators.RSIHistogram RSIHistogram(int rSIPeriod, int rSISmoothing, double rSIModifier)
|
|
{
|
|
return indicator.RSIHistogram(Input, rSIPeriod, rSISmoothing, rSIModifier);
|
|
}
|
|
|
|
public Indicators.RSIHistogram RSIHistogram(ISeries<double> input , int rSIPeriod, int rSISmoothing, double rSIModifier)
|
|
{
|
|
return indicator.RSIHistogram(input, rSIPeriod, rSISmoothing, rSIModifier);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|