Fibonacci compression
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © Greg_007

//@version=5
indicator(title="Fibonacci compression" , shorttitle="Fib compression", overlay=true)
var length = input.int(300, title="How many bars to look back?")
min_length = 50
bool searchBull = input.bool(true, title="Search for bullish structures, uncheck for bearish")
int version = input.int(1,"Version", options=[1,2])
float RRR = input.float(3.0, "Risk to reward based on statistics to hit TP1 (only in version 2)")
float fib1 = input.float(defval=0.786, title="Minumum fib level for 2nd leg", options=[0.786,0.618])
float fib2 = input.float(0.618, title="Minumum fib level for 3rd leg")
float fib3 = input.float(0.618, title="Minumum fib level for 4th leg")
float fib4 = input.float(defval=0.5, title="Minumum fib level for 5th leg", options=[0.5,0.382,0.236])
color lblTxtCol = input.color(defval = color.yellow, title = "Text color labels")
float high1 = 0.0
float high2 = 0.0
float high3 = 0.0
float low1 = 0.0
float low2 = 0.0
float low3 = 0.0
arr_all_highs = array.new_float(length, 0)  //will contain the highs
arr_all_lows = array.new_float(length, 0) //will contain the lows
arr_cumul_vol = array.new_float(length, 0) //will contain the cumulative volume

//temporary arrays
b = array.new_float()
c = array.new_float()
d = array.new_float()
e = array.new_float()
f = array.new_float()
int positionH1 = 0
int positionH2 = 0
int positionH3 = 0
int positionL1 = 0
int positionL2 = 0
int positionL3 = 0
var cumVol = 0.0
float cumVolH1 = 0.0
float cumVolH2 = 0.0
float cumVolH3 = 0.0
float cumVolL1 = 0.0
float cumVolL2 = 0.0
float cumVolL3 = 0.0
label l_nothingFound = na
label l_H1 = na
label l_H2 = na
label l_H3 = na
label l_L1 = na
label l_L2 = na
label l_L3 = na
label l_info = na
label l_optiEntry = na
label SLLabel = na
label.delete(l_H1)
label.delete(l_H2)
label.delete(l_H3)
label.delete(l_L1)
label.delete(l_L2)
label.delete(l_L3)
label.delete(l_info)
label.delete(l_optiEntry)
label.delete(SLLabel)
line stoploss = na
line.delete(stoploss)

//FUNCTIONS
drawPivotLines(H, posH, L, posL) =>
    pivotLine = line.new(bar_index - length + posH + 1, H, bar_index - length + posL + 1, L, color = color.purple)
    line.delete(pivotLine[1])

