Remove label from zones like RBR, DBR and extend zone box to current price and sometimes distal line is placed on the lowest point of RBR Formation Bottom but we want to place distal line on lowest Point of Base Candles in RBR Formation: //@version=5
indicator("Advanced Demand Zone Detector with Proximal Line Adjustments", overlay=true)


// User Inputs
base_candles = input.int(2, "Number of Base Candles", minval=1, maxval=6)
small_range_multiplier = input.float(0.5, "Base Candle Range Multiplier", minval=0.1, step=0.1)
atr_length = input.int(14, "ATR Length", minval=1)


// Calculations
avg_range = ta.sma(ta.tr, atr_length)


// Arrays to store zones and associated data
var box[] demand_zones = array.new<box>()
var line[] distal_lines = array.new<line>()
var line[] proximal_lines = array.new<line>()
var label[] zone_labels = array.new<label>()
var float[] zone_lows = array.new_float()
var float[] zone_highs = array.new_float()
var float[] proximal_prices = array.new_float()
var int[] zone_types = array.new_int()  // 1 for RBR, 2 for DBR


// Function to check for violation
f_check_violation(index) =>
    zone_low = array.get(zone_lows, index)
    zone_high = array.get(zone_highs, index)
    proximal_price = array.get(proximal_prices, index)
    // For Demand Zones, violation occurs when price closes below the zone_low
    if close < zone_low
        // Remove box, lines, and label
        box.delete(array.get(demand_zones, index))
        line.delete(array.get(distal_lines, index))
        line.delete(array.get(proximal_lines, index))
        label.delete(array.get(zone_labels, index))
        // Remove from arrays
        array.remove(demand_zones, index)
        array.remove(distal_lines, index)
        array.remove(proximal_lines, index)
        array.remove(zone_labels, index)
        array.remove(zone_lows, index)
        array.remove(zone_highs, index)
        array.remove(proximal_prices, index)
        array.remove(zone_types, index)


// RBR Detection


// Check if initial rally candle before base candles is bullish
rally1 = close[base_candles + 1] > open[base_candles + 1]


// Initialize variables
base = true
total_base_size = 0.0
float proximal_price = na  // Explicitly declare the variable type


// Check base candles and find proximal price
for i = 0 to base_candles - 1
    idx = base_candles - i
    base_candle_size = math.abs(close[idx] - open[idx])
    base := base and base_candle_size < avg_range[idx] * small_range_multiplier
    total_base_size += base_candle_size
    // Calculate candle body top
    body_top = math.max(open[idx], close[idx])
    proximal_price := na(proximal_price) ? body_top : math.max(proximal_price, body_top)


avg_base_size = total_base_size / base_candles


// Legout candle is current candle
legout_candle_size = math.abs(close - open)


// Check if legout candle is bullish and its size is more than double the avg base candle size
rally2 = (close > open) and (legout_candle_size > 2 * avg_base_size)


// Ensure overall upward movement
overall_up = close > close[base_candles + 1]


// Determine if pattern is RBR
isRBR = rally1 and base and rally2 and overall_up


// DBR Detection


// Check if initial drop candle before base candles is bearish
drop1 = close[base_candles + 1] < open[base_candles + 1]


// Initialize variables
base_d = true
total_base_size_d = 0.0
float proximal_price_d = na  // Explicitly declare the variable type


// Check base candles and find proximal price
for i = 0 to base_candles - 1
    idx = base_candles - i
    base_candle_size_d = math.abs(close[idx] - open[idx])
    base_d := base_d and base_candle_size_d < avg_range[idx] * small_range_multiplier
    total_base_size_d += base_candle_size_d
    // Calculate candle body top
    body_top_d = math.max(open[idx], close[idx])
    proximal_price_d := na(proximal_price_d) ? body_top_d : math.max(proximal_price_d, body_top_d)


avg_base_size_d = total_base_size_d / base_candles


// Legout candle is current candle
legout_candle_size_d = math.abs(close - open)


// Check if legout candle is bullish and its size is more than double the avg base candle size
rally = (close > open) and (legout_candle_size_d > 2 * avg_base_size_d)


// Ensure overall upward movement
overall_up_d = close > close[base_candles + 1]


// Determine if pattern is DBR
isDBR = drop1 and base_d and rally and overall_up_d


// Plot Demand Zones
if isRBR or isDBR
    // Determine the base zone
    idx_legin = base_candles + 1  // Index of leg-in candle
    idx_legout = 0                // Index of leg-out candle (current candle)


    // Initialize zone_high and zone_low
    zone_high = high[idx_legin]
    zone_low = low[idx_legin]


    // Find the highest high and lowest low of leg-in, base candles, and leg-out
    i = idx_legin
    while i >= idx_legout
        candle_high = high[i]
        candle_low = low[i]
        zone_high := math.max(zone_high, candle_high)
        zone_low := math.min(zone_low, candle_low)
        i := i - 1  // Decrement the index


    // Determine proximal price
    proximal_price_final = isRBR ? proximal_price : proximal_price_d


    // Draw a rectangle to represent the demand zone, with top at proximal_price
    zone_start = bar_index - base_candles - 1  // Start from leg-in candle
    zone_end = bar_index + 100  // Extend into the future (adjust as needed)
    color_zone = isRBR ? color.new(color.green, 80) : color.new(color.blue, 80)
    demand_zone = box.new(left=zone_start, top=proximal_price_final, right=zone_end, bottom=zone_low, xloc=xloc.bar_index, border_color=color_zone, bgcolor=color_zone)


    // Store the new box and zone data
    array.push(demand_zones, demand_zone)
    array.push(zone_lows, zone_low)
    array.push(zone_highs, proximal_price_final)  // Use proximal_price_final as zone_high
    array.push(proximal_prices, proximal_price_final)
    array.push(zone_types, isRBR ? 1 : 2)  // 1 for RBR, 2 for DBR


    // Draw distal line at the lowest low of the formation
    distal_price = zone_low  // For demand zones, distal line is at the zone low
    distal_line = line.new(x1=zone_start, y1=distal_price, x2=zone_end, y2=distal_price, xloc=xloc.bar_index, color=color.red, style=line.style_dashed, width=2)
    array.push(distal_lines, distal_line)


    // Draw proximal line at the proximal_price_final
    proximal_line = line.new(x1=zone_start, y1=proximal_price_final, x2=zone_end, y2=proximal_price_final, xloc=xloc.bar_index, color=color.green, style=line.style_solid, width=2)
    array.push(proximal_lines, proximal_line)


    // Plot labels
    zone_label = label.new(zone_start, proximal_price_final, isRBR ? "RBR Demand Zone" : "DBR Demand Zone", xloc=xloc.bar_index, style=label.style_label_down, color=color.yellow, textcolor=color.black)
    array.push(zone_labels, zone_label)


// Check for violations and remove violated zones
i = array.size(demand_zones) - 1
while i >= 0
    f_check_violation(i)
    i := i - 1  // Decrement index


// Include an invisible plot to force the indicator to overlay on the main chart
plot(close, title="Invisible Plot", display=display.none)