Category Trend  Published on 02/12/2021

Harmonics Plus

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's avatar
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
Comments
Log in to add a comment.
No comments found.