Market Structure [TFO]
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © tradeforopp

//@version=5
indicator("Market Structure [TFO]", "Market Structure [TFO]", true, max_labels_count = 500, max_lines_count = 500)

pivot_strength = input.int(3, "Pivot Strength", 1)
show_pivots = input.bool(false, "Show Pivots", inline = "PIV")
highs = input.color(color.blue, "", inline = "PIV")
lows = input.color(#f23645, "", inline = "PIV")
show_bos = input.bool(false, "Show BOS/MSS")
style = input.string("Dashed", "Line Style", options = ['Solid', 'Dashed', 'Dotted'])

type swing
    int _index = na
    float _val = na

method set_val(swing s, int i, float v) =>
    s._index := i
    s._val := v

method set_na(swing s) =>
    s._index := na
    s._val := na

var swing_high = swing.new()
var swing_low = swing.new()
var temp_hi = swing.new()
var temp_lo = swing.new()

var bool bull = na

sh = false
sl = false

bull_bos = false
bull_mss = false
bear_bos = false
bear_mss = false

var line_style = switch style
    "Solid" => line.style_solid
    "Dashed" => line.style_dashed
    "Dotted" => line.style_dotted

if not na(ta.pivothigh(high, pivot_strength, pivot_strength))
    swing_high.set_val(bar_index - pivot_strength, high[pivot_strength])
    sh := true
    
if not na(ta.pivotlow(low, pivot_strength, pivot_strength))
    swing_low.set_val(bar_index - pivot_strength, low[pivot_strength])
    sl := true

if not na(swing_high._val)
    if close > swing_high._val 
        mss = (bull == false or na(bull))
        if mss
            bull_mss := true
            temp_hi.set_val(swing_high._index, swing_high._val)
        else
            bull_bos := true
            temp_hi.set_val(swing_high._index, swing_high._val)
        bull := true
        swing_high.set_na()
        
if not na(swing_low._val)
    if close < swing_low._val
        mss = (bull == true or na(bull))
        if mss
            bear_mss := true
            temp_lo.set_val(swing_low._index, swing_low._val)
        else
            bear_bos := true
            temp_lo.set_val(swing_low._index, swing_low._val)
        bull := false
        swing_low.set_na()

if show_bos
    if bull_mss[1] or bull_bos[1]
        line.new(temp_hi._index, temp_hi._val, bar_index - 1, temp_hi._val, style = line_style, color = highs)
        label.new(math.floor(math.avg(temp_hi._index, bar_index - 1)), temp_hi._val, bull_mss[1] ? "MSS" : "BOS", textcolor = highs, color = #ffffff00, style = label.style_label_down)

    if bear_mss[1] or bear_bos[1]
        line.new(temp_lo._index, temp_lo._val, bar_index - 1, temp_lo._val, style = line_style, color = lows)
        label.new(math.floor(math.avg(temp_lo._index, bar_index - 1)), temp_lo._val, bear_mss[1] ? "MSS" : "BOS", textcolor = lows, color = #ffffff00, style = label.style_label_up)

plotshape(show_pivots and sh, style = shape.triangledown, location = location.abovebar, color = highs, offset = -pivot_strength, size = size.tiny)
plotshape(show_pivots and sl, style = shape.triangleup, location = location.belowbar, color = lows, offset = -pivot_strength, size = size.tiny)

any_mss = bull_mss or bear_mss
any_bos = bull_bos or bear_bos

alertcondition(any_mss[1], "Any MSS")
alertcondition(any_bos[1], "Any BOS")

alertcondition(bull_mss[1], "Bull MSS")
alertcondition(bull_bos[1], "Bull BOS")

alertcondition(bear_mss[1], "Bear MSS")
alertcondition(bear_bos[1], "Bear BOS")