Trend Channels [Cryptoverse]
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © HasanGocmen

//@version=5
indicator("Trend Channels [Cryptoverse]", overlay = true, max_labels_count = 500, max_lines_count = 500, max_bars_back = 10)
period = input.int(defval = 6, title="Pivot Period", minval = 1, maxval = 50, group = "GENERAL SETUP")
topSource = input.string(title="Top Pivot Source", defval = 'close', group = "GENERAL SETUP", options = ['close', 'high'])
bottomSource = input.string(title="Bottom Pivot Source", defval = 'close', group = "GENERAL SETUP", options = ['close', 'low'])

// Trend Lines Setups
showTL = input.bool(true, "Show All Trend Lines", group = "TREND LINES SETUP")
hideOL = input.bool(false, "Hide Old Trend Lines", group = "TREND LINES SETUP")
hideML = input.bool(false, "Hide Middle Trend Lines", group = "TREND LINES SETUP")
hideTTSL = input.bool(false, "Hide 0.236 Lines", group = "TREND LINES SETUP", inline="hidelines")
hideSESL = input.bool(false, "Hide 0.786 Lines", group = "TREND LINES SETUP", inline="hidelines")
hlpr_l_f = input.string(title="Helper Line Format", defval="$", options=["%", "$"], group = "TREND LINES SETUP")
ut_clr = input.color(color.rgb(113, 165, 42), "Up Trend Color", group = "TREND LINES SETUP", inline = "trendcolor")
dt_clr = input.color(color.rgb(246, 12, 122), "Down Trend Color", group = "TREND LINES SETUP", inline = "trendcolor")
mt_clr = input.color(color.rgb(255, 152, 0), "0.5 Trend Color", group = "TREND LINES SETUP", inline = "centercolor")
tts_t_clr = input.color(color.rgb(0,188,212), "0.236 Trend Color", group = "TREND LINES SETUP", inline = "helpercolor")
ses_t_clr = input.color(color.rgb(0,188,212), "0.786 Trend Color", group = "TREND LINES SETUP", inline = "helpercolor")
t_c_w = input.int(defval = 1, title="Trend Channel Width", minval = 1, maxval = 4, group = "TREND LINES SETUP")
t_c_s = input.string("solid (─)", title="Trend Channel Style", options=["solid (─)", "dotted (┈)", "dashed (╌)"], group = "TREND LINES SETUP")

tPT = topSource == 'close' ? close : high 
bPT = bottomSource == 'close' ? close : low

float src1 =  math.max(tPT, tPT)
float src2 =  math.min(bPT, bPT)

float ph = ta.pivothigh(src1, period, period)
float pl = ta.pivotlow(src2, period, period)

plotshape(ph, style = shape.triangledown, color = color.red, textcolor = color.red, location = location.abovebar,  offset = -period)
plotshape(pl, style = shape.triangleup, color = color.lime, textcolor = color.lime, location = location.belowbar,  offset = -period)

var pvtH = array.new_float(0)
var pvtL = array.new_float(0)
var pvtHI = array.new_int(0)
var pvtLI = array.new_int(0)

var line t_h_l = na
var line t_l_l = na
var line t_c_l = na
var line t_tts_l = na
var line t_ses_l = na

var line b_l_l = na
var line b_h_l = na
var line b_c_l = na
var line b_tts_l = na
var line b_ses_l = na

t_l_s = t_c_s == "dotted (┈)" ? line.style_dotted : t_c_s == "dashed (╌)" ? line.style_dashed : line.style_solid

add_to_array(arr, indexArr, val)=>
    array.push(arr, val)
    array.push(indexArr, bar_index - period)

c_e_p(price, process, percent)=>
    result = 0.0
    if(process == "plus")
        result := price + (price / 100) * percent
    else
        result := price - (price / 100) * percent

u_d_l(line, type)=>
    l_x_i = line.get_x1(line)
    l_x_p = line.get_y1(line)
    l_y_i = line.get_x2(line)
    l_y_p = line.get_y2(line)
    l_b_c = l_y_i - l_x_i
    l_d_p = type == "top" ? l_x_p - l_y_p : l_y_p - l_x_p 
    l_u_p = l_d_p / l_b_c
    d_l_f_p = (bar_index - period) - l_x_i
    c_l_p_p = 0.0
    if(type == "top")
        c_l_p_p := l_x_p - (l_u_p * d_l_f_p)
    else
        c_l_p_p := l_x_p + (l_u_p * d_l_f_p)
    c_l_p_p