calcDrawTPlevels(A, B, C) =>
    TP1 = math.round_to_mintick(A + ((B - C) * 0.236))
    TP2 = math.round_to_mintick(A + ((B - C) * 0.618))
    TP3 = math.round_to_mintick(A + ((B - C) * 1))
    TP1_line = line.new(bar_index,TP1, bar_index + 100, TP1, color=#00aeff, width=2, style=line.style_dashed)
    TP2_line = line.new(bar_index,TP2, bar_index + 100, TP2, color=#043308, width=2, style=line.style_dashed)
    TP3_line = line.new(bar_index,TP3, bar_index + 100, TP3, color=#043308, width=2, style=line.style_dashed)
    line.delete(TP1_line[1])
    line.delete(TP2_line[1])
    line.delete(TP3_line[1])
    TP1Label = label.new(bar_index + 101 , TP1, text = "TP1 - "+ str.tostring(TP1), color=#00aeff, style=label.style_label_left, textcolor=lblTxtCol)
    label.delete(TP1Label[1])
    TP2Label = label.new(bar_index + 101 , TP2, text = "TP2 - "+ str.tostring(TP2), color=#043308, style=label.style_label_left, textcolor=lblTxtCol)
    label.delete(TP2Label[1])
    TP3Label = label.new(bar_index + 101 , TP3, text = "TP3 - "+ str.tostring(TP3), color=#043308, style=label.style_label_left, textcolor=lblTxtCol)
    label.delete(TP3Label[1])
    [TP1, TP2, TP3]                        

// END FUNCTIONS

l_nothingFound := label.new(bar_index + 10 ,high,"No matching setup found", style = label.style_label_left, textcolor = lblTxtCol)
label.delete(l_nothingFound[1])

if barstate.islast
    i = length - 1
    while i > -1
        array.set(arr_all_highs, length - 1 - i, high[i])
        array.set(arr_all_lows,length - 1 - i, low[i])
        array.set(arr_cumul_vol,length - 1 - i, cumVol[i])
        i -= 1
    if searchBull 
        //Search High 1
        high1 := array.max(arr_all_highs)
        positionH1 := array.indexof(arr_all_highs, high1)
        cumVolH1 := array.get(arr_cumul_vol, positionH1)

        if positionH1 < length - min_length  //Don't search if the high is too close to the current candle
            //Search Low 1
            b := array.slice(arr_all_lows, positionH1 + 1, array.size(arr_all_lows))
            len = array.size(b)
            low1 := array.min(b)
            positionL1 := length - array.size(b) + array.indexof(b, low1)
            cumVolL1 := array.get(arr_cumul_vol, positionL1)
            //Search High 2
            if positionL1 + 1 == length //avoid slicing index error when we already reached the current candle
                c := array.slice(arr_all_highs, positionL1, array.size(arr_all_highs))
            else
                c := array.slice(arr_all_highs, positionL1 + 1, array.size(arr_all_highs))
            high2 := array.max(c)
            positionH2 := length - array.size(c) + array.indexof(c, high2)
            cumVolH2 := array.get(arr_cumul_vol, positionH2)

            if high2 >= low1 + ((high1 - low1) * fib1)
                l_H1 := label.new(bar_index - length + positionH1 + 1,high1,"High", style = label.style_label_down, textcolor = lblTxtCol)
                l_L1 := label.new(bar_index - length + positionL1 + 1,low1,"Low", style = label.style_label_up, textcolor = lblTxtCol)
                l_H2 := label.new(bar_index - length + positionH2 + 1,high2,"Lower high", style = label.style_label_down, textcolor = lblTxtCol)
                label.delete(l_nothingFound)
                label.delete(l_H1[1])
                label.delete(l_L1[1])
                label.delete(l_H2[1])
                drawPivotLines(high1, positionH1, low1, positionL1)
                drawPivotLines(high2, positionH2, low1, positionL1)
                //Search Low 2
                if positionH2 + 1 == length
                    d := array.slice(arr_all_lows, positionH2, array.size(arr_all_lows))
                else
                    d := array.slice(arr_all_lows, positionH2 + 1, array.size(arr_all_lows))
                low2 := array.min(d)
                positionL2 := length - array.size(d) + array.indexof(d, low2)
                cumVolL2 := array.get(arr_cumul_vol, positionL2)
                if low2 <= high2 - ((high2 - low1) * fib2)
                    l_L2 := label.new(bar_index - length + positionL2 + 1,low2,"Higher low", style = label.style_label_up, textcolor = lblTxtCol)
                    label.delete(l_L2[1])
                    drawPivotLines(high2, positionH2, low2, positionL2)
                    [TP1, TP2, TP3] = calcDrawTPlevels(high2, high1, low1)
                    if version == 2
                        optiEntry = math.round_to_mintick(low1+((TP1 - low1)/(RRR+1)))
                        optimalEntry = line.new(bar_index,optiEntry, bar_index + 100, optiEntry, color=#0ff807, width=2)
                        l_optiEntry := label.new(bar_index + 101,optiEntry,"Optimal entry " + str.tostring(optiEntry), color=#043308, style=label.style_label_left, textcolor = lblTxtCol)
                        label.delete(l_optiEntry[1])
                        stoploss := line.new(bar_index - length + positionL1 + 1,low1, bar_index + 100, low1, color=#ff0000, width=2)
                        line.delete(stoploss[1])
                        SLLabel := label.new(bar_index + 101 , low1, text = "Stop/Loss "+ str.tostring(low1), color=#ff0000, style=label.style_label_left, textcolor = lblTxtCol)
                        label.delete(SLLabel[1])
                        lineEntrytoTP1 = line.new(bar_index + 25,optiEntry, bar_index + 25,TP1, color = color.green, style=line.style_arrow_right)
                        line.delete(lineEntrytoTP1[1])
                        lineEntrytoSL = line.new(bar_index + 25,optiEntry, bar_index + 25,low1, color = color.red, style=line.style_arrow_right)
                        line.delete(lineEntrytoSL[1])
                    //Search High 3
                    if positionL2 + 1 == length //avoid slicing index error when we already reached the current candle
                        e := array.slice(arr_all_highs, positionL2, array.size(arr_all_highs))
                    else
                        e := array.slice(arr_all_highs, positionL2 + 1, array.size(arr_all_highs))
                    high3 := array.max(e)
                    positionH3 := length - array.size(e) + array.indexof(e, high3)
                    cumVolH3 := array.get(arr_cumul_vol, positionH3)
                    if high3 >= low2 + ((high2 - low2) * fib3)
                        l_H3 := label.new(bar_index - length + positionH3 + 1,high3,"2nd lower high", style = label.style_label_down, textcolor = lblTxtCol)
                        label.delete(l_H3[1])
                        drawPivotLines(high3, positionH3, low2, positionL2)
                        //Search Low 3
                        if positionH3 + 1 == length //avoid slicing index error when we already reached the current candle
                            f := array.slice(arr_all_lows, positionH3, array.size(arr_all_lows))
                        else
                            f := array.slice(arr_all_lows, positionH3 + 1, array.size(arr_all_lows))
                        low3 := array.min(f)
                        positionL3 := length - array.size(f) + array.indexof(f, low3)
                        cumVolL3 := array.get(arr_cumul_vol, positionL3)
                        if low3 <= high3 - ((high3 - low2) * fib4)
                            alert("Fib compression - 2nd Higher Low formed", alert.freq_once_per_bar)
                            l_L3 := label.new(bar_index - length + positionL3 + 1,low3,"2nd higher low", style = label.style_label_up, textcolor = lblTxtCol)
                            label.delete(l_L3[1])
                            drawPivotLines(high3, positionH3, low3, positionL3)
                            if version == 1
                                stoploss := line.new(bar_index - length + positionL3 + 1,low3, bar_index + 100, low3, color=#ff0000, width=2)
                                line.delete(stoploss[1])
                                SLLabel := label.new(bar_index + 101 , low3, text = "Stop/Loss "+ str.tostring(low3), color=#ff0000, style=label.style_label_left, textcolor = lblTxtCol)
                                label.delete(SLLabel[1])
                                lineL3to0618 = line.new(bar_index - length + positionL3 + 1,low3, bar_index + 50,TP2, color = color.green, style=line.style_arrow_right)
                                line.delete(lineL3to0618[1])
    else
        //Search Low 1
        low1 := array.min(arr_all_lows)
        positionL1 := array.indexof(arr_all_lows, low1)
        cumVolL1 := array.get(arr_cumul_vol, positionL1)
        if positionL1 < length - min_length  //Don't search if the low is too close to the current candle
            //Search High 1
            b := array.slice(arr_all_highs, positionL1 + 1, array.size(arr_all_highs))
            high1 := array.max(b)
            positionH1 := length - array.size(b) + array.indexof(b, high1)
            cumVolH1 := array.get(arr_cumul_vol, positionH1)
            //Search Low 2
            if positionH1 + 1 == length //avoid slicing index error when we already reached the current candle
                c := array.slice(arr_all_lows, positionH1, array.size(arr_all_lows))
            else
                c := array.slice(arr_all_lows, positionH1 + 1, array.size(arr_all_lows))
            low2 := array.min(c)
            positionL2 := length - array.size(c) + array.indexof(c, low2)
            cumVolL2 := array.get(arr_cumul_vol, positionL2)
            if low2 <= high1 + ((low1 - high1) * fib1)
                l_L1 := label.new(bar_index - length + positionL1 + 1,low1,"Low", style = label.style_label_up, textcolor=color.yellow)
                l_H1 := label.new(bar_index - length + positionH1 + 1,high1,"High", style = label.style_label_down, textcolor=color.yellow)
                l_L2 := label.new(bar_index - length + positionL2 + 1,low2,"Higher low", style = label.style_label_up, textcolor=color.yellow)
                label.delete(l_nothingFound)
                label.delete(l_L1[1])
                label.delete(l_H1[1])
                label.delete(l_L2[1])
                drawPivotLines(high1, positionH1, low1, positionL1)
                drawPivotLines(high1, positionH1, low2, positionL2)
                //Search High 2
                if positionL2 + 1 == length //avoid slicing index error when we already reached the current candle
                    d := array.slice(arr_all_highs, positionL2, array.size(arr_all_highs))
                else
                    d := array.slice(arr_all_highs, positionL2 + 1, array.size(arr_all_highs))
                high2 := array.max(d)
                positionH2 := length - array.size(d) + array.indexof(d, high2)
                cumVolH2 := array.get(arr_cumul_vol, positionH2)
                if high2 >= low2 - ((low2 - high1) * fib2)
                    l_H2 := label.new(bar_index - length + positionH2 + 1,high2,"Lower high", style = label.style_label_down, textcolor=color.yellow)
                    label.delete(l_H2[1])
                    drawPivotLines(high2, positionH2, low2, positionL2)
                    [TP1, TP2, TP3] = calcDrawTPlevels(low2, low1, high1)
                    if version == 2
                        optiEntry = math.round_to_mintick(high1-((high1 - TP1)/(RRR+1)))
                        optimalEntry = line.new(bar_index,optiEntry, bar_index + 100, optiEntry, color=#0ff807, width=2)
                        l_optiEntry := label.new(bar_index + 101,optiEntry,"Optimal entry " + str.tostring(optiEntry), color=#043308, style=label.style_label_left, textcolor = lblTxtCol)
                        label.delete(l_optiEntry[1])
                        stoploss := line.new(bar_index - length + positionH1 + 1,high1, bar_index + 100, high1, color=#ff0000, width=2)
                        line.delete(stoploss[1])
                        SLLabel := label.new(bar_index + 101 , high1, text = "Stop/Loss "+ str.tostring(high1), color=#ff0000, style=label.style_label_left, textcolor = lblTxtCol)
                        label.delete(SLLabel[1])
                        lineEntrytoTP1 = line.new(bar_index + 25,optiEntry, bar_index + 25,TP1, color = color.green, style=line.style_arrow_right)
                        line.delete(lineEntrytoTP1[1])
                        lineEntrytoSL = line.new(bar_index + 25,optiEntry, bar_index + 25,high1, color = color.red, style=line.style_arrow_right)
                        line.delete(lineEntrytoSL[1])
                    //Search Low 3
                    if positionH2 + 1 == length //avoid slicing index error when we already reached the current candle
                        e := array.slice(arr_all_lows, positionH2, array.size(arr_all_lows))
                    else
                        e := array.slice(arr_all_lows, positionH2 + 1, array.size(arr_all_lows))
                    low3 := array.min(e)
                    positionL3 := length - array.size(e) + array.indexof(e, low3)
                    cumVolL3 := array.get(arr_cumul_vol, positionL3)
                    if low3 <= high2 + ((low2 - high2) * fib3)
                        l_L3 := label.new(bar_index - length + positionL3 + 1,low3,"2nd higher low", style = label.style_label_up, textcolor=color.yellow)
                        label.delete(l_L3[1])
                        drawPivotLines(high2, positionH2, low3, positionL3)
                        //Search High 3
                        if positionL3 + 1 == length //avoid slicing index error when we already reached the current candle
                            f := array.slice(arr_all_highs, positionL3, array.size(arr_all_highs))
                        else
                            f := array.slice(arr_all_highs, positionL3 + 1, array.size(arr_all_highs))
                        high3 := array.max(f)
                        positionH3 := length - array.size(f) + array.indexof(f, high3)
                        cumVolH3 := array.get(arr_cumul_vol, positionH3)
                        if high3 >= low3 - ((low3 - high2) * fib4)
                            alert("Fib compression - 2nd Lower High formed", alert.freq_once_per_bar)
                            l_H3 := label.new(bar_index - length + positionH3 + 1,high3,"2nd lower high", style = label.style_label_down, textcolor=color.yellow)
                            label.delete(l_L3[1])
                            drawPivotLines(high3, positionH3, low3, positionL3)
                            if version == 1
                                stoploss := line.new(bar_index - length + positionH3 + 1,high3, bar_index + 100, high3, color=#ff0000, width=2)
                                line.delete(stoploss[1])
                                SLLabel := label.new(bar_index + 101 , high3, text = "Stop/Loss "+ str.tostring(high3), color=#ff0000, style=label.style_label_left, textcolor = lblTxtCol)
                                label.delete(SLLabel[1])
                                lineH3to0618 = line.new(bar_index - length + positionH3 + 1,high3, bar_index + 50,TP2, color = color.green, style=line.style_arrow_right)
                                line.delete(lineH3to0618[1])