Warning! This section will be deprecated on February 1st 2025. Please move all your Indicators to the cTrader Store catalogue.
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: 2048
- 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.