d_t_h_l(pHI, pHP, lHP)=>
    new_l_b_c = (bar_index - period) - pHI
    new_l_d_p = pHP - lHP
    new_l_u_p = new_l_d_p / new_l_b_c

    lowest = 100000.0
    t_lowest = 100000.0
    l_i = 0

    if(topSource == 'close')
        for y = 0 to new_l_b_c
            if(close[period + new_l_b_c - y] - (new_l_u_p * (new_l_b_c - y)) < t_lowest)
                lowest := close[period + new_l_b_c -  y]
                t_lowest := close[period + new_l_b_c -  y] - (new_l_u_p * (new_l_b_c - y))
                l_i := bar_index - (period + new_l_b_c - y)
    else
        for y = 0 to new_l_b_c
            if(low[period + new_l_b_c - y] - (new_l_u_p * (new_l_b_c - y)) < t_lowest)
                lowest := low[period + new_l_b_c -  y]
                t_lowest := low[period + new_l_b_c -  y] - (new_l_u_p * (new_l_b_c - y))
                l_i := bar_index - (period + new_l_b_c - y)

    d_l_b_c = l_i - pHI
    c_l_l_p = pHP - (new_l_u_p * d_l_b_c)
    pLP = 0.0
    lLP = 0.0
    pCP = 0.0
    lCP = 0.0
    pTTSP = 0.0
    lTTSP = 0.0
    pSESP = 0.0
    lSESP = 0.0

    if(hlpr_l_f == '%')
        l_perc = (lowest - c_l_l_p) * 100 / c_l_l_p
        pLP := pHP * ((100 - math.abs(l_perc)) / 100)
        lLP := lHP * ((100 - math.abs(l_perc)) / 100)

        c_perc = ((lowest - c_l_l_p) * 100 / c_l_l_p) / 2
        pCP := pHP * ((100 - math.abs(c_perc)) / 100)
        lCP := lHP * ((100 - math.abs(c_perc)) / 100)
    else
        pLP := pHP + (lowest - c_l_l_p)
        lLP := lHP + (lowest - c_l_l_p)
        pCP := pHP - ((pHP - pLP) * 0.5)
        lCP := lHP - ((lHP - lLP) * 0.5)
        pTTSP := pHP - ((pHP - pLP) * 0.236)
        lTTSP := lHP - ((lHP - lLP) * 0.236)
        pSESP := pHP - ((pHP - pLP) * 0.786)
        lSESP := lHP - ((lHP - lLP) * 0.786)
    [pLP, lLP, pCP, lCP, pTTSP, lTTSP, pSESP, lSESP]

d_b_h_l(pLI, pLP, lLP)=>
    new_l_b_c = (bar_index - period) - pLI
    new_l_d_p = lLP - pLP
    new_l_u_p = new_l_d_p / new_l_b_c

    highest = 0.0
    t_highest = 0.0
    h_i = 0

    if(bottomSource == 'close')
        for y = 0 to new_l_b_c
            if(close[period + new_l_b_c - y] + (new_l_u_p * (new_l_b_c - y)) > t_highest)
                highest := close[period + new_l_b_c -  y]
                t_highest := close[period + new_l_b_c -  y] + (new_l_u_p * (new_l_b_c - y))
                h_i := bar_index - (period + new_l_b_c - y) 
    else
        for y = 0 to new_l_b_c
            if(high[period + new_l_b_c - y] + (new_l_u_p * (new_l_b_c - y)) > t_highest)
                highest := high[period + new_l_b_c -  y]
                t_highest := high[period + new_l_b_c -  y] + (new_l_u_p * (new_l_b_c - y))
                h_i := bar_index - (period + new_l_b_c - y) 

    d_l_b_c = h_i - pLI

    c_h_l_p = pLP + (new_l_u_p * d_l_b_c)
    pHP = 0.0
    lHP = 0.0
    pCP = 0.0
    lCP = 0.0

    pTTSP = 0.0
    lTTSP = 0.0
    pSESP = 0.0
    lSESP = 0.0

    if(hlpr_l_f == '%')
        l_perc = (highest - c_h_l_p) * 100 / c_h_l_p
        pHP := pLP * ((100 + math.abs(l_perc)) / 100)
        lHP := lLP * ((100 + math.abs(l_perc)) / 100)
        c_perc = ((highest - c_h_l_p) * 100 / c_h_l_p) / 2
        pCP := pLP * ((100 - math.abs(c_perc)) / 100)
        lCP := lLP * ((100 - math.abs(c_perc)) / 100)
    else
        pHP := pLP + (highest - c_h_l_p)
        lHP := lLP + (highest - c_h_l_p)
        pCP := pLP + ((pHP - pLP) * 0.5)
        lCP := lLP + ((lHP - lLP) * 0.5)
        pTTSP := pLP + ((pHP - pLP) * 0.236)
        lTTSP := lLP + ((lHP - lLP) * 0.236)
        pSESP := pLP + ((pHP - pLP) * 0.786)
        lSESP := lLP + ((lHP - lLP) * 0.786)        
    [pHP, lHP, pCP, lCP, pTTSP, lTTSP, pSESP, lSESP]

