What this indicator do: //@version=5
indicator("Support and Resistance Levels with Time Frame Filter", overlay=true)

// Input parameters
lookbackPeriod = input.int(50, title="Lookback Period for Support/Resistance")
flexibility = input.float(0.01, title="Flexibility Percentage", minval=0.0, step=0.01) / 100
supportRise = input.float(0.5, title="Minimum Green Candle Price Rise (%)", minval=0.0, step=0.1) / 100
resistanceFall = input.float(0.5, title="Minimum Red Candle Price Fall (%)", minval=0.0, step=0.1) / 100
daysToCheck = input.int(1, title="Days to Check for Support/Resistance Level", minval=1)
showSupport = input.bool(true, title="Show Support Levels")
showResistance = input.bool(true, title="Show Resistance Levels")
showBrokenLevels = input.bool(false, title="Show Only Broken Support and Resistance Levels")
maxBrokenTimes = input.int(2, title="Hide Levels Broken More Than N Times", minval=1)

// Time frame inputs
tf1 = input.string("60", title="Time Frame 1")
tf2 = input.string("120", title="Time Frame 2")
tf3 = input.string("240", title="Time Frame 3")
tf4 = input.string("D", title="Time Frame 4")

// Check if current chart's time frame matches any of the specified time frames
showLevels = (timeframe.period == tf1) or (timeframe.period == tf2) or (timeframe.period == tf3) or (timeframe.period == tf4)

// Variables to store support and resistance levels and their broken counts
var float[] supportLevels = na
var int[] supportBrokenCounts = na
var line[] supportLines = na

var float[] resistanceLevels = na
var int[] resistanceBrokenCounts = na
var line[] resistanceLines = na

// Variables to store the latest support and resistance levels for alerts
var float latestSupportLevel = na
var float latestResistanceLevel = na

