MTF Market Structure Highs and Lows
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © geneclash

//@version=5
indicator("MTF Market Structure Highs and Lows",overlay=true,max_bars_back = 5000)

drawLine = input(true,title="Draw Vertical Line to Latest Alert")
filterBW = input(false, title="filter Bill Williams Fractals:")
LabelsOffset = input(50)

isRegularFractal(mode) =>
    ret = mode == 1 ? high[4] < high[3] and high[3] < high[2] and high[2] > high[1] and high[1] > high[0] : mode == -1 ? low[4] > low[3] and low[3] > low[2] and low[2] < low[1] and low[1] < low[0] : false

isBWFractal(mode) =>
    ret = mode == 1 ? high[4] < high[2] and high[3] <= high[2] and high[2] >= high[1] and high[2] > high[0] : mode == -1 ? low[4] > low[2] and low[3] >= low[2] and low[2] <= low[1] and low[2] < low[0] : false

dt = time - time[1]

GetLastPivots() =>
    var float LastPh_v = na
    var float LastPl_v = na
    var int LastPh_t = na
    var int LastPl_t = na
    
    filteredtopf = filterBW ? isRegularFractal(1) : isBWFractal(1)
    filteredbotf = filterBW ? isRegularFractal(-1) : isBWFractal(-1)

    if filteredtopf
        LastPh_v := high[2]
        LastPh_t := time[2]
    if filteredbotf
        LastPl_v := low[2]
        LastPl_t := time[2]
        
    [LastPh_v,LastPh_t,LastPl_v,LastPl_t]

ShowY = input.bool(false,title="Use Monthly Levels")
ColorHY = input.color(color.black,inline='y1',title="High")
ColorLY = input.color(color.black,inline='y1',title="Low ")
StyleY = input.string("Dotted",options=["Solid","Dotted","Dashed"],inline='y1',title="")
WidthY = input.int(1,title="",inline="y1")

Show1 = input.bool(true,title="Use Weekly Levels")
ColorH1 = input.color(color.black,inline='l1',title="High")
ColorL1 = input.color(color.black,inline='l1',title="Low ")
Style1 = input.string("Dotted",options=["Solid","Dotted","Dashed"],inline='l1',title="")
Width1 = input.int(1,title="",inline="l1")

Show2 = input.bool(true,title="Use Daily Levels")
ColorH2 = input.color(color.black,inline='l2',title="High")
ColorL2 = input.color(color.black,inline='l2',title="Low")
Style2 = input.string("Dotted",options=["Solid","Dotted","Dashed"],inline='l2',title="")
Width2 = input.int(1,title="",inline="l2")

Show3 = input.bool(true,title="Show 4H Levels")
ColorH3 = input.color(color.black,inline='l3',title="High")
ColorL3 = input.color(color.black,inline='l3',title="Low ")
Style3 = input.string("Dotted",options=["Solid","Dotted","Dashed"],inline='l3',title="")
Width3 = input.int(1,title="",inline="l3")

Show4 = input.bool(true,title="Show 1H Levels")
ColorH4 = input.color(color.black,inline='l4',title="High")
ColorL4 = input.color(color.black,inline='l4',title="Low")
Style4 = input.string("Dotted",options=["Solid","Dotted","Dashed"],inline='l4',title="")
Width4 = input.int(1,title="",inline="l4")

Show5 = input.bool(false,title="Show 30m Levels")
ColorH5 = input.color(color.black,inline='l5',title="High")
ColorL5 = input.color(color.black,inline='l5',title="Low")
Style5 = input.string("Dotted",options=["Solid","Dotted","Dashed"],inline='l5',title="")
Width5 = input.int(1,title="",inline="l5")

Show6 = input.bool(false,title="Show 15m Levels")
ColorH6 = input.color(color.black,inline='l6',title="High")
ColorL6 = input.color(color.black,inline='l6',title="Low")
Style6 = input.string("Dotted",options=["Solid","Dotted","Dashed"],inline='l6',title="")
Width6 = input.int(1,title="",inline="l6")