if(ph)
    if(array.size(pvtH) > 0 and showTL)
        pPH = array.get(pvtH, array.size(pvtH) - 1)
        prev_pvtHI = array.get(pvtHI, array.size(pvtHI) - 1)

        two_pPH = array.size(pvtH) > 1 ? array.get(pvtH, array.size(pvtH) - 2) : 0
        two_prev_pvtHI = array.size(pvtHI) > 1 ? array.get(pvtHI, array.size(pvtHI) - 2) : 0
        three_pPH = array.size(pvtH) > 2 ? array.get(pvtH, array.size(pvtH) - 3) : 0

        c_HLPP = u_d_l(t_h_l, "top")
        c_LLPP = u_d_l(t_l_l, "top")
        c_CLPP = u_d_l(t_c_l, "top")
        c_TTSLPP = u_d_l(t_tts_l, "top")
        c_SESLPP = u_d_l(t_ses_l, "top")
        a_LTP = line.get_y1(t_h_l)

        if(two_pPH >= three_pPH and pPH < two_pPH and ph * 1.001 < pPH)
            line.set_xy2(t_h_l, bar_index - period, c_HLPP)
            line.set_xy2(t_l_l, bar_index - period, c_LLPP)
            line.set_xy2(t_c_l, bar_index - period, c_CLPP)
            line.set_xy2(t_tts_l, bar_index - period, c_TTSLPP)
            line.set_xy2(t_ses_l, bar_index - period, c_SESLPP)

            if(na(c_HLPP) or c_e_p(c_HLPP, "plus", 0.35) < ph or c_e_p(c_LLPP, "minus", 0.35) > ph)
                line.set_color(t_h_l, color.new(dt_clr, 50))
                line.set_color(t_l_l, color.new(dt_clr, 50))
                line.set_color(t_c_l, color.new(mt_clr, 75))
                line.set_color(t_tts_l, color.new(tts_t_clr, 75))
                line.set_color(t_ses_l, color.new(ses_t_clr, 75))

                line.set_extend(t_h_l, extend.none)
                line.set_extend(t_l_l, extend.none)
                line.set_extend(t_c_l, extend.none)
                line.set_extend(t_tts_l, extend.none)
                line.set_extend(t_ses_l, extend.none)

                if(hideOL)
                    line.delete(t_h_l)
                    line.delete(t_l_l)
                    line.delete(t_c_l)
                    line.delete(t_tts_l)
                    line.delete(t_ses_l)

                t_h_l := line.new(two_prev_pvtHI, two_pPH, bar_index - period, ph, extend = extend.right, width = t_c_w, color= dt_clr, style = t_l_s)
                [pLP, lLP, pCP, lCP, pTTSP, lTTSP, pSESP, lSESP] = d_t_h_l(two_prev_pvtHI, two_pPH, ph)

                t_l_l := line.new(two_prev_pvtHI, pLP, bar_index - period, lLP, extend = extend.right, width = 1, color= dt_clr, style = t_l_s)

                if not hideML
                    t_c_l := line.new(two_prev_pvtHI, pCP, bar_index - period, lCP, extend = extend.right, width = t_c_w, color = color.new(mt_clr, 50), style = t_l_s)
                if not hideTTSL
                    t_tts_l := line.new(two_prev_pvtHI, pTTSP, bar_index - period, lTTSP, extend = extend.right, width = t_c_w, color = color.new(tts_t_clr, 75), style = t_l_s)
                if not hideSESL
                    t_ses_l := line.new(two_prev_pvtHI, pSESP, bar_index - period, lSESP, extend = extend.right, width = t_c_w, color = color.new(ses_t_clr, 75), style = t_l_s)
        else
            if(a_LTP > ph)
                line.set_xy2(t_h_l, bar_index - period, c_HLPP)
                line.set_xy2(t_l_l, bar_index - period, c_LLPP)
                line.set_xy2(t_c_l, bar_index - period, c_CLPP)

    add_to_array(pvtH, pvtHI, ph)

