Category Trend  Published on 22/07/2024

Luc FVG GAP Imbalance - ICT indicator

Description

This indicator allows FVG and OB ZONES to be marked on the curve. It can superimpose LVFs from higher timeframes. It adds a 50% line in the middle of the FVG. If the FVG zone has an interrupted line, it's because the 3rd candle makes this zone more likely for an eventual price comeback.


using System;
using System.Linq;
using System.Collections.Generic;
using cAlgo.API;
using cAlgo.API.Internals;
using cAlgo.API.Indicators;

namespace cAlgo
{
    [
        Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)
    ]
    public class LucFVG : Indicator
    {
        [Parameter("Remove filled", DefaultValue = true)]
        public bool removeHistory { get; set; }
        [Parameter("Show panel", DefaultValue = true)]
        public bool showPanel { get; set; }

        [Parameter("Min Size (Pips)", Group = "FVG", DefaultValue = 0.7, MinValue = 0, Step = 0.1)]
        public double ZoneMinSizePips { get; set; }

        [Parameter("Max boxes", Group = "FVG", DefaultValue = 100, MinValue = 0, Step = 1)]
        public int ZoneMaxBoxes { get; set; }

        [Parameter("Up Color", Group = "FVG", DefaultValue = "#3A007F01")]
        public Color ZoneUpColor { get; set; }

        [Parameter("Down Color", Group = "FVG", DefaultValue = "#37FE0000")]
        public Color ZoneDownColor { get; set; }

        [Parameter("Extend #candles", Group = "FVG", DefaultValue = 0)]
        public int ZoneExtend { get; set; }

        [Parameter("Only same type of candles", DefaultValue = false, Group = "FVG")]
        public bool onlySameType { get; set; }

        [Parameter("Show 5mn FVG on minor timeframe", Group = "FVG", DefaultValue = true)]
        public bool ShowFVG5mn { get; set; }

        [Parameter("Show 15mn FVG on minor timeframe", Group = "FVG", DefaultValue = true)]
        public bool ShowFVG15mn { get; set; }

        [Parameter("Show305mn FVG on minor timeframe", Group = "FVG", DefaultValue = true)]
        public bool ShowFVG30mn { get; set; }

        [Parameter("Show 1h FVG...", Group = "FVG", DefaultValue = true)]
        public bool ShowFVG1h { get; set; }

        [Parameter("Show 4h FVG...", Group = "FVG", DefaultValue = true)]
        public bool ShowFVG4h { get; set; }

        [Parameter("Show FVG label on minor timeframe", DefaultValue = true, Group = "FVG")]
        public bool showFVGlbl { get; set; }

        [Parameter("Label Font Size", Group = "FVG", DefaultValue = 8)]
        public int lblFontSize { get; set; }

        [Parameter("Label Font Color", DefaultValue = "#A2FFFFFF", Group = "FVG")]
        public Color labelFontColor { get; set; }

        [Parameter("# fill before remove", DefaultValue = 2, MinValue = 0, Group = "FVG")]
        public int nZonesFillMax { get; set; }

        [Parameter("% overlap for remove history (0-100)", DefaultValue = 75.0, MinValue = 0.0, MaxValue = 100.0, Step = 1.0, Group = "FVG")]
        public double percentRemoveHistory { get; set; }

        [Parameter("Thickness", Group = "FVG Line", DefaultValue = 1, MinValue = 0)]
        public int ZoneLineThickness { get; set; }

        [Parameter("Style", Group = "FVG Line", DefaultValue = LineStyle.Solid)]
        public LineStyle ZoneLineStyle { get; set; }

        [Parameter("Show", Group = "FVG no Breakaway Gap", DefaultValue = true)]
        public bool showNoBreakaway { get; set; }

        [Parameter("Show OB", DefaultValue = true, Group = "Order Blocks")]
        public bool showOB { get; set; }
        [Parameter("Thickness", Group = "Order Blocks", DefaultValue = 1, MinValue = 0)]
        public int thicknessOB { get; set; }
        [Parameter("Style", Group = "Order Blocks", DefaultValue = LineStyle.Solid)]
        public LineStyle lineStyleOB { get; set; }
        [Parameter("Color", DefaultValue = "#C2013861", Group = "Order Blocks")]
        public Color colorOB { get; set; }

        [Parameter("Color", Group = "Volume Imbalance", DefaultValue = "#428A0BE8")]
        public Color VolumeImbalanceColor { get; set; }

        [Parameter("Show", Group = "Volume Imbalance", DefaultValue = true)]
        public bool showVI { get; set; }

        [Parameter("Color", Group = "Immediate Rebalance (IB)", DefaultValue = "#FF025776")]
        public Color ImmediateRebalanceColor { get; set; }

        [Parameter("Show", Group = "Immediate Rebalance (IB)", DefaultValue = true)]
        public bool showIB { get; set; }

        [Parameter("Show", Group = "Gap", DefaultValue = true)]
        public bool showGap { get; set; }

        [Parameter("Color", Group = "Gap", DefaultValue = "#99075A9B")]
        public Color colorGap { get; set; }

        [Parameter("Min size (pips)", Group = "Gap", DefaultValue = 0.01, MinValue = 0.01, Step = 0.01)]
        public double minGapSize { get; set; }

        private int _index;

        private double _zoneMinSize, _zoneMinSizeGap;

        private Bars bars15, bars30, bars1h, bars4h, bars5, barsMonthly, barsDaily, barsWeekly;

        private IndicatorDataSeries obPlaced;

        public class Zone
        {
            public string id;
            public string id_trendline;
            public string id_txt;

            public double size; // taille max non grignotée
            //public double over_size;
            public double ihigh, ilow;

            public int index;
            public int type; // 1: UP  -1:DOWN

            public int cptFull = 0;

            public double high, low;
            public DateTime lastTime;

            public TimeFrame tf;

            public string txtOB = "", idOBLine = "";

            public Zone(string _id, string _id_trendline, string _id_txt, double _high, double _low, DateTime _lastTime, int _index, int _type, TimeFrame _tf)
            {
                id = _id;
                id_trendline = _id_trendline;
                id_txt = _id_txt;
                size = _high - _low;
                //over_size = 0;
                high = _high;
                low = _low;
                lastTime = _lastTime;
                index = _index;
                type = _type;
                tf = _tf;

                ihigh = _high;
                ilow = _low;
            }
        }
        private SortedList<string, Zone> zonestf, zones5mn, zones15mn, zones30mn, zones1h, zones4h, zonesDaily, zonesMonthly, zonesWeekly;
        private int saveZoneMaxCount = 0, savenZonesFillMax = 0;

        private void displayBars(SortedList<string, Zone> zones, Bars bars, string tag, ref int lastIndex, TimeFrame timeFrame)
        {
            if (bars == null || lastIndex == bars.Count - 2 || bars.Count <= 2) return;

            for (int i = lastIndex; i <= bars.Count - 2; i++)
            {
                if (bars[i - 2].Low - bars[i].High >= _zoneMinSize)
                {
                    var IsNoBreakaway = !(showNoBreakaway && IsBreakaway(-1, bars[i - 1], bars[i]));
                    DrawGapColor(zones, tag + "Down", "FVG " + tag, bars[i].High, bars[i - 2].Low, ZoneDownColor,
                        Bars.OpenTimes.GetIndexByTime(bars[i - 2].OpenTime),
                        Bars.OpenTimes.GetIndexByTime(bars[i].OpenTime) + ZoneExtend, bars[i - 2].OpenTime, -1, IsNoBreakaway, timeFrame);
                }

                if (bars[i].Low - bars[i - 2].High >= _zoneMinSize)
                {
                    var IsNoBreakaway = !(showNoBreakaway && IsBreakaway(1, bars[i - 1], bars[i]));
                    DrawGapColor(zones, tag + "Up", "FVG " + tag, bars[i].Low, bars[i - 2].High, ZoneUpColor,
                        Bars.OpenTimes.GetIndexByTime(bars[i - 2].OpenTime),
                        Bars.OpenTimes.GetIndexByTime(bars[i].OpenTime) + ZoneExtend, bars[i - 2].OpenTime, 1, IsNoBreakaway, timeFrame);
                }

                if (removeHistory) removeHistoryBars(zones, bars, i, timeFrame);
            }
            lastIndex = bars.Count - 2;
        }

        protected override void Initialize()
        {
            init();

            _zoneMinSize = ZoneMinSizePips * Symbol.PipSize;
            _zoneMinSizeGap = minGapSize * Symbol.PipSize;

            if (ShowFVG5mn && (TimeFrame < TimeFrame.Minute5 || TimeFrame <= TimeFrame.HeikinMinute5))
            {
                Action<Bars> callback = o =>
                {
                    displayBars(zones5mn, o, "5mn", ref lastIndex5, TimeFrame.Minute5);
                    bars5 = o;
                };
                MarketData.GetBarsAsync(TimeFrame.Minute5, callback);
            }

            if (ShowFVG15mn && (TimeFrame < TimeFrame.Minute15 || TimeFrame <= TimeFrame.HeikinMinute15))
            {
                Action<Bars> callback = o =>
                {
                    displayBars(zones15mn, o, "15mn", ref lastIndex15, TimeFrame.Minute15);
                    bars15 = o;
                };
                MarketData.GetBarsAsync(TimeFrame.Minute15, callback);
            }

            if (ShowFVG30mn && (TimeFrame < TimeFrame.Minute30 || TimeFrame <= TimeFrame.HeikinMinute30))
            {
                Action<Bars> callback = o =>
                {
                    displayBars(zones30mn, o, "15mn", ref lastIndex15, TimeFrame.Minute30);
                    bars30 = o;
                };
                MarketData.GetBarsAsync(TimeFrame.Minute15, callback);
            }

            if (ShowFVG1h && (TimeFrame >= TimeFrame.Minute15 && TimeFrame < TimeFrame.Hour || TimeFrame >= TimeFrame.HeikinMinute15 && TimeFrame <= TimeFrame.HeikinHour))
            {
                Action<Bars> callback = o =>
                {
                    displayBars(zones1h, o, "1h", ref lastIndex1h, TimeFrame.Hour);
                    bars1h = o;
                };
                MarketData.GetBarsAsync(TimeFrame.Hour4, callback);
            }

            if (ShowFVG4h && (TimeFrame >= TimeFrame.Minute15 && TimeFrame < TimeFrame.Hour4 || TimeFrame >= TimeFrame.HeikinMinute15 && TimeFrame <= TimeFrame.HeikinHour4))
            {
                Action<Bars> callback = o =>
                {
                    displayBars(zones4h, o, "4h", ref lastIndex4h, TimeFrame.Hour4);
                    bars4h = o;
                };
                MarketData.GetBarsAsync(TimeFrame.Hour4, callback);
            }

            if (TimeFrame >= TimeFrame.Hour && TimeFrame < TimeFrame.Daily || TimeFrame >= TimeFrame.HeikinHour && TimeFrame <= TimeFrame.HeikinDaily)
            {
                Action<Bars> callbackDaily = o =>
                {
                    displayBars(zonesDaily, o, "Daily", ref lastIndexDaily, TimeFrame.Daily);
                    barsDaily = o;
                };
                MarketData.GetBarsAsync(TimeFrame.Daily, callbackDaily);
            }

            if (TimeFrame == TimeFrame.Weekly || TimeFrame == TimeFrame.Daily || TimeFrame == TimeFrame.HeikinWeekly || TimeFrame == TimeFrame.HeikinDaily)
            {
                Action<Bars> callbackMonthly = o =>
                {
                    displayBars(zonesMonthly, o, "Monthly", ref lastIndexMonthly, TimeFrame.Monthly);
                    barsMonthly = o;
                };
                MarketData.GetBarsAsync(TimeFrame.Monthly, callbackMonthly);
            }

            if (TimeFrame == TimeFrame.Daily || TimeFrame == TimeFrame.HeikinDaily)
            {
                Action<Bars> callbackW = o =>
                {
                    displayBars(zonesMonthly, o, "Weekly", ref lastIndexWeekly, TimeFrame.Weekly);
                    barsWeekly = o;
                };
                MarketData.GetBarsAsync(TimeFrame.Weekly, callbackW);
            }

            if (showPanel)
            {
                var stackPanel = new StackPanel
                {
                    HorizontalAlignment = HorizontalAlignment.Left,
                    VerticalAlignment = VerticalAlignment.Bottom,
                    BackgroundColor = Color.Black,
                    Opacity = 0.5,
                    Margin = 15
                };
                var checkBox = new CheckBox
                {
                    Text = "FVG Show all",
                    Margin = 2,
                    FontWeight = FontWeight.ExtraBold,
                    ForegroundColor = Color.White,
                    IsChecked = !removeHistory,
                    BackgroundColor = Color.Black
                };

                checkBox.Checked += CheckBox_Checked;
                checkBox.Unchecked += CheckBox_Unchecked;
                stackPanel.AddChild(checkBox);
                Chart.AddControl(stackPanel);
            }
        }

        private void init()
        {
            _index = -1;
            obPlaced = CreateDataSeries();
            lastIndex15 = 2;
            lastIndex5 = 2;
            lastIndex1h = 2;
            lastIndex4h = 2;
            lastIndex30 = 2;
            lastIndexZoneOB = 2;
            lastIndexMonthly = 2;
            lastIndexDaily = 2;
            lastIndexWeekly = 2;
            countIdxOBUp = 0;
            countIdxOBDOWN = 0;

            zonestf = new SortedList<string, Zone>();
            zones5mn = new SortedList<string, Zone>();
            zones15mn = new SortedList<string, Zone>();
            zones30mn = new SortedList<string, Zone>();
            zones1h = new SortedList<string, Zone>();
            zones4h = new SortedList<string, Zone>();
            zonesDaily = new SortedList<string, Zone>();
            zonesMonthly = new SortedList<string, Zone>();
            zonesWeekly = new SortedList<string, Zone>();
        }

        private void CheckBox_Checked(CheckBoxEventArgs obj)
        {
            removeHistory = false;
            saveZoneMaxCount = ZoneMaxBoxes;
            savenZonesFillMax = nZonesFillMax;
            ZoneMaxBoxes = 0;
            nZonesFillMax = 10000;
            Chart.RemoveAllObjects();
            init();
            displayOthersFVG();
            for (int i = 4; i < Bars.Count - 1; i++)
                OnBarClosed(i);
        }
        private void CheckBox_Unchecked(CheckBoxEventArgs obj)
        {
            removeHistory = true;
            ZoneMaxBoxes = saveZoneMaxCount;
            nZonesFillMax = savenZonesFillMax;
            Chart.RemoveAllObjects();
            init();
            displayOthersFVG();
            for (int i = 4; i < Bars.Count - 1; i++)
            {
                OnBarClosed(i);
            }
        }

        public override void Calculate(int index)
        {
            if (index < 4) return;

            if (_index < index)
            {
                _index = index;

                OnBarClosed(index - 1);
            }

        }

        private static int BinarySearch<Bar>(Bars list, DateTime barDate, TimeSpan offset)
        {
            int left = 0;
            int right = list.Count() - 1;

            while (left <= right)
            {
                int median = (left + right) / 2;
                DateTime dateMin = list[median].OpenTime;
                DateTime dateMax = list[median].OpenTime.Add(offset);

                if (dateMin <= barDate && barDate < dateMax)
                {
                    return median;
                }

                if (barDate < dateMin)
                {
                    right = median - 1;
                }
                else
                {
                    left = median + 1;
                }
            }

            return -1;
        }

        private void removeZone(SortedList<string, Zone> zones, int i)
        {
            Chart.RemoveObject(zones.ElementAt(i).Value.id);
            Chart.RemoveObject(zones.ElementAt(i).Value.id_trendline);
            if (zones.ElementAt(i).Value.id_txt != "") Chart.RemoveObject(zones.ElementAt(i).Value.id_txt);
            if (zones.ElementAt(i).Value.txtOB != "") Chart.RemoveObject(zones.ElementAt(i).Value.txtOB);
            if (zones.ElementAt(i).Value.idOBLine != "") Chart.RemoveObject(zones.ElementAt(i).Value.idOBLine);
            zones.RemoveAt(i);
        }

        private void displayOthersFVG()
        {
            // FVG 15mn
            if (bars15 != null)
            {
                displayBars(zones15mn, bars15, "15mn", ref lastIndex15, TimeFrame.Minute15);
            }

            // FVG 30mn
            if (bars30 != null)
            {
                displayBars(zones30mn, bars30, "30mn", ref lastIndex30, TimeFrame.Minute30);
            }

            // FVG 5mn
            if (bars5 != null)
            {
                displayBars(zones5mn, bars5, "5mn", ref lastIndex5, TimeFrame.Minute5);
            }

            // FVG 1h
            if (bars1h != null)
            {
                displayBars(zones1h, bars1h, "1h", ref lastIndex1h, TimeFrame.Hour);
            }

            // FVG 4h
            if (bars4h != null)
            {
                displayBars(zones4h, bars4h, "4h", ref lastIndex4h, TimeFrame.Hour4);
            }

            // Daily sur H1+
            if (barsDaily != null)
            {
                displayBars(zonesDaily, barsDaily, "Daily", ref lastIndexDaily, TimeFrame.Daily);
            }

            // FVG Monthly sur le weekly
            if (barsMonthly != null)
            {
                displayBars(zonesMonthly, barsMonthly, "Monthly", ref lastIndexMonthly, TimeFrame.Monthly);
            }

            // FVG Weekly sur le daily
            if (barsWeekly != null)
            {
                displayBars(zonesWeekly, barsWeekly, "Weekly", ref lastIndexWeekly, TimeFrame.Weekly);
            }
        }

        private void removeHistoryBars(SortedList<string, Zone> zones, Bars bar, int index, TimeFrame tf)
        {
            var currentTime = bar[index].OpenTime;

            for (int i = zones.Count - 1; i >= 0; i--)
            {
                if (currentTime <= zones.ElementAt(i).Value.lastTime) continue;

                if (Math.Min(bar[index].Close, bar[index].Open) <= zones.ElementAt(i).Value.ilow && Math.Max(bar[index].Close, bar[index].Open) >= zones.ElementAt(i).Value.ihigh)
                {
                    zones.ElementAt(i).Value.cptFull++;
                    zones.ElementAt(i).Value.ihigh = zones.ElementAt(i).Value.high;
                    zones.ElementAt(i).Value.ilow = zones.ElementAt(i).Value.low;
                }
                else
                    if (zones.ElementAt(i).Value.ihigh >= Math.Min(bar[index].Close, bar[index].Open) && Math.Min(bar[index].Close, bar[index].Open) >= zones.ElementAt(i).Value.ilow)
                {
                    zones.ElementAt(i).Value.ihigh = Math.Min(bar[index].Close, bar[index].Open);
                    if (zones.ElementAt(i).Value.ilow >= zones.ElementAt(i).Value.ihigh)
                    {
                        zones.ElementAt(i).Value.cptFull++;
                        zones.ElementAt(i).Value.ihigh = zones.ElementAt(i).Value.high;
                        zones.ElementAt(i).Value.ilow = zones.ElementAt(i).Value.low;
                    }
                    else
                    {
                        if (percentRemoveHistory > 0.0)
                        {
                            if ((1 - (zones.ElementAt(i).Value.ihigh - zones.ElementAt(i).Value.ilow) / (zones.ElementAt(i).Value.high - zones.ElementAt(i).Value.low)) * 100.0 >= percentRemoveHistory)
                                zones.ElementAt(i).Value.cptFull++;
                        }
                    }
                }
                else
                    if (zones.ElementAt(i).Value.ihigh >= Math.Max(bar[index].Close, bar[index].Open) && Math.Max(bar[index].Close, bar[index].Open) >= zones.ElementAt(i).Value.ilow)
                {
                    zones.ElementAt(i).Value.ilow = Math.Max(bar[index].Close, bar[index].Open);
                    if (zones.ElementAt(i).Value.ilow >= zones.ElementAt(i).Value.ihigh)
                    {
                        zones.ElementAt(i).Value.cptFull++;
                        zones.ElementAt(i).Value.ihigh = zones.ElementAt(i).Value.high;
                        zones.ElementAt(i).Value.ilow = zones.ElementAt(i).Value.low;
                    }
                    else
                    {
                        if (percentRemoveHistory > 0.0)
                        {
                            if ((1 - (zones.ElementAt(i).Value.ihigh - zones.ElementAt(i).Value.ilow) / (zones.ElementAt(i).Value.high - zones.ElementAt(i).Value.low)) * 100.0 >= percentRemoveHistory)
                                zones.ElementAt(i).Value.cptFull++;
                        }
                    }
                }


                if (zones.ElementAt(i).Value.cptFull > 0 && zones.ElementAt(i).Value.cptFull >= nZonesFillMax)
                {
                    removeZone(zones, i);
                }

            }
        }

        private bool IsBreakaway(int sens, Bar bar1, Bar bar0)
        {
            return (sens == -1) && Math.Min(bar0.Close, bar0.Open) >= bar1.Low || (sens == 1) && Math.Max(bar0.Close, bar0.Open) <= bar1.High;
        }

        private int lastIndex15 = 2, lastIndex5 = 2, lastIndex30 = 2, lastIndex1h = 2, lastIndex4h = 2, lastIndexZoneOB = 2, lastIndexMonthly = 2, lastIndexDaily = 2, lastIndexWeekly = 2;
        private int countIdxOBUp = 0, countIdxOBDOWN = 0;
        private void OnBarClosed(int index)
        {
            displayOthersFVG();
            //if (TimeFrame <= TimeFrame.Minute2) return;

            var bars = new[] { Bars[index], Bars[index - 1], Bars[index - 2] };

            if (removeHistory)
            {
                removeHistoryBars(zonestf, Bars, index, TimeFrame);
            }

            // Volume Imbalance
            if (showVI && TimeFrame > TimeFrame.Minute)
            {
                var hautCandle1 = Math.Max(Bars[index - 1].Close, Bars[index - 1].Open);
                var basCandle0 = Math.Min(Bars[index].Close, Bars[index].Open);
                if (hautCandle1 < basCandle0 && Bars[index].Low <= Bars[index - 1].High && basCandle0 - hautCandle1 >= _zoneMinSize) // && Bars[index].Low >= hautCandle1 && Bars[index-1].High <= basCandle0)
                {
                    DrawGapColor(zonestf, "vb-up-zone", "", basCandle0, hautCandle1, VolumeImbalanceColor, index - 1, index + ZoneExtend, Bars[index - 1].OpenTime, 0);
                }

                var basCandle1 = Math.Min(Bars[index - 1].Close, Bars[index - 1].Open);
                var hautCandle2 = Math.Max(Bars[index].Close, Bars[index].Open);
                if (basCandle1 > hautCandle2 && Bars[index - 1].Low <= Bars[index].High && basCandle1 - hautCandle2 >= _zoneMinSize) // && Bars[index-1].Low >= hautCandle2 && Bars[index].High <= basCandle1)
                {
                    DrawGapColor(zonestf, "vb-down-zone", "", basCandle1, hautCandle2, VolumeImbalanceColor, index - 1, index + ZoneExtend, Bars[index - 1].OpenTime, 0);
                }
            }

            // GAP
            if (showGap && (TimeFrame > TimeFrame.Minute || TimeFrame > TimeFrame.HeikinMinute))
            {
                if (Bars[index].Low > Bars[index - 1].High && Bars[index].Low - Bars[index - 1].High >= _zoneMinSizeGap)
                {
                    DrawGapColor(zonestf, "gap-up-zone", "Gap", Bars[index].Low, Bars[index - 1].High, colorGap, index - 1, index + ZoneExtend, Bars[index].OpenTime, 0, true, TimeFrame);
                }
                if (bars[0].High < bars[1].Low && bars[1].Low - bars[0].High >= _zoneMinSizeGap)
                {
                    DrawGapColor(zonestf, "gap-down-zone", "Gap", bars[1].Low, bars[0].High, colorGap, index - 1, index + ZoneExtend, bars[0].OpenTime, 0, true, TimeFrame);
                }
            }

            // FVG
            if (bars[2].Low - bars[0].High >= _zoneMinSize && (!onlySameType || bars[2].Close < bars[2].Open && bars[1].Close < bars[1].Open && bars[0].Close < bars[0].Open) && TimeFrame > TimeFrame.Minute)
            {
                //var IsNoBreakaway = !(showNoBreakaway && Math.Min(bars[1].Close, bars[1].Open) <= Math.Max(bars[0].Close, bars[0].Open));        
                var IsNoBreakaway = !(showNoBreakaway && IsBreakaway(-1, bars[1], bars[0]));
                DrawGapColor(zonestf, "b-down-zone", "", bars[0].High, bars[2].Low, ZoneDownColor, index - 2, index + ZoneExtend, bars[2].OpenTime, -1, IsNoBreakaway, TimeFrame);
            }

            if (bars[0].Low - bars[2].High >= _zoneMinSize && (!onlySameType || bars[2].Close > bars[2].Open && bars[1].Close > bars[1].Open && bars[0].Close > bars[0].Open) && TimeFrame > TimeFrame.Minute)
            {
                //var IsNoBreakaway = !(showNoBreakaway && Math.Max(bars[1].Close, bars[1].Open) >= Math.Min(bars[0].Close, bars[0].Open));
                var IsNoBreakaway = !(showNoBreakaway && IsBreakaway(1, bars[1], bars[0]));
                DrawGapColor(zonestf, "b-up-zone", "", bars[0].Low, bars[2].High, ZoneUpColor, index - 2, index + ZoneExtend, bars[2].OpenTime, 1, IsNoBreakaway, TimeFrame);
            }


            // Immediate Rebalance
            if (showIB && Math.Abs(bars[1].Open - bars[1].Close) >= 0.6 * Math.Abs(bars[1].High - bars[1].Low) && (TimeFrame > TimeFrame.Minute || TimeFrame > TimeFrame.HeikinMinute))
            {
                var hautCandle1 = Math.Max(bars[2].Close, bars[2].Open); // bougie basse à gauche
                var basCandle2 = Math.Min(bars[0].Close, bars[0].Open); // bougie plus haute à droite
                if (hautCandle1 < basCandle2 && bars[2].High > bars[0].Low && bars[2].High != Math.Max(bars[2].Close, bars[2].Open) && bars[0].Low != Math.Min(bars[0].Close, bars[0].Open)
                    && bars[2].High < basCandle2 && bars[0].Low > hautCandle1
                    )//&& bars[2].Open<bars[2].Close && bars[0].Open<bars[0].Close)
                {
                    var median = bars[2].High;
                    if (true)
                    {
                        Chart.DrawTrendLine("line_ImReb_up" + index, index - 2, median, index, median, ImmediateRebalanceColor,
                            ZoneLineThickness, ZoneLineStyle);
                        var lbl = Chart.DrawText("Txt_ImbReb_up_" + index, "IReb", index - 2, median, ImmediateRebalanceColor);
                        lbl.FontSize = lblFontSize;
                        lbl.VerticalAlignment = VerticalAlignment.Center;
                        lbl.HorizontalAlignment = HorizontalAlignment.Left;
                    }
                }

                var basCandle1 = Math.Min(bars[2].Close, bars[2].Open); // bougie haute
                var hautCandle2 = Math.Max(bars[0].Close, bars[0].Open); // bougie basse
                if (basCandle1 > hautCandle2 && bars[2].Low < bars[0].High && bars[2].Low != Math.Min(bars[2].Close, bars[2].Open) && bars[0].High != Math.Max(bars[0].Close, bars[0].Open)
                    && bars[2].Low > hautCandle2 && bars[0].High < basCandle1
                    )//&& bars[2].Close<bars[2].Open && bars[0].Close<bars[0].Open)
                {
                    var median = bars[2].Low;
                    Chart.DrawTrendLine("line_ImReb_down" + index, index - 2, median, index, median, ImmediateRebalanceColor, ZoneLineThickness, ZoneLineStyle);
                    var lbl = Chart.DrawText("Txt_ImbReb_down_" + index, "IReb", index - 2, median, ImmediateRebalanceColor);
                    lbl.FontSize = lblFontSize;
                    lbl.VerticalAlignment = VerticalAlignment.Center;
                    lbl.HorizontalAlignment = HorizontalAlignment.Left;
                }
            }

            // OB
            if (showOB && zonestf.Count > 0)
            {
                if (zonestf.ElementAt(zonestf.Count - 1).Value.index != lastIndexZoneOB)
                {

                    for (int i = zonestf.Count - 1; i >= 0; i--)
                    {

                        if (zonestf.ElementAt(i).Value.index == 0) continue; // FVG d'un autre timeframe ou pas faire de OB dessus
                        if (zonestf.ElementAt(i).Value.tf != TimeFrame) continue;

                        if (zonestf.ElementAt(i).Value.index <= lastIndexZoneOB || zonestf.ElementAt(i).Value.txtOB != "") break; // arrivé sur la dernière faite

                        // on est sur le FVG du timeframe à analyser, chercher la bougie dans l'autre sens
                        for (int j = zonestf.ElementAt(i).Value.index - 1; j >= 0; j--)
                        {
                            //if (zones[i].index-j>6) break;
                            // UP
                            if (zonestf.ElementAt(i).Value.type == 1)
                            {
                                if (obPlaced[j] == 1) break; // tombé sur un OB ?

                                // tant qu'on a une bougie pareil on descend
                                if (Bars[j].Close > Bars[j].Open) continue;

                                // trop haute ?
                                //if (Bars[j].Open > Bars[zones.ElementAt(i).Value.index].High) break;
                                var proportionFactor = 0.45;
                                var proportion = Math.Abs(Bars[j].Open - Bars[j].Close) / (Bars[j].High - Bars[j].Low - Math.Abs(Bars[j].Open - Bars[j].Close));
                                if (proportion < proportionFactor) break;

                                // vérifier si la barre d'avant est ok et au dessus pour prendre son close
                                if (j > 0 && Bars[j - 1].Open > Bars[j - 1].Close && Bars[j - 1].Open <= zonestf.ElementAt(i).Value.high)
                                {
                                    proportion += Math.Abs(Bars[j - 1].Open - Bars[j - 1].Close) / (Bars[j - 1].High - Bars[j - 1].Low - Math.Abs(Bars[j - 1].Open - Bars[j - 1].Close));
                                    if (proportion >= proportionFactor)
                                    {
                                        j--;
                                        if (obPlaced[j] == 1) break;

                                        if (j > 0 && Bars[j - 1].Open > Bars[j - 1].Close && Bars[j - 1].Open <= zonestf.ElementAt(i).Value.high)
                                        {
                                            proportion += Math.Abs(Bars[j - 1].Open - Bars[j - 1].Close) / (Bars[j - 1].High - Bars[j - 1].Low - Math.Abs(Bars[j - 1].Open - Bars[j - 1].Close));
                                            if (proportion >= proportionFactor)
                                            {
                                                j--;
                                                if (obPlaced[j] == 1) break;

                                                if (j > 0 && Bars[j - 1].Open > Bars[j - 1].Close && Bars[j - 1].Open <= zonestf.ElementAt(i).Value.high && proportion >= proportionFactor)
                                                {
                                                    proportion += Math.Abs(Bars[j - 1].Open - Bars[j - 1].Close) / (Bars[j - 1].High - Bars[j - 1].Low - Math.Abs(Bars[j - 1].Open - Bars[j - 1].Close));
                                                    if (proportion >= proportionFactor)
                                                    {
                                                        j--;
                                                        if (obPlaced[j] == 1) break;

                                                        if (j > 0 && Bars[j - 1].Open > Bars[j - 1].Close && Bars[j - 1].Open <= zonestf.ElementAt(i).Value.high && proportion >= proportionFactor)
                                                        {
                                                            proportion += Math.Abs(Bars[j - 1].Open - Bars[j - 1].Close) / (Bars[j - 1].High - Bars[j - 1].Low - Math.Abs(Bars[j - 1].Open - Bars[j - 1].Close));
                                                            if (proportion >= proportionFactor)
                                                            {
                                                                j--;
                                                                if (obPlaced[j] == 1) break;
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }

                                var idxMod = countIdxOBUp;
                                if (ZoneMaxBoxes != 0) idxMod %= ZoneMaxBoxes;
                                countIdxOBUp++;

                                Chart.DrawTrendLine("OB+" + idxMod, j, Bars[j].Open, zonestf.ElementAt(i).Value.index + ZoneExtend + 2, Bars[j].Open, colorOB, thicknessOB, lineStyleOB);
                                zonestf.ElementAt(i).Value.idOBLine = "OB+" + idxMod;

                                obPlaced[j] = 1;

                                var lbl = Chart.DrawText("Txt_OB_UP_" + idxMod, "OB+", zonestf.ElementAt(i).Value.index + ZoneExtend + 2, Bars[j].Open, labelFontColor);
                                lbl.FontSize = lblFontSize;
                                lbl.VerticalAlignment = VerticalAlignment.Center;
                                lbl.HorizontalAlignment = HorizontalAlignment.Right;
                                zonestf.ElementAt(i).Value.txtOB = "Txt_OB_UP_" + idxMod;

                                break;
                            }

                            // Down
                            if (zonestf.ElementAt(i).Value.type == -1)
                            {
                                if (obPlaced[j] == 1) break; // tombé sur un OB ?

                                // tant qu'on a une bougie pareil on descend
                                if (Bars[j].Close < Bars[j].Open) continue;

                                // trop basse ?
                                //if (Bars[j].Open < zones.ElementAt(i).Value.low) break;
                                var proportionFactor = 0.45;
                                var proportion = Math.Abs(Bars[j].Open - Bars[j].Close) / (Bars[j].High - Bars[j].Low - Math.Abs(Bars[j].Open - Bars[j].Close));
                                if (proportion < proportionFactor) break;


                                if (j > 0 && Bars[j - 1].Close > Bars[j - 1].Open && Bars[j - 1].Open >= zonestf.ElementAt(i).Value.low && Bars[j - 1].Open >= zonestf.ElementAt(i).Value.low)
                                {
                                    proportion += Math.Abs(Bars[j - 1].Open - Bars[j - 1].Close) / (Bars[j - 1].High - Bars[j - 1].Low - Math.Abs(Bars[j - 1].Open - Bars[j - 1].Close));
                                    if (proportion >= proportionFactor)
                                    {
                                        j--;
                                        if (obPlaced[j] == 1) break;

                                        if (j > 0 && Bars[j - 1].Close > Bars[j - 1].Open && Bars[j - 1].Open >= zonestf.ElementAt(i).Value.low && Bars[j - 1].Open >= zonestf.ElementAt(i).Value.low)
                                        {
                                            proportion += Math.Abs(Bars[j - 1].Open - Bars[j - 1].Close) / (Bars[j - 1].High - Bars[j - 1].Low - Math.Abs(Bars[j - 1].Open - Bars[j - 1].Close));
                                            if (proportion >= proportionFactor)
                                            {
                                                j--;
                                                if (obPlaced[j] == 1) break;

                                                if (j > 0 && Bars[j - 1].Close > Bars[j - 1].Open && Bars[j - 1].Open >= zonestf.ElementAt(i).Value.low && Bars[j - 1].Open >= zonestf.ElementAt(i).Value.low)
                                                {
                                                    proportion += Math.Abs(Bars[j - 1].Open - Bars[j - 1].Close) / (Bars[j - 1].High - Bars[j - 1].Low - Math.Abs(Bars[j - 1].Open - Bars[j - 1].Close));
                                                    if (proportion >= proportionFactor)
                                                    {
                                                        j--;
                                                        if (obPlaced[j] == 1) break;

                                                        if (j > 0 && Bars[j - 1].Close > Bars[j - 1].Open && Bars[j - 1].Open >= zonestf.ElementAt(i).Value.low && Bars[j - 1].Open >= zonestf.ElementAt(i).Value.low)
                                                        {
                                                            proportion += Math.Abs(Bars[j - 1].Open - Bars[j - 1].Close) / (Bars[j - 1].High - Bars[j - 1].Low - Math.Abs(Bars[j - 1].Open - Bars[j - 1].Close));
                                                            if (proportion >= proportionFactor)
                                                            {
                                                                j--;
                                                                if (obPlaced[j] == 1) break;
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }

                                var idxMod = countIdxOBDOWN;
                                if (ZoneMaxBoxes != 0) idxMod = countIdxOBDOWN % ZoneMaxBoxes;
                                countIdxOBDOWN++;

                                Chart.DrawTrendLine("OB-" + idxMod, j, Bars[j].Open, zonestf.ElementAt(i).Value.index + ZoneExtend + 2, Bars[j].Open, colorOB, thicknessOB, lineStyleOB);
                                zonestf.ElementAt(i).Value.idOBLine = "OB-" + idxMod;

                                obPlaced[j] = 1;

                                var lbl = Chart.DrawText("Txt_OB_DOWN_" + idxMod, "OB-", zonestf.ElementAt(i).Value.index + ZoneExtend + 2, Bars[j].Open, labelFontColor);
                                lbl.FontSize = lblFontSize;
                                lbl.VerticalAlignment = VerticalAlignment.Center;
                                lbl.HorizontalAlignment = HorizontalAlignment.Right;
                                zonestf.ElementAt(i).Value.txtOB = "Txt_OB_DOWN_" + idxMod;
                                break;

                            }
                        }

                        break;// for i sur les zones
                    }

                    lastIndexZoneOB = zonestf.ElementAt(zonestf.Count - 1).Value.index != 0 ? zonestf.ElementAt(zonestf.Count - 1).Value.index : lastIndexZoneOB;
                }
            }
        }


        private void DrawGapColor(SortedList<string, Zone> zones, string tag, string label, double y1, double y2, Color color, int time1, int time2, DateTime dTime2, int type, bool isNoBreakaway = true, TimeFrame tf = null)
        {
            tag = dTime2.ToString() + "_" + tag;
            if (ZoneMaxBoxes > 0 && zones.Count >= ZoneMaxBoxes)
                removeZone(zones, 0);

            var median = (y1 + y2) / 2;
            var line = Chart.DrawTrendLine("line_" + tag, time1, median, time2, median, color, ZoneLineThickness, ZoneLineStyle);
            line.ExtendToInfinity = false;

            var zoneRect = Chart.DrawRectangle("zone_" + tag, time1, y1, time2, y2, color, !isNoBreakaway ? 2 : 0, LineStyle.Lines);
            zoneRect.IsFilled = true;
            zoneRect.ZIndex = 300;

            var h = y1 > y2 ? y1 : y2;
            var l = y1 > y2 ? y2 : y1;

            string txt = "";
            if (showFVGlbl && label != "")
            {
                var lbl = Chart.DrawText("Txt_" + tag, label, time1, h, labelFontColor);
                lbl.FontSize = lblFontSize;
                txt = "Txt_" + tag;
                lbl.VerticalAlignment = VerticalAlignment.Bottom;
                lbl.HorizontalAlignment = HorizontalAlignment.Right;
            }

            if (zones.ContainsKey("zone_" + tag))
                removeZone(zones, zones.IndexOfKey("zone_" + tag));
            zones.Add("zone_" + tag, new Zone("zone_" + tag, "line_" + tag, txt, h, l, dTime2, time1, type, tf));
        }
    }
}


LB
lbellego

Joined on 20.06.2024

  • Distribution: Free
  • Language: C#
  • Trading platform: cTrader Automate
  • File name: Luc FVG_withSourceCode.algo
  • Rating: 5
  • Installs: 744
  • Modified: 22/07/2024 15:15
Comments
Log in to add a comment.
BO
boanders266 · 2 months ago

Very nice indicators you make, thank very much!