Show7 = input.bool(false,title="Show 5m Levels")
ColorH7 = input.color(color.black,inline='l7',title="High")
ColorL7 = input.color(color.black,inline='l7',title="Low")
Style7 = input.string("Dotted",options=["Solid","Dotted","Dashed"],inline='l7',title="")
Width7 = input.int(1,title="",inline="l7")

LabelColor = input.color(color.purple)
TextColor = input.color(color.black)

StyleToEnum(s) =>
    if s == 'Solid'
        line.style_solid
    else if s == 'Dotted'
        line.style_dotted
    else
        line.style_dashed

[LastPh_vY,LastPh_tY_,LastPl_vY,LastPl_tY_] = request.security(syminfo.tickerid,"M", GetLastPivots())
[LastPh_v1,LastPh_t1_,LastPl_v1,LastPl_t1_] = request.security(syminfo.tickerid,"W", GetLastPivots())
[LastPh_v2,LastPh_t2_,LastPl_v2,LastPl_t2_] = request.security(syminfo.tickerid,"D", GetLastPivots())
[LastPh_v3,LastPh_t3_,LastPl_v3,LastPl_t3_] = request.security(syminfo.tickerid,"240", GetLastPivots())
[LastPh_v4,LastPh_t4_,LastPl_v4,LastPl_t4_] = request.security(syminfo.tickerid,"60", GetLastPivots())
[LastPh_v5,LastPh_t5_,LastPl_v5,LastPl_t5_] = request.security(syminfo.tickerid,"30", GetLastPivots())
[LastPh_v6,LastPh_t6_,LastPl_v6,LastPl_t6_] = request.security(syminfo.tickerid,"15", GetLastPivots())
[LastPh_v7,LastPh_t7_,LastPl_v7,LastPl_t7_] = request.security(syminfo.tickerid,"5", GetLastPivots())

line lhY = na, line llY = na
line lh1 = na, line ll1 = na
line lh2 = na, line ll2 = na
line lh3 = na, line ll3 = na
line lh4 = na, line ll4 = na
line lh5 = na, line ll5 = na
line lh6 = na, line ll6 = na
line lh7 = na, line ll7 = na

label lblhY = na, label lbllY = na
label lblh1 = na, label lbll1 = na
label lblh2 = na, label lbll2 = na
label lblh3 = na, label lbll3 = na
label lblh4 = na, label lbll4 = na
label lblh5 = na, label lbll5 = na
label lblh6 = na, label lbll6 = na
label lblh7 = na, label lbll7 = na

var Pl_Y_trigger = false, var Pl_1_trigger = false,  var Pl_2_trigger = false, var Pl_3_trigger = false, var Pl_4_trigger = false, var Pl_5_trigger = false, var Pl_6_trigger = false, var Pl_7_trigger = false
var Ph_Y_trigger = false, var Ph_1_trigger = false,  var Ph_2_trigger = false, var Ph_3_trigger = false, var Ph_4_trigger = false, var Ph_5_trigger = false, var Ph_6_trigger = false, var Ph_7_trigger = false

//Reset Trigger
if ta.change(LastPh_v7)
    Ph_7_trigger := false
    
if ta.change(LastPh_v6)
    Ph_6_trigger := false

if ta.change(LastPh_v5)
    Ph_5_trigger := false

if ta.change(LastPh_v4)
    Ph_4_trigger := false

if ta.change(LastPh_v3)
    Ph_3_trigger := false

if ta.change(LastPh_v2)
    Ph_2_trigger := false

if ta.change(LastPh_v1)
    Ph_1_trigger := false

if ta.change(LastPh_vY)
    Ph_Y_trigger := false

if ta.change(LastPl_v4)
    Pl_4_trigger := false

if ta.change(LastPl_v3)
    Pl_3_trigger := false
    
if ta.change(LastPl_v2)
    Pl_2_trigger := false
    
if ta.change(LastPl_v1)
    Pl_1_trigger := false

if ta.change(LastPl_vY)
    Pl_Y_trigger := false