if(pl)
    if(array.size(pvtL) > 0 and showTL)
        pPL = array.get(pvtL, array.size(pvtL) - 1)
        prev_pvtLI = array.get(pvtLI, array.size(pvtLI) - 1)

        two_pPL = array.size(pvtL) > 1 ? array.get(pvtL, array.size(pvtL) - 2) : 0
        two_prev_pvtLI = array.size(pvtLI) > 1 ? array.get(pvtLI, array.size(pvtLI) - 2) : 0

        three_pPL = array.size(pvtL) > 2 ? array.get(pvtL, array.size(pvtL) - 3) : 0

        c_LLPP = u_d_l(b_l_l, "bottom")
        c_HLPP = u_d_l(b_h_l, "bottom")
        c_CLPP = u_d_l(b_c_l, "bottom")
        c_TTSLPP = u_d_l(b_tts_l, "bottom")
        c_SESLPP = u_d_l(b_ses_l, "bottom")
        a_LBP = line.get_y1(b_l_l)

        if(two_pPL <= three_pPL and pPL > two_pPL and pl * 0.999 > pPL)
            line.set_xy2(b_l_l, bar_index - period, c_LLPP)
            line.set_xy2(b_h_l, bar_index - period, c_HLPP)
            line.set_xy2(b_c_l, bar_index - period, c_CLPP)
            line.set_xy2(b_tts_l, bar_index - period, c_TTSLPP)
            line.set_xy2(b_ses_l, bar_index - period, c_SESLPP)

            if(na(c_LLPP) or c_e_p(c_LLPP, "minus", 0.35) > pl or c_e_p(c_HLPP, "plus", 0.35) < pl)
                line.set_color(b_h_l, color.new(ut_clr, 50))
                line.set_color(b_l_l, color.new(ut_clr, 50))
                line.set_color(b_c_l, color.new(ut_clr, 75))
                line.set_color(b_tts_l, color.new(tts_t_clr, 90))
                line.set_color(b_ses_l, color.new(ses_t_clr, 90))

                line.set_extend(b_h_l, extend.none)
                line.set_extend(b_l_l, extend.none)
                line.set_extend(b_c_l, extend.none)
                line.set_extend(b_tts_l, extend.none)
                line.set_extend(b_ses_l, extend.none)

                if(hideOL)
                    line.delete(b_h_l)
                    line.delete(b_l_l)  
                    line.delete(b_c_l) 
                    line.delete(b_tts_l)
                    line.delete(b_ses_l)

                b_l_l := line.new(two_prev_pvtLI, two_pPL, bar_index - period, pl, extend = extend.right, width = t_c_w, color= ut_clr, style = t_l_s)

                [pHP, lHP, pCP, lCP, pTTSP, lTTSP, pSESP, lSESP] = d_b_h_l(two_prev_pvtLI, two_pPL, pl)                
                b_h_l := line.new(two_prev_pvtLI, pHP, bar_index - period, lHP, extend = extend.right, width = t_c_w, color= ut_clr, style = t_l_s)
                
                if not hideML
                    b_c_l := line.new(two_prev_pvtLI, pCP, bar_index - period, lCP, extend = extend.right, width = t_c_w, color= color.new(mt_clr, 50), style = t_l_s)
                if not hideTTSL
                    b_tts_l := line.new(two_prev_pvtLI, pTTSP, bar_index - period, lTTSP, extend = extend.right, width = t_c_w, color = color.new(tts_t_clr, 50), style = t_l_s)
                if not hideSESL
                    b_ses_l := line.new(two_prev_pvtLI, pSESP, bar_index - period, lSESP, extend = extend.right, width = t_c_w, color = color.new(ses_t_clr, 50), style = t_l_s)
        else
            if(a_LBP < pl)
                line.set_xy2(b_l_l, bar_index - period, c_LLPP)
                line.set_xy2(b_h_l, bar_index - period, c_HLPP)
                line.set_xy2(b_c_l, bar_index - period, c_CLPP)

    add_to_array(pvtL, pvtLI, pl)
