Description
Improved version of Harmonic Patterns. All available patterns can be shown with only one indicator.
For Bots: Check the outputs two bars back.
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) && (!done))
{
if ((!double.IsNaN(fractals.UpFractal[l])) && (Bars.HighPrices[l] > nodeA.val))
{
if (isHarmonicNode(nodeB.val, nodeA.val, Bars.HighPrices[l], r.B, Accuracy, BEAR))
{
nodeX.index = l;
nodeX.val = Bars.HighPrices[l];
if (ShowLines)
showLines(nodeX, nodeA, nodeB, nodeC, nodeD, MINUSCOLOR, index);
if (ShowRatios)
showRatios(nodeX, nodeA, nodeB, nodeC, nodeD, BEAR, index, r);
if (ShowNodes)
showNodes(nodeX, nodeA, nodeB, nodeC, nodeD, BEAR, MINUSCOLOR, index);
if (!double.IsNaN(nodeD.val))
if (nodeD.val > 0)
Minus[nodeD.index] = nodeD.val;
done = true;
}
}
l--;
}
}
}
k--;
}
}
}
j--;
}
}
i--;
}
}
return done;
}
private bool isHarmonicNode(double lastFractalValue, double midFractalValue, double prevFractalValue, double ratio, double accuracy, int mode)
{
bool ret = false;
double lastSegmentHeight = mode == BULL ? midFractalValue - lastFractalValue : lastFractalValue - midFractalValue;
double prevSegmentHeight = mode == BULL ? midFractalValue - prevFractalValue : prevFractalValue - midFractalValue;
double calcLastSegmentHeight = prevSegmentHeight * ratio;
double margin = (lastSegmentHeight * accuracy) / 100;
if ((calcLastSegmentHeight > lastSegmentHeight - margin) && (calcLastSegmentHeight < lastSegmentHeight + margin))
ret = true;
return ret;
}
private void showLines(Node nodeX, Node nodeA, Node nodeB, Node nodeC, Node nodeD, Colors color, int index)
{
ChartObjects.DrawLine("xa_" + index + nodeX.index, nodeX.index, nodeX.val, nodeA.index, nodeA.val, color, SizeLines, LineStyle.Solid);
ChartObjects.DrawLine("ab_" + index + nodeX.index, nodeA.index, nodeA.val, nodeB.index, nodeB.val, color, SizeLines, LineStyle.Solid);
ChartObjects.DrawLine("bc_" + index + nodeX.index, nodeB.index, nodeB.val, nodeC.index, nodeC.val, color, SizeLines, LineStyle.Solid);
ChartObjects.DrawLine("cd_" + index + nodeX.index, nodeC.index, nodeC.val, nodeD.index, nodeD.val, color, SizeLines, LineStyle.Solid);
ChartObjects.DrawLine("xb_" + index + nodeX.index, nodeX.index, nodeX.val, nodeB.index, nodeB.val, color, SizeLines, LineStyle.DotsRare);
ChartObjects.DrawLine("bd_" + index + nodeX.index, nodeB.index, nodeB.val, nodeD.index, nodeD.val, color, SizeLines, LineStyle.DotsRare);
ChartObjects.DrawText("nc01_" + index + nodeX.index, NODE_DOT, nodeX.index, nodeX.val, VerticalAlignment.Center, HorizontalAlignment.Center, color);
ChartObjects.DrawText("nc02_" + index + nodeX.index, NODE_DOT, nodeA.index, nodeA.val, VerticalAlignment.Center, HorizontalAlignment.Center, color);
ChartObjects.DrawText("nc03_" + index + nodeX.index, NODE_DOT, nodeB.index, nodeB.val, VerticalAlignment.Center, HorizontalAlignment.Center, color);
ChartObjects.DrawText("nc04_" + index + nodeX.index, NODE_DOT, nodeC.index, nodeC.val, VerticalAlignment.Center, HorizontalAlignment.Center, color);
ChartObjects.DrawText("nc05_" + index + nodeX.index, NODE_DOT, nodeD.index, nodeD.val, VerticalAlignment.Center, HorizontalAlignment.Center, color);
}
private void showRatios(Node nodeX, Node nodeA, Node nodeB, Node nodeC, Node nodeD, int mode, int index, Ratios r)
{
ChartObjects.DrawText("txt01_" + index + nodeX.index, "" + r.B, nodeA.index + (nodeB.index - nodeA.index) / 2, nodeA.val - (nodeA.val - nodeB.val) / 2, mode == BULL ? VerticalAlignment.Center : VerticalAlignment.Center, mode == BULL ? HorizontalAlignment.Right : HorizontalAlignment.Left, Colors.LightGray);
ChartObjects.DrawText("txt02_" + index + nodeX.index, "" + r.C, nodeB.index + (nodeC.index - nodeB.index) / 2, nodeB.val - (nodeB.val - nodeC.val) / 2, mode == BULL ? VerticalAlignment.Top : VerticalAlignment.Center, mode == BULL ? HorizontalAlignment.Left : HorizontalAlignment.Left, Colors.LightGray);
ChartObjects.DrawText("txt03_" + index + nodeX.index, "" + r.D, nodeC.index + (nodeD.index - nodeC.index) / 2, nodeC.val - (nodeC.val - nodeD.val) / 2, mode == BULL ? VerticalAlignment.Center : VerticalAlignment.Center, mode == BULL ? HorizontalAlignment.Right : HorizontalAlignment.Right, Colors.LightGray);
}
private void showNodes(Node nodeX, Node nodeA, Node nodeB, Node nodeC, Node nodeD, int mode, Colors color, int index)
{
ChartObjects.DrawText("nd01_" + index + nodeX.index, "X", nodeX.index, nodeX.val, mode == BULL ? VerticalAlignment.Bottom : VerticalAlignment.Top, HorizontalAlignment.Center, color);
ChartObjects.DrawText("nd02_" + index + nodeX.index, "A", nodeA.index, nodeA.val, mode == BULL ? VerticalAlignment.Top : VerticalAlignment.Bottom, HorizontalAlignment.Center, color);
ChartObjects.DrawText("nd03_" + index + nodeX.index, "B", nodeB.index, nodeB.val, mode == BULL ? VerticalAlignment.Bottom : VerticalAlignment.Top, HorizontalAlignment.Center, color);
ChartObjects.DrawText("nd04_" + index + nodeX.index, "C", nodeC.index, nodeC.val, mode == BULL ? VerticalAlignment.Top : VerticalAlignment.Bottom, HorizontalAlignment.Center, color);
ChartObjects.DrawText("nd05_" + index + nodeX.index, "D", nodeD.index, nodeD.val, mode == BULL ? VerticalAlignment.Bottom : VerticalAlignment.Top, HorizontalAlignment.Center, color);
}
}
}
Abstract
Joined on 08.08.2021
- Distribution: Free
- Language: C#
- Trading platform: cTrader Automate
- File name: HarmonicsPlus.algo
- Rating: 5
- Installs: 1948
- Modified: 27/11/2021 00:18
Note that publishing copyrighted material is strictly prohibited. If you believe there is copyrighted material in this section, please use the Copyright Infringement Notification form to submit a claim.
Comments
Log in to add a comment.
No comments found.