FindT(t,v) =>
    int result = time
    begin = (time - t) / dt
    if begin < 5000
        for i = begin to 0
            if high[i] == v or low[i] == v
                result := t + (begin-i) * dt
                break
        result
    else
        t

LastPl_tY = FindT(LastPl_tY_,LastPl_vY)
LastPh_tY = FindT(LastPh_tY_,LastPh_vY)

LastPl_t1 = FindT(LastPl_t1_,LastPl_v1)
LastPh_t1 = FindT(LastPh_t1_,LastPh_v1)

LastPl_t2 = FindT(LastPl_t2_,LastPl_v2)
LastPh_t2 = FindT(LastPh_t2_,LastPh_v2)

LastPl_t3 = FindT(LastPl_t3_,LastPl_v3)
LastPh_t3 = FindT(LastPh_t3_,LastPh_v3)

LastPl_t4 = FindT(LastPl_t4_,LastPl_v4)
LastPh_t4 = FindT(LastPh_t4_,LastPh_v4)

LastPl_t5 = FindT(LastPl_t5_,LastPl_v5)
LastPh_t5 = FindT(LastPh_t5_,LastPh_v5)

LastPl_t6 = FindT(LastPl_t6_,LastPl_v6)
LastPh_t6 = FindT(LastPh_t6_,LastPh_v6)

LastPl_t7 = FindT(LastPl_t7_,LastPl_v7)
LastPh_t7 = FindT(LastPh_t7_,LastPh_v7)

//////
LastPl_Yalert = ta.crossunder(low,LastPl_vY) and Pl_Y_trigger == false
LastPh_Yalert = ta.crossover(high,LastPh_vY) and Ph_Y_trigger == false

LastPl_1alert = ta.crossunder(low,LastPl_v1) and Pl_1_trigger == false
LastPh_1alert = ta.crossover(high,LastPh_v1) and Ph_1_trigger == false

LastPl_2alert = ta.crossunder(low,LastPl_v2) and Pl_2_trigger == false
LastPh_2alert = ta.crossover(high,LastPh_v2) and Ph_2_trigger == false

LastPl_3alert = ta.crossunder(low,LastPl_v3) and Pl_3_trigger == false
LastPh_3alert = ta.crossover(high,LastPh_v3) and Ph_3_trigger == false

LastPl_4alert = ta.crossunder(low,LastPl_v4) and Pl_4_trigger == false
LastPh_4alert = ta.crossover(high,LastPh_v4) and Ph_4_trigger == false

LastPl_5alert = ta.crossunder(low,LastPl_v5) and Pl_5_trigger == false
LastPh_5alert = ta.crossover(high,LastPh_v5) and Ph_5_trigger == false

LastPl_6alert = ta.crossunder(low,LastPl_v6) and Pl_6_trigger == false
LastPh_6alert = ta.crossover(high,LastPh_v6) and Ph_6_trigger == false

LastPl_7alert = ta.crossunder(low,LastPl_v7) and Pl_7_trigger == false
LastPh_7alert = ta.crossover(high,LastPh_v7) and Ph_7_trigger == false

alertcondition(LastPl_Yalert or LastPh_Yalert,title="04- M high/Low cross alert",message="M high/Low cross alert")
alertcondition(LastPl_1alert or LastPh_1alert,title="05- W high/Low cross alert",message="W high/Low cross alert")
alertcondition(LastPl_2alert or LastPh_2alert,title="06- D high/Low cross alert",message="D high/Low cross alert")
alertcondition(LastPl_3alert or LastPh_3alert,title="07- 240 high/Low cross alert",message="240 high/Low cross alert")
alertcondition(LastPl_4alert or LastPh_4alert,title="08- 60 high/Low cross alert",message="60 high/Low cross alert")
alertcondition(LastPl_5alert or LastPh_5alert,title="09- 30 high/Low cross alert",message="30 high/Low cross alert")
alertcondition(LastPl_6alert or LastPh_6alert,title="10- 15 high/Low cross alert",message="15 high/Low cross alert")
alertcondition(LastPl_7alert or LastPh_7alert,title="11- 5 high/Low cross alert",message="5 high/Low cross alert")

