ATR Visualizer
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © peacefulLizard50262

//@version=5
indicator("Range", overlay = true)

length   = input.int(10, "Length", 1)
candle_1 = input.string("Bear/Bull Range", "Style", ["Bear/Bull Range", "Bearish Range", "Bullish Range","Average Range", "Cumulative Average Range"])
candle_2 = input.string("Disabled", "Style", ["Disabled", "Bear/Bull Range", "Bearish Range", "Bullish Range","Average Range", "Cumulative Average Range"])


bullish_color = input.color(color.green, "Color", inline = "color")
even_color    = input.color(color.gray, "", inline = "color")
bearish_color = input.color(color.red, "", inline = "color")

ema(source)=>
    var float ema = 0.0
    var int count = 0
    if source != 0
        count := nz(count[1]) + 1
        ema := (1.0 - 2.0 / (count + 1.0)) * nz(ema[1]) + 2.0 / (count + 1.0) * source
    ema

bullish_average_body(length)=>
    var float ema = 0.0
    if close > open
        ema := (1.0 - 2.0 / (length + 1.0)) * nz(ema[1]) + 2.0 / (length + 1.0) * math.abs(close - open)
    ema

bullish_average_top_wick(length)=>
    var float ema = 0.0
    wick = close > open ? math.abs(high - close) : math.abs(high - open)
    if wick != 0 and close > open
        ema := (1.0 - 2.0 / (length + 1.0)) * nz(ema[1]) + 2.0 / (length + 1.0) * wick
    ema

bullish_average_bottom_wick(length)=>
    var float ema = 0.0
    wick = close > open ? math.abs(open - low) : math.abs(close - low)
    if wick != 0 and close > open
        ema := (1.0 - 2.0 / (length + 1.0)) * nz(ema[1]) + 2.0 / (length + 1.0) * wick
    ema

bearish_average_body(length)=>
    var float ema = 0.0
    if close < open
        ema := (1.0 - 2.0 / (length + 1.0)) * nz(ema[1]) + 2.0 / (length + 1.0) * math.abs(open - close)
    ema

bearish_average_top_wick(length)=>
    var float ema = 0.0
    wick = close > open ? math.abs(high - close) : math.abs(high - open)
    if wick != 0 and close < open
        ema := (1.0 - 2.0 / (length + 1.0)) * nz(ema[1]) + 2.0 / (length + 1.0) * wick
    ema

bearish_average_bottom_wick(length)=>
    var float ema = 0.0
    wick = close > open ? math.abs(open - low) : math.abs(close - low)
    if wick != 0 and close < open
        ema := (1.0 - 2.0 / (length + 1.0)) * nz(ema[1]) + 2.0 / (length + 1.0) * wick
    ema

windowed_top_wick(length)=>
    ta.rma(close > open ? math.abs(high - close) : math.abs(high - open), length)

windowed_bottom_wick(length)=>
    ta.rma(close > open ? math.abs(open - low) : math.abs(close - low), length)

windowed_bear_bull_ratio(length = 10)=>
    bull_count = 0
    bear_count = 0
    
    for i = 0 to length - 1
        if open[i] < close[i] 
            bull_count += 1
        if open[i] > close[i] 
            bear_count += 1
        log_bear_bull_ratio = math.log(bull_count / bear_count)

bear_bull_ratio()=>
    var bull_count = 0
    var bear_count = 0
    
    if open < close 
        bull_count += 1
    if open > close 
        bear_count += 1
    
    log_bear_bull_ratio = math.log(bull_count / bear_count)

average_body = ema(math.abs(open - close))
average_top_wick = ema(open < close ? high - close : high - open)
average_bottom_wick = ema(open < close ? open - low : close - low)

bear_bull_ratio = bear_bull_ratio()

bear_bull_ratio_status = bear_bull_ratio >= 0

center = 0
average_open = bear_bull_ratio_status ? center - average_body / 2 : center + average_body / 2
average_close = bear_bull_ratio_status ? center + average_body / 2 : center - average_body / 2
average_high = bear_bull_ratio_status ? average_close + average_top_wick : average_open + average_top_wick
average_low = bear_bull_ratio_status ? average_open - average_bottom_wick : average_close - average_bottom_wick

top_value = bear_bull_ratio_status ? average_close : average_open
bottom_value = bear_bull_ratio_status ? average_open : average_close

average_color = bear_bull_ratio > 0 ? bullish_color : bear_bull_ratio < 0 ? bearish_color : even_color

windowed_body = ta.ema(ta.tr, length)
windowed_top_wick = windowed_top_wick(length)
windowed_bottom_wick = windowed_bottom_wick(length)
windowed_bear_bull_ratio = windowed_bear_bull_ratio(length)
windowed_condition = windowed_bear_bull_ratio >= 0
windowed_color = windowed_bear_bull_ratio > 0 ? bullish_color : windowed_bear_bull_ratio < 0 ? bearish_color : even_color

