Swing indicator
Can Ninjatrader(7) "Swing" indicator be added for Tradovate (?).
Draws a line at the highs and lows at x number of bars (ie: 5 or 10 or 20 etc) depending on "strength" selected in indicator properties. Many thanks.
Please see image:-

And NT7 code:-
public class Swing : Indicator
{
#region Variables
private double currentSwingHigh = 0;
private double currentSwingLow = 0;
private ArrayList lastHighCache;
private double lastSwingHighValue = 0;
private ArrayList lastLowCache;
private double lastSwingLowValue = 0;
private int saveCurrentBar = -1;
private int strength = 5;
private DataSeries swingHighSeries;
private DataSeries swingHighSwings;
private DataSeries swingLowSeries;
private DataSeries swingLowSwings;
#endregion
/// This method is used to configure the indicator and is called once before any bar data is loaded.
protected override void Initialize()
{
Add(new Plot(Color.Green, PlotStyle.Dot, "Swing high"));
Add(new Plot(Color.Orange, PlotStyle.Dot, "Swing low"));
Plots[0].Pen.Width = 2;
Plots[0].Pen.DashStyle = DashStyle.Dot;
Plots[1].Pen.Width = 2;
Plots[1].Pen.DashStyle = DashStyle.Dot;
lastHighCache = new ArrayList();
lastLowCache = new ArrayList();
swingHighSeries = new DataSeries(this);
swingHighSwings = new DataSeries(this);
swingLowSeries = new DataSeries(this);
swingLowSwings = new DataSeries(this);
DisplayInDataBox = false;
PaintPriceMarkers = false;
Overlay = true;
}
/// Called on each bar update event (incoming tick)
protected override void OnBarUpdate()
{
if (saveCurrentBar != CurrentBar)
{
swingHighSwings.Set(0); // initializing important internal
swingLowSwings.Set(0); // initializing important internal
swingHighSeries.Set(0); // initializing important internal
swingLowSeries.Set(0); // initializing important internal
lastHighCache.Add(High[0]);
if (lastHighCache.Count > (2 * strength) + 1)
lastHighCache.RemoveAt(0);
lastLowCache.Add(Low[0]);
if (lastLowCache.Count > (2 * strength) + 1)
lastLowCache.RemoveAt(0);
if (lastHighCache.Count == (2 * strength) + 1)
{
bool isSwingHigh = true;
double swingHighCandidateValue = (double) lastHighCache[strength];
for (int i=0; i < strength; i++)
if ((double) lastHighCache[i] >= swingHighCandidateValue - double.Epsilon)
isSwingHigh = false;
for (int i=strength+1; i < lastHighCache.Count; i++)
if ((double) lastHighCache[i] > swingHighCandidateValue - double.Epsilon)
isSwingHigh = false;
swingHighSwings.Set(strength, isSwingHigh ? swingHighCandidateValue : 0.0);
if (isSwingHigh)
lastSwingHighValue = swingHighCandidateValue;
if (isSwingHigh)
{
currentSwingHigh = swingHighCandidateValue;
for (int i=0; i <= strength; i++)
SwingHighPlot.Set(i, currentSwingHigh);
}
else if (High[0] > currentSwingHigh)
{
currentSwingHigh = 0.0;
SwingHighPlot.Reset();
}
else
SwingHighPlot.Set(currentSwingHigh);
if (isSwingHigh)
{
for (int i=0; i<=strength; i++)
swingHighSeries.Set(i, lastSwingHighValue);
}
else
{
swingHighSeries.Set(lastSwingHighValue);
}
}
if (lastLowCache.Count == (2 * strength) + 1)
{
bool isSwingLow = true;
double swingLowCandidateValue = (double) lastLowCache[strength];
for (int i=0; i < strength; i++)
if ((double) lastLowCache[i] <= swingLowCandidateValue + double.Epsilon)
isSwingLow = false;
for (int i=strength+1; i < lastLowCache.Count; i++)
if ((double) lastLowCache[i] < swingLowCandidateValue + double.Epsilon)
isSwingLow = false;
swingLowSwings.Set(strength, isSwingLow ? swingLowCandidateValue : 0.0);
if (isSwingLow)
lastSwingLowValue = swingLowCandidateValue;
if (isSwingLow)
{
currentSwingLow = swingLowCandidateValue;
for (int i=0; i <= strength; i++)
SwingLowPlot.Set(i, currentSwingLow);
}
else if (Low[0] < currentSwingLow)
{
currentSwingLow = double.MaxValue;
SwingLowPlot.Reset();
}
else
SwingLowPlot.Set(currentSwingLow);
if (isSwingLow)
{
for (int i=0; i<=strength; i++)
swingLowSeries.Set(i, lastSwingLowValue);
}
else
{
swingLowSeries.Set(lastSwingLowValue);
}
}
saveCurrentBar = CurrentBar;
}
else
{
if (High[0] > High[strength] && swingHighSwings[strength] > 0.0)
{
swingHighSwings.Set(strength, 0.0);
for (int i=0; i<=strength; i++)
SwingHighPlot.Reset(i);
currentSwingHigh = 0.0;
}
else if (High[0] > High[strength] && currentSwingHigh != 0.0)
{
SwingHighPlot.Reset();
currentSwingHigh = 0.0;
}
else if (High[0] <= currentSwingHigh)
SwingHighPlot.Set(currentSwingHigh);
if (Low[0] < Low[strength] && swingLowSwings[strength] > 0.0)
{
swingLowSwings.Set(strength, 0.0);
for (int i=0; i<=strength; i++)
SwingLowPlot.Reset(i);
currentSwingLow = double.MaxValue;
}
else if (Low[0] < Low[strength] && currentSwingLow != double.MaxValue)
{
SwingLowPlot.Reset();
currentSwingLow = double.MaxValue;
}
else if (Low[0] >= currentSwingLow)
SwingLowPlot.Set(currentSwingLow);
}
}
#region Functions
/// Returns the number of bars ago a swing low occurred. Returns a value of -1 if a swing low is not found within the look back period.
/// <param name="barsAgo"></param>
/// <param name="instance"></param>
/// <param name="lookBackPeriod"></param>
/// <returns></returns>
public int SwingLowBar(int barsAgo, int instance, int lookBackPeriod)
{
if (instance < 1)
throw new Exception(GetType().Name + ".SwingLowBar: instance must be greater/equal 1 but was " + instance);
else if (barsAgo < 0)
throw new Exception(GetType().Name + ".SwingLowBar: barsAgo must be greater/equal 0 but was " + barsAgo);
else if (barsAgo >= Count)
throw new Exception(GetType().Name + ".SwingLowBar: barsAgo out of valid range 0 through " + (Count - 1) + ", was " + barsAgo + ".");
Update();
for (int idx=CurrentBar - barsAgo - strength; idx >= CurrentBar - barsAgo - strength - lookBackPeriod; idx--)
{
if (idx < 0)
return -1;
if (idx >= swingLowSwings.Count)
continue;
if (swingLowSwings.Get(idx).Equals(0.0))
continue;
if (instance == 1) // 1-based, < to be save
return CurrentBar - idx;
instance--;
}
return -1;
}
/// Returns the number of bars ago a swing high occurred. Returns a value of -1 if a swing high is not found within the look back period.
/// <param name="barsAgo"></param>
/// <param name="instance"></param>
/// <param name="lookBackPeriod"></param>
/// <returns></returns>
public int SwingHighBar(int barsAgo, int instance, int lookBackPeriod)
{
if (instance < 1)
throw new Exception(GetType().Name + ".SwingHighBar: instance must be greater/equal 1 but was " + instance);
else if (barsAgo < 0)
throw new Exception(GetType().Name + ".SwingHighBar: barsAgo must be greater/equal 0 but was " + barsAgo);
else if (barsAgo >= Count)
throw new Exception(GetType().Name + ".SwingHighBar: barsAgo out of valid range 0 through " + (Count - 1) + ", was " + barsAgo + ".");
Update();
for (int idx=CurrentBar - barsAgo - strength; idx >= CurrentBar - barsAgo - strength - lookBackPeriod; idx--)
{
if (idx < 0)
return -1;
if (idx >= swingHighSwings.Count)
continue;
if (swingHighSwings.Get(idx).Equals(0.0))
continue;
if (instance <= 1) // 1-based, < to be save
return CurrentBar - idx;
instance--;
}
return -1;
}
#endregion
#region Properties
[Description("Number of bars required on each side of the swing point.")]
[GridCategory("Parameters")]
public int Strength
{
get { return strength; }
set { strength = Math.Max(1, value); }
}
/// Gets the high swings.
/// </summary>
[Browsable(false)]
[XmlIgnore()]
public DataSeries SwingHigh
{
get
{
Update();
return swingHighSeries;
}
}
private DataSeries SwingHighPlot
{
get
{
Update();
return Values[0];
}
}
/// Gets the low swings.
[Browsable(false)]
[XmlIgnore()]
public DataSeries SwingLow
{
get
{
Update();
return swingLowSeries;
}
}
private DataSeries SwingLowPlot
{
get
{
Update();
return Values[1];
}
}
#endregion
-
Tiki Dave..Greetings.
Thanks for taking the time to reply.
I've attached a Tradovate and NT 15min chart side by side to compare the Price Channel (no Middle line plotted) with the NT Swing Indicator, both set to 5.
Thanks for the Price Channel indicator example.
I see it's plotting a continuous line connecting the H's and one for the L's which makes it look (to me) that every HH and every LL is being plotted.
The NT Swing Indicator only plots at H's and L's determined by the indicator strength (5 in this case)
The Price Channel indicator may well be doing the same but visually doesn;t look like it. (to me atleast)
I suppose I'm used to the NT version.
If possible, my preference would be to elimintate the the "continuous connecting line"
Again my thanks,
Please sign in to leave a comment.


Comments
3 comments