ShowYa=input(false,"Show Previous alert points M") 
Show1a=input(false,"Show Previous alert points W")
Show2a=input(false,"Show Previous alert points D")
Show3a=input(false,"Show Previous alert points 240")
Show4a=input(false,"Show Previous alert points 60")
Show5a=input(false,"Show Previous alert points 30")
Show6a=input(false,"Show Previous alert points 15")
Show7a=input(false,"Show Previous alert points 5")
ShowAlla = input(false,"Show Previous Any alert points")

bgcolor(LastPl_Yalert and ShowYa?color.new(color.red,80):na)
bgcolor(LastPh_Yalert and ShowYa?color.new(color.green,80):na)

bgcolor(LastPl_1alert and Show1a?color.new(color.red,80):na)
bgcolor(LastPh_1alert and Show1a?color.new(color.green,80):na)

bgcolor(LastPl_2alert and Show2a?color.new(color.red,80):na)
bgcolor(LastPh_2alert and Show2a?color.new(color.green,80):na)

bgcolor(LastPl_3alert and Show3a?color.new(color.red,80):na)
bgcolor(LastPh_3alert and Show3a?color.new(color.green,80):na)

bgcolor(LastPl_4alert and Show4a?color.new(color.red,80):na)
bgcolor(LastPh_4alert and Show4a?color.new(color.green,80):na)

bgcolor(LastPl_5alert and Show5a?color.new(color.red,80):na)
bgcolor(LastPh_5alert and Show5a?color.new(color.green,80):na)

bgcolor(LastPl_6alert and Show6a?color.new(color.red,80):na)
bgcolor(LastPh_6alert and Show6a?color.new(color.green,80):na)

bgcolor(LastPl_7alert and Show7a?color.new(color.red,80):na)
bgcolor(LastPh_7alert and Show7a?color.new(color.green,80):na)

anyLowAlertCond = (LastPl_Yalert or LastPl_1alert or LastPl_2alert or LastPl_3alert or LastPl_4alert or LastPl_5alert or LastPl_6alert or LastPl_7alert)
anyHighAlertCond = (LastPh_Yalert or LastPh_1alert or LastPh_2alert or LastPh_3alert or LastPh_4alert or LastPh_5alert or LastPh_6alert or LastPh_7alert) 

bgcolor(anyLowAlertCond and ShowAlla?color.new(color.green,80):na)
bgcolor(anyHighAlertCond and ShowAlla?color.new(color.red,80):na)

var line alertLine = na
if (anyLowAlertCond or anyHighAlertCond) and drawLine
    alertLine := line.new(bar_index,high,bar_index,low,extend=extend.both,color=color.navy)
    line.delete(alertLine[1])

alertcondition(anyLowAlertCond or anyHighAlertCond,title="01- Any Level Cross Alert",message="Any Level Cross Alert")
alertcondition(anyLowAlertCond,title="02- Any Level (Low) Cross Alert",message="Any Level (Low) Cross Alert")
alertcondition(anyHighAlertCond,title="03- Any Level (High) Cross Alert",message="Any Level (High) Cross Alert")


//Set Trigger
if LastPl_Yalert
    Pl_Y_trigger := true

if LastPh_Yalert
    Ph_Y_trigger := true
    
if LastPl_1alert
    Pl_1_trigger := true

if LastPh_1alert
    Ph_1_trigger := true

if LastPl_2alert
    Pl_2_trigger := true

if LastPh_2alert
    Ph_2_trigger := true

if LastPl_3alert
    Pl_3_trigger := true

if LastPh_3alert
    Ph_3_trigger := true

if LastPl_4alert
    Pl_4_trigger := true

if LastPh_4alert
    Ph_4_trigger := true

if LastPl_5alert
    Pl_5_trigger := true

if LastPh_5alert
    Ph_5_trigger := true

if LastPl_6alert
    Pl_6_trigger := true

if LastPh_6alert
    Ph_6_trigger := true
    
if LastPl_7alert
    Pl_7_trigger := true

if LastPh_7alert
    Ph_7_trigger := true