windowed_open = windowed_condition ? center - windowed_body / 2 : center + windowed_body / 2
windowed_close = windowed_condition ? center + windowed_body / 2 : center - windowed_body / 2
windowed_high = windowed_condition ? windowed_close + windowed_top_wick : windowed_open + windowed_top_wick
windowed_low = windowed_condition ? windowed_open - windowed_bottom_wick : windowed_close - windowed_bottom_wick

windowed_top_value = windowed_condition ? average_close : average_open
windowed_bottom_value = windowed_condition ? average_open : average_close

bullish_average_body = bullish_average_body(length)
bullish_average_top_wick = bullish_average_top_wick(length)
bullish_average_bottom_wick = bullish_average_bottom_wick(length)

bullish_close = center + bullish_average_body / 2 
bullish_open = center - bullish_average_body / 2
bullish_high = bullish_close + bullish_average_top_wick
bullish_low =  bullish_open - bullish_average_bottom_wick

bearish_average_body = bearish_average_body(length)
bearish_average_top_wick = bearish_average_top_wick(length)
bearish_average_bottom_wick = bearish_average_bottom_wick(length)

bearish_open = center + bearish_average_body / 2
bearish_close = center - bearish_average_body / 2 
bearish_high = bearish_open + bearish_average_top_wick
bearish_low =  bearish_close - bearish_average_bottom_wick

candle_state = close > open

current_color = candle_state ? bullish_color : bearish_color

current_body = math.abs(close - open)
current_top_wick = candle_state ? math.abs(high - close) : math.abs(high - open)
current_bottom_wick = candle_state ? math.abs(open - low) : math.abs(close - low)

current_open = candle_state ? center - current_body / 2 : center + current_body / 2
current_close = candle_state ? center + current_body / 2 : center - current_body / 2
current_high = candle_state ? current_close + current_top_wick : current_open + current_top_wick
current_low = candle_state ? current_open - current_bottom_wick : current_close - current_bottom_wick

current_top = candle_state ? current_close : current_open
current_bottom = candle_state ? current_open : current_close

oc2 = math.avg(open, close)

type candle 
    box body
    line top_wick
    line bottom_wick

method delete(candle id)=>
    box.delete(id.body)
    line.delete(id.top_wick)
    line.delete(id.bottom_wick)

type position 
    int x1 = na
    int x2 = na
    int x3 = na


type values
    float t = na
    float b = na
    float h = na
    float l = na
    color c = na

bullish_values = values.new(
         bullish_close[1] + oc2 
         , bullish_open[1]  + oc2
         , bullish_high[1] + oc2 
         , bullish_low[1]  + oc2
         , bullish_color
         )

bearish_values = values.new(
 bearish_open[1] + oc2 
 , bearish_close[1]  + oc2
 , bearish_high[1] + oc2 
 , bearish_low[1]  + oc2 
 , bearish_color
 )

windowed_values = values.new(
   windowed_top_value[1] + oc2
 , windowed_bottom_value[1] + oc2
 , windowed_high[1] + oc2
 , windowed_low[1] + oc2
 , windowed_color
 )

average_values = values.new(
   top_value[1] + oc2
 , bottom_value[1] + oc2
 , average_high[1] + oc2
 , average_low[1] + oc2
 , average_color
 )

bear_bull_values()=>
    switch close > open
        true  => bullish_values
        false => bearish_values


first_position = position.new(
   bar_index + 1
 , bar_index + 3
 , bar_index + 2
 )

second_position = position.new(
   bar_index + 4
 , bar_index + 6
 , bar_index + 5
 )

candle_values(string style)=>
    values out = switch style
        "Disabled"                 => values.new()
        "Bear/Bull Range"          => bear_bull_values()
        "Bearish Range"            => bearish_values
        "Bullish Range"            => bullish_values
        "Average Range"            => windowed_values
        "Cumulative Average Range" => average_values
    out

candle_1_values = candle_values(candle_1)
candle_2_values = candle_values(candle_2)

first_candle = candle.new(box.new(first_position.x1, candle_1_values.t, first_position.x2, candle_1_values.b, candle_1_values.c, bgcolor = candle_1_values.c)
 , line.new(first_position.x3, candle_1_values.t, first_position.x3, candle_1_values.h, color = candle_1_values.c)
 , line.new(first_position.x3, candle_1_values.b, first_position.x3, candle_1_values.l, color = candle_1_values.c)
 )
second_candle = candle.new(box.new(second_position.x1, candle_2_values.t, second_position.x2, candle_2_values.b, candle_2_values.c, bgcolor = candle_2_values.c)
 , line.new(second_position.x3, candle_2_values.t, second_position.x3, candle_2_values.h, color = candle_2_values.c)
 , line.new(second_position.x3, candle_2_values.b, second_position.x3, candle_2_values.l, color = candle_2_values.c)
 )

if barstate.isconfirmed
    first_candle.delete()
    second_candle.delete()
