using System;
using cAlgo.API;
using cAlgo.API.Internals;
using cAlgo.API.Indicators;
using cAlgo.Indicators;
namespace cAlgo
{
[Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class HarmonicsPlus : Indicator
{
[Parameter("Period", Group = "Setup", DefaultValue = 100, MinValue = 25)]
public int Period { get; set; }
[Parameter("Accuracy Percentage", Group = "Setup", DefaultValue = 5, MinValue = 0)]
public double Accuracy { get; set; }
[Parameter("Gartley", Group = "Harmonic Patterns", DefaultValue = true)]
public bool PatternGartley { get; set; }
[Parameter("Bat", Group = "Harmonic Patterns", DefaultValue = true)]
public bool PatternBat { get; set; }
[Parameter("AlternateBat", Group = "Harmonic Patterns", DefaultValue = true)]
public bool PatternAlternateBat { get; set; }
[Parameter("Butterfly", Group = "Harmonic Patterns", DefaultValue = true)]
public bool PatternButterfly { get; set; }
[Parameter("Crab", Group = "Harmonic Patterns", DefaultValue = true)]
public bool PatternCrab { get; set; }
[Parameter("DeepCrab", Group = "Harmonic Patterns", DefaultValue = true)]
public bool PatternDeepCrab { get; set; }
[Parameter("Show Lines", Group = "Lines", DefaultValue = true)]
public bool ShowLines { get; set; }
[Parameter("Line Size", Group = "Lines", DefaultValue = 1, MinValue = 1)]
public int SizeLines { get; set; }
[Parameter("Show Ratios", Group = "Text", DefaultValue = true)]
public bool ShowRatios { get; set; }
[Parameter("Show Nodes", Group = "Text", DefaultValue = true)]
public bool ShowNodes { get; set; }
[Output("Plus", PlotType = PlotType.Points, Thickness = 8, LineColor = "Lime")]
public IndicatorDataSeries Plus { get; set; }
[Output("Minus", PlotType = PlotType.Points, Thickness = 8, LineColor = "Magenta")]
public IndicatorDataSeries Minus { get; set; }
public struct Node
{
public int index;
public double val;
}
public struct Ratios
{
public double B;
public double C;
public double D;
}
private const int BULL = 1;
private const int BEAR = -1;
private const String NODE_DOT = "•";
private const int MAX_PATTERNS = 6;
private const int GARTLEY = 0;
private const int BAT = 1;
private const int ALTERNATEBAT = 2;
private const int BUTTERFLY = 3;
private const int CRAB = 4;
private const int DEEPCRAB = 5;
private const Colors PLUSCOLOR = Colors.Lime;
private const Colors MINUSCOLOR = Colors.Magenta;
private int lastIndex;
private Fractals fractals;
protected override void Initialize()
{
fractals = Indicators.Fractals(5);
lastIndex = -1;
}
public override void Calculate(int index)
{
if (index != lastIndex)
{
lastIndex = index;
Plus[index] = double.NaN;
Minus[index] = double.NaN;
if (index > Period + 1)
{
for (int i = 0; i < MAX_PATTERNS; i++)
{
Ratios r = getPattern(i);
if ((r.B > 0) && (r.C > 0) && (r.D > 0))
{
if (!getBullPattern(index, Period, r))
getBearPattern(index, Period, r);
}
}
}
}
}
private Ratios getPattern(int pt)
{
Ratios r;
r.B = r.C = r.D = -1;
switch (pt)
{
case GARTLEY:
if (PatternGartley)
{
r.B = 0.618;
r.C = 0.886;
r.D = 1.27;
}
break;
case BAT:
if (PatternBat)
{
r.B = 0.5;
r.C = 0.886;
r.D = 1.618;
}
break;
case ALTERNATEBAT:
if (PatternAlternateBat)
{
r.B = 0.382;
r.C = 0.886;
r.D = 3.618;
}
break;
case BUTTERFLY:
if (PatternButterfly)
{
r.B = 0.786;
r.C = 0.886;
r.D = 2.618;
}
break;
case CRAB:
if (PatternCrab)
{
r.B = 0.618;
r.C = 0.886;
r.D = 3.618;
}
break;
case DEEPCRAB:
if (PatternDeepCrab)
{
r.B = 0.886;
r.C = 0.886;
r.D = 2.618;
}
break;
}
return r;
}
private bool getBullPattern(int index, int period, Ratios r)
{
Node nodeX, nodeA, nodeB, nodeC, nodeD;
bool done = false;
int i, j, k, l;
if (!double.IsNaN(fractals.DownFractal[index - 2]))
{
nodeD.index = index - 2;
nodeD.val = Bars.LowPrices[index - 2];
i = nodeD.index - 1;
while ((i > index - Period) && (!done))
{
if ((!double.IsNaN(fractals.UpFractal[i])) && (Bars.HighPrices[i] > nodeD.val))
{
nodeC.index = i;
nodeC.val = Bars.HighPrices[i];
j = nodeC.index - 1;
while ((j > index - Period) && (!done))
{
if ((!double.IsNaN(fractals.DownFractal[j])) && (Bars.LowPrices[j] < nodeC.val))
{
if (isHarmonicNode(nodeD.val, nodeC.val, Bars.LowPrices[j], r.D, Accuracy, BULL))
{
nodeB.index = j;
nodeB.val = Bars.LowPrices[j];
k = nodeB.index - 1;
while ((k > index - Period) && (!done))
{
if ((!double.IsNaN(fractals.UpFractal[k])) && (Bars.HighPrices[k] > nodeB.val))
{
if (isHarmonicNode(nodeC.val, nodeB.val, Bars.HighPrices[k], r.C, Accuracy, BEAR))
{
nodeA.index = k;
nodeA.val = Bars.HighPrices[k];
l = nodeA.index - 1;
while ((l > index - Period) && (!done))
{
if ((!double.IsNaN(fractals.DownFractal[l])) && (Bars.LowPrices[l] < nodeA.val))
{
if (isHarmonicNode(nodeB.val, nodeA.val, Bars.LowPrices[l], r.B, Accuracy, BULL))
{
nodeX.index = l;
nodeX.val = Bars.LowPrices[l];
if (ShowLines)
showLines(nodeX, nodeA, nodeB, nodeC, nodeD, PLUSCOLOR, index);
if (ShowRatios)
showRatios(nodeX, nodeA, nodeB, nodeC, nodeD, BULL, index, r);
if (ShowNodes)
showNodes(nodeX, nodeA, nodeB, nodeC, nodeD, BULL, PLUSCOLOR, index);
if (!double.IsNaN(nodeD.val))
if (nodeD.val > 0)
Plus[nodeD.index] = nodeD.val;
done = true;
}
}
l--;
}
}
}
k--;
}
}
}
j--;
}
}
i--;
}
}
return done;
}
private bool getBearPattern(int index, int period, Ratios r)
{
Node nodeX, nodeA, nodeB, nodeC, nodeD;
bool done = false;
int i, j, k, l;
if (!double.IsNaN(fractals.UpFractal[index - 2]))
{
nodeD.index = index - 2;
nodeD.val = Bars.HighPrices[index - 2];
i = nodeD.index - 1;
while ((i > index - Period) && (!done))
{
if ((!double.IsNaN(fractals.DownFractal[i])) && (Bars.LowPrices[i] < nodeD.val))
{
nodeC.index = i;
nodeC.val = Bars.LowPrices[i];
j = nodeC.index - 1;
while ((j > index - Period) && (!done))
{
if ((!double.IsNaN(fractals.UpFractal[j])) && (Bars.HighPrices[j] > nodeC.val))
{
if (isHarmonicNode(nodeD.val, nodeC.val, Bars.HighPrices[j], r.D, Accuracy, BEAR))
{
nodeB.index = j;
nodeB.val = Bars.HighPrices[j];
k = nodeB.index - 1;
while ((k > index - Period) && (!done))
{
if ((!double.IsNaN(fractals.DownFractal[k])) && (Bars.LowPrices[k] < nodeB.val))
{
if (isHarmonicNode(nodeC.val, nodeB.val, Bars.LowPrices[k], r.C, Accuracy, BULL))
{
nodeA.index = k;
nodeA.val = Bars.LowPrices[k];
l = nodeA.index - 1;
while ((l > index - Period) && (