if barstate.islast
    if ShowY
        lhY := line.new(LastPh_tY,LastPh_vY,time,LastPh_vY,xloc=xloc.bar_time,color=ColorHY,style=StyleToEnum(StyleY),extend=extend.right,width=WidthY)
        line.delete(lhY[1])
        
        llY := line.new(LastPl_tY,LastPl_vY,time,LastPl_vY,xloc=xloc.bar_time,color=ColorLY,style=StyleToEnum(StyleY),extend=extend.right,width=WidthY)
        line.delete(llY[1])
        
        lblhY := label.new(bar_index + LabelsOffset,LastPh_vY,"Monthly MS High",color=LabelColor,style=label.style_none,textcolor=TextColor,textalign=text.align_right,size=size.small)
        label.delete(lblhY[1])
        lbllY := label.new(bar_index + LabelsOffset,LastPl_vY,"Monthly MS Low",color=LabelColor,style=label.style_none,textcolor=TextColor,textalign=text.align_right,size=size.small)
        label.delete(lbllY[1])
        
    if Show1
        lh1 := line.new(LastPh_t1,LastPh_v1,time,LastPh_v1,xloc=xloc.bar_time,color=ColorH1,style=StyleToEnum(Style1),extend=extend.right,width=Width1)
        line.delete(lh1[1])
        
        ll1 := line.new(LastPl_t1,LastPl_v1,time,LastPl_v1,xloc=xloc.bar_time,color=ColorL1,style=StyleToEnum(Style1),extend=extend.right,width=Width1)
        line.delete(ll1[1])
        
        lblh1 := label.new(bar_index + LabelsOffset,LastPh_v1,"Weekly MS High",color=LabelColor,style=label.style_none,textcolor=TextColor,textalign=text.align_right,size=size.small)
        label.delete(lblh1[1])
        lbll1 := label.new(bar_index + LabelsOffset,LastPl_v1,"Weekly MS Low",color=LabelColor,style=label.style_none,textcolor=TextColor,textalign=text.align_right,size=size.small)
        label.delete(lbll1[1])

    if Show2
        lh2 := line.new(LastPh_t2,LastPh_v2,time,LastPh_v2,xloc=xloc.bar_time,color=ColorH2,style=StyleToEnum(Style2),extend=extend.right,width=Width2)
        line.delete(lh2[1])
        
        ll2 := line.new(LastPl_t2,LastPl_v2,time,LastPl_v2,xloc=xloc.bar_time,color=ColorL2,style=StyleToEnum(Style2),extend=extend.right,width=Width2)
        line.delete(ll2[1])
        
        lblh2 := label.new(bar_index + LabelsOffset,LastPh_v2,"Daily MS High",color=LabelColor,style=label.style_none,textcolor=TextColor,textalign=text.align_right,size=size.small)
        label.delete(lblh2[1])
        lbll2 := label.new(bar_index + LabelsOffset,LastPl_v2,"Daily MS Low",color=LabelColor,style=label.style_none,textcolor=TextColor,textalign=text.align_right,size=size.small)
        label.delete(lbll2[1])
    
    if Show3
        lh3 := line.new(LastPh_t3,LastPh_v3,time,LastPh_v3,xloc=xloc.bar_time,color=ColorH3,style=StyleToEnum(Style3),extend=extend.right,width=Width3)
        line.delete(lh3[1])
        
        ll3 := line.new(LastPl_t3,LastPl_v3,time,LastPl_v3,xloc=xloc.bar_time,color=ColorL3,style=StyleToEnum(Style3),extend=extend.right,width=Width3)
        line.delete(ll3[1])
        
        lblh3 := label.new(bar_index + LabelsOffset,LastPh_v3,"4H MS High",color=LabelColor,style=label.style_none,textcolor=TextColor,textalign=text.align_right,size=size.small)
        label.delete(lblh3[1])
        lbll3 := label.new(bar_index + LabelsOffset,LastPl_v3,"4H MS Low",color=LabelColor,style=label.style_none,textcolor=TextColor,textalign=text.align_right,size=size.small)
        label.delete(lbll3[1])
    
    if Show4
        lh4 := line.new(LastPh_t4,LastPh_v4,time,LastPh_v4,xloc=xloc.bar_time,color=ColorH4,style=StyleToEnum(Style4),extend=extend.right,width=Width4)
        line.delete(lh4[1])
        
        ll4 := line.new(LastPl_t4,LastPl_v4,time,LastPl_v4,xloc=xloc.bar_time,color=ColorL4,style=StyleToEnum(Style4),extend=extend.right,width=Width4)
        line.delete(ll4[1])
        
        lblh4 := label.new(bar_index + LabelsOffset,LastPh_v4,"1H MS High",color=LabelColor,style=label.style_none,textcolor=TextColor,textalign=text.align_right,size=size.small)
        label.delete(lblh4[1])
        lbll4 := label.new(bar_index + LabelsOffset,LastPl_v4,"1H MS Low",color=LabelColor,style=label.style_none,textcolor=TextColor,textalign=text.align_right,size=size.small)
        label.delete(lbll4[1])

    if Show5
        lh5 := line.new(LastPh_t5,LastPh_v5,time,LastPh_v5,xloc=xloc.bar_time,color=ColorH5,style=StyleToEnum(Style5),extend=extend.right,width=Width5)
        line.delete(lh5[1])
        
        ll5 := line.new(LastPl_t5,LastPl_v5,time,LastPl_v5,xloc=xloc.bar_time,color=ColorL5,style=StyleToEnum(Style5),extend=extend.right,width=Width5)
        line.delete(ll5[1])
        
        lblh5 := label.new(bar_index + LabelsOffset,LastPh_v5,"30m MS High",color=LabelColor,style=label.style_none,textcolor=TextColor,textalign=text.align_right,size=size.small)
        label.delete(lblh5[1])
        lbll5 := label.new(bar_index + LabelsOffset,LastPl_v5,"30m MS Low",color=LabelColor,style=label.style_none,textcolor=TextColor,textalign=text.align_right,size=size.small)
        label.delete(lbll5[1])

    if Show6
        lh6 := line.new(LastPh_t6,LastPh_v6,time,LastPh_v6,xloc=xloc.bar_time,color=ColorH6,style=StyleToEnum(Style6),extend=extend.right,width=Width6)
        line.delete(lh6[1])
        
        ll6 := line.new(LastPl_t6,LastPl_v6,time,LastPl_v6,xloc=xloc.bar_time,color=ColorL6,style=StyleToEnum(Style6),extend=extend.right,width=Width6)
        line.delete(ll6[1])
        
        lblh6 := label.new(bar_index + LabelsOffset,LastPh_v6,"15m MS High",color=LabelColor,style=label.style_none,textcolor=TextColor,textalign=text.align_right,size=size.small)
        label.delete(lblh6[1])
        lbll6 := label.new(bar_index + LabelsOffset,LastPl_v6,"15m MS Low",color=LabelColor,style=label.style_none,textcolor=TextColor,textalign=text.align_right,size=size.small)
        label.delete(lbll6[1])

    if Show7
        lh7 := line.new(LastPh_t7,LastPh_v7,time,LastPh_v7,xloc=xloc.bar_time,color=ColorH7,style=StyleToEnum(Style7),extend=extend.right,width=Width7)
        line.delete(lh7[1])
        
        ll7 := line.new(LastPl_t7,LastPl_v7,time,LastPl_v7,xloc=xloc.bar_time,color=ColorL7,style=StyleToEnum(Style7),extend=extend.right,width=Width7)
        line.delete(ll7[1])
        
        lblh7 := label.new(bar_index + LabelsOffset,LastPh_v7,"5m MS High",color=LabelColor,style=label.style_none,textcolor=TextColor,textalign=text.align_right,size=size.small)
        label.delete(lblh7[1])
        lbll7 := label.new(bar_index + LabelsOffset,LastPl_v7,"5m MS Low",color=LabelColor,style=label.style_none,textcolor=TextColor,textalign=text.align_right,size=size.small)
        label.delete(lbll7[1])