Use High or Low of Candle for BOS as ChoCh: //@version=5
indicator(title="BoS and ChoCh Indicator", shorttitle="BoS & ChoCh Indicator", overlay=true, max_lines_count=500, max_labels_count=500)

// Input parameters
swingLookback = input.int(title="Swing Lookback Period", defval=3, minval=1, maxval=20)
showBoS = input.bool(title="Show Break of Structure (BoS)", defval=true)
showChoCh = input.bool(title="Show Change of Character (ChoCh)", defval=true)
showLabels = input.bool(title="Show Labels", defval=true)
lineExtension = input.string(title="Line Extension", defval="Right", options=["None", "Right", "Both"])
higherTF = input.timeframe(title="Higher Timeframe", defval="", tooltip="Leave empty to use current timeframe")

// Map line extension to extend parameter
extend_mode = switch lineExtension
    "None" => extend.none
    "Right" => extend.right
    "Both" => extend.both
    => extend.right

// Function to detect swings and times
f_detectSwings(_swingLookback) =>
    // Identify swing highs and lows
    swh = ta.pivothigh(high, _swingLookback, _swingLookback)
    int swhTime = na
    if not na(swh)
        swhTime := time[_swingLookback]
    swl = ta.pivotlow(low, _swingLookback, _swingLookback)
    int swlTime = na
    if not na(swl)
        swlTime := time[_swingLookback]
    [swh, swhTime, swl, swlTime]

// Variables to store swing highs and lows
var float[] swingHighs = array.new_float()
var int[] swingHighTimes = array.new_int()
var float[] swingLows = array.new_float()
var int[] swingLowTimes = array.new_int()

// Get swings from higher timeframe if specified
[swh, swhTime, swl, swlTime] = request.security(syminfo.tickerid, higherTF == "" ? timeframe.period : higherTF, f_detectSwings(swingLookback), barmerge.gaps_off, barmerge.lookahead_off)

// Update swing highs and lows arrays
if not na(swh)
    array.unshift(swingHighs, swh)
    array.unshift(swingHighTimes, swhTime)
    if array.size(swingHighs) > 10
        array.pop(swingHighs)
        array.pop(swingHighTimes)

if not na(swl)
    array.unshift(swingLows, swl)
    array.unshift(swingLowTimes, swlTime)
    if array.size(swingLows) > 10
        array.pop(swingLows)
        array.pop(swingLowTimes)

// Determine the current trend
var string trend = na
if array.size(swingHighs) >= 2 and array.size(swingLows) >= 2
    lastSwingHigh = array.get(swingHighs, 0)
    prevSwingHigh = array.get(swingHighs, 1)
    lastSwingLow = array.get(swingLows, 0)
    prevSwingLow = array.get(swingLows, 1)

    // If last swing high is higher than previous swing high and last swing low is higher than previous swing low
    if lastSwingHigh > prevSwingHigh and lastSwingLow > prevSwingLow
        trend := "Uptrend"
    // If last swing high is lower than previous swing high and last swing low is lower than previous swing low
    else if lastSwingHigh < prevSwingHigh and lastSwingLow < prevSwingLow
        trend := "Downtrend"
    else
        trend := "Sideways"

// Variables to hold BoS and ChoCh lines and labels
var line bosLine = na
var label bosLabel = na
var line chochLine = na
var label chochLabel = na

// Variables to store event times
var int bosTime = na
var int chochTime = na

// Detect BoS and ChoCh based on trend
if trend == "Uptrend"
    // Break of Structure (BoS) to the upside
    if showBoS and close > array.get(swingHighs, 0)
        bosTime := time
        // Delete previous BoS line and label
        if not na(bosLine)
            line.delete(bosLine)
        if not na(bosLabel)
            label.delete(bosLabel)
        // Draw BoS line
        bosLine := line.new(x1=array.get(swingHighTimes, 0), y1=array.get(swingHighs, 0), x2=bosTime, y2=array.get(swingHighs, 0), xloc=xloc.bar_time, extend=extend_mode, color=color.green, width=2)
        // Add label
        if showLabels
            bosLabel := label.new(x=bosTime, y=array.get(swingHighs, 0), text="BoS High", xloc=xloc.bar_time, style=label.style_label_down, color=color.new(color.green, 0), textcolor=color.white, size=size.tiny)
    // Change of Character (ChoCh) to the downside
    if showChoCh and low < array.get(swingLows, 0)
        chochTime := time
        // Delete previous ChoCh line and label
        if not na(chochLine)
            line.delete(chochLine)
        if not na(chochLabel)
            label.delete(chochLabel)
        // Draw ChoCh line
        chochLine := line.new(x1=array.get(swingLowTimes, 0), y1=array.get(swingLows, 0), x2=chochTime, y2=array.get(swingLows, 0), xloc=xloc.bar_time, extend=extend_mode, color=color.orange, width=2)
        // Add label
        if showLabels
            chochLabel := label.new(x=chochTime, y=array.get(swingLows, 0), text="ChoCh Low", xloc=xloc.bar_time, style=label.style_label_up, color=color.new(color.orange, 0), textcolor=color.white, size=size.tiny)
        // Reset trend
        trend := "Downtrend"

else if trend == "Downtrend"
    // Break of Structure (BoS) to the downside
    if showBoS and close < array.get(swingLows, 0)
        bosTime := time
        // Delete previous BoS line and label
        if not na(bosLine)
            line.delete(bosLine)
        if not na(bosLabel)
            label.delete(bosLabel)
        // Draw BoS line
        bosLine := line.new(x1=array.get(swingLowTimes, 0), y1=array.get(swingLows, 0), x2=bosTime, y2=array.get(swingLows, 0), xloc=xloc.bar_time, extend=extend_mode, color=color.red, width=2)
        // Add label
        if showLabels
            bosLabel := label.new(x=bosTime, y=array.get(swingLows, 0), text="BoS Low", xloc=xloc.bar_time, style=label.style_label_up, color=color.new(color.red, 0), textcolor=color.white, size=size.tiny)
    // Change of Character (ChoCh) to the upside
    if showChoCh and high > array.get(swingHighs, 0)
        chochTime := time
        // Delete previous ChoCh line and label
        if not na(chochLine)
            line.delete(chochLine)
        if not na(chochLabel)
            label.delete(chochLabel)
        // Draw ChoCh line
        chochLine := line.new(x1=array.get(swingHighTimes, 0), y1=array.get(swingHighs, 0), x2=chochTime, y2=array.get(swingHighs, 0), xloc=xloc.bar_time, extend=extend_mode, color=color.purple, width=2)
        // Add label
        if showLabels
            chochLabel := label.new(x=chochTime, y=array.get(swingHighs, 0), text="ChoCh High", xloc=xloc.bar_time, style=label.style_label_down, color=color.new(color.purple, 0), textcolor=color.white, size=size.tiny)
        // Reset trend
        trend := "Uptrend"

// --- Display Current Trend Label on Top Right Corner of Chart ---

// Create a table to display the trend
var table trendTable = table.new(position.top_right, 1, 1, border_width = 1)

// Update the table with the current trend
if barstate.islast and not na(trend)
    // Define background color based on trend
    bgcolor = trend == "Uptrend" ? color.new(color.green, 80) : trend == "Downtrend" ? color.new(color.red, 80) : color.new(color.gray, 80)
    // Update the table cell
    table.cell(trendTable, 0, 0, text = "Current Trend:\n" + trend, text_color = color.white, bgcolor = bgcolor, text_halign = text.align_center, text_valign = text.align_center)