if showLevels
    // Initialize arrays if they are na
    if na(supportLevels)
        supportLevels := array.new_float()
        supportBrokenCounts := array.new_int()
        supportLines := array.new_line()
    if na(resistanceLevels)
        resistanceLevels := array.new_float()
        resistanceBrokenCounts := array.new_int()
        resistanceLines := array.new_line()
    
    // Ensure we have at least 2 bars of data before proceeding
    if bar_index >= 1

        // Check for support formations
        for i = 1 to lookbackPeriod

            if i > bar_index
                break  // Prevent accessing bars that don't exist

            // Check for support formation
            if close[i] < open[i] and close[i - 1] > open[i - 1] and math.abs(close[i] - open[i - 1]) <= (close[i - 1] * flexibility) and (close[i - 1] - open[i - 1]) >= (open[i - 1] * supportRise) and (timenow - time[i]) <= daysToCheck * 86400000

                supportLevel = close[i]

                // Check if this level is already in the supportLevels array
                isNewLevel = true
                if array.size(supportLevels) > 0
                    for k = 0 to array.size(supportLevels) - 1
                        existingLevel = array.get(supportLevels, k)
                        if math.abs(existingLevel - supportLevel) <= syminfo.mintick * 10
                            isNewLevel := false
                            break
                if isNewLevel
                    array.push(supportLevels, supportLevel)
                    array.push(supportBrokenCounts, 0)
                    // Create line object
                    supportLine = line.new(x1=math.max(0, bar_index - i), y1=supportLevel, x2=bar_index + 100, y2=supportLevel, color=color.green, width=2, extend=extend.right)
                    array.push(supportLines, supportLine)

        // Check for resistance formations
        for i = 1 to lookbackPeriod

            if i > bar_index
                break  // Prevent accessing bars that don't exist

            // Check for resistance formation
            if close[i] > open[i] and close[i - 1] < open[i - 1] and math.abs(close[i] - open[i - 1]) <= (close[i - 1] * flexibility) and (open[i - 1] - close[i - 1]) >= (open[i - 1] * resistanceFall) and (timenow - time[i]) <= daysToCheck * 86400000

                resistanceLevel = close[i]

                // Check if this level is already in the resistanceLevels array
                isNewLevel = true
                if array.size(resistanceLevels) > 0
                    for k = 0 to array.size(resistanceLevels) - 1
                        existingLevel = array.get(resistanceLevels, k)
                        if math.abs(existingLevel - resistanceLevel) <= syminfo.mintick * 10
                            isNewLevel := false
                            break
                if isNewLevel
                    array.push(resistanceLevels, resistanceLevel)
                    array.push(resistanceBrokenCounts, 0)
                    // Create line object
                    resistanceLine = line.new(x1=math.max(0, bar_index - i), y1=resistanceLevel, x2=bar_index + 100, y2=resistanceLevel, color=color.red, width=2, extend=extend.right)
                    array.push(resistanceLines, resistanceLine)

        // Update and draw support levels
        jSupport = array.size(supportLevels) - 1
        while jSupport >= 0

            supportLevel = array.get(supportLevels, jSupport)
            brokenCount = array.get(supportBrokenCounts, jSupport)
            supportLine = array.get(supportLines, jSupport)

            // Check if level is broken
            isBroken = brokenCount > 0

            // Increment broken count if level is broken
            if close < supportLevel and brokenCount < maxBrokenTimes
                brokenCount := brokenCount + 1
                array.set(supportBrokenCounts, jSupport, brokenCount)
                isBroken := true

            // Delete the level if broken more than allowed times
            if brokenCount >= maxBrokenTimes
                line.delete(supportLine)
                array.remove(supportLevels, jSupport)
                array.remove(supportBrokenCounts, jSupport)
                array.remove(supportLines, jSupport)
            else
                // Update line properties based on user inputs
                showLine = showSupport and ((not showBrokenLevels) or (showBrokenLevels and isBroken))
                line.set_extend(supportLine, showLine ? extend.right : extend.none)
                line.set_color(supportLine, showLine ? color.green : color.new(color.green, 100))
                line.set_x2(supportLine, bar_index + 100)

            jSupport := jSupport - 1

        // Update and draw resistance levels
        jResistance = array.size(resistanceLevels) - 1
        while jResistance >= 0

            resistanceLevel = array.get(resistanceLevels, jResistance)
            brokenCount = array.get(resistanceBrokenCounts, jResistance)
            resistanceLine = array.get(resistanceLines, jResistance)

            // Check if level is broken
            isBroken = brokenCount > 0

            // Increment broken count if level is broken
            if close > resistanceLevel and brokenCount < maxBrokenTimes
                brokenCount := brokenCount + 1
                array.set(resistanceBrokenCounts, jResistance, brokenCount)
                isBroken := true

            // Delete the level if broken more than allowed times
            if brokenCount >= maxBrokenTimes
                line.delete(resistanceLine)
                array.remove(resistanceLevels, jResistance)
                array.remove(resistanceBrokenCounts, jResistance)
                array.remove(resistanceLines, jResistance)
            else
                // Update line properties based on user inputs
                showLine = showResistance and ((not showBrokenLevels) or (showBrokenLevels and isBroken))
                line.set_extend(resistanceLine, showLine ? extend.right : extend.none)
                line.set_color(resistanceLine, showLine ? color.red : color.new(color.red, 100))
                line.set_x2(resistanceLine, bar_index + 100)

            jResistance := jResistance - 1

        // Update latest support and resistance levels
        latestSupportLevel := array.size(supportLevels) > 0 ? array.get(supportLevels, array.size(supportLevels) - 1) : na
        latestResistanceLevel := array.size(resistanceLevels) > 0 ? array.get(resistanceLevels, array.size(resistanceLevels) - 1) : na
else
    // If showLevels is false, delete existing lines and reset arrays
    if not na(supportLines)
        for l = 0 to array.size(supportLines) - 1
            lineToDelete = array.get(supportLines, l)
            line.delete(lineToDelete)
        supportLevels := na
        supportBrokenCounts := na
        supportLines := na

    if not na(resistanceLines)
        for l = 0 to array.size(resistanceLines) - 1
            lineToDelete = array.get(resistanceLines, l)
            line.delete(lineToDelete)
        resistanceLevels := na
        resistanceBrokenCounts := na
        resistanceLines := na

    // Reset latest levels
    latestSupportLevel := na
    latestResistanceLevel := na

// Alerts for broken support and resistance levels (must be in global scope)
alertcondition(not na(latestSupportLevel) and close < latestSupportLevel, title="Support Level Broken", message="A support level has been broken.")
alertcondition(not na(latestResistanceLevel) and close > latestResistanceLevel, title="Resistance Level Broken", message="A resistance level has been broken.")