Liquidity Candles
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © zathruswriter

//@version=5
indicator( "Liquidity Candles", overlay = true, max_lines_count = 500, max_labels_count = 500, max_bars_back = 4500 )

liq_line_color = input.color( color.black, "Liquidity Line", inline="liq" )
liq_line_style = input.string( line.style_solid, "", options = [ line.style_solid, line.style_dashed, line.style_dotted ], inline="liq" )
liq_line_width = input.int( 2, "", inline="liq" )
liq_color_by_type = input.bool( false, "Color liquidity lines by break type (red/green)" )
i_show_potentials = input.bool( false, "Mark Potential Breakout Candles" )
i_show_liq_labels = input.bool( false, "Show Liquidity Labels" )
size = input.float( 0.07, "Big Candle Minimum Size", minval = 0.01, step = 0.1, inline = "candlesize" )
percentage = input.bool( true, "Percentage", inline = "candlesize", tooltip = "In order to prevent calculating liquidity sweeps on very small candles, you can say how big a candle should be at least to consider it for the sweep calculation. This setting affects both, candles where a potential place for the sweep occurs (marked with red/green diamonds) and the candles where the sweep actually occurs (i.e. where the red/green sweep line ends)." )
min_pullback = input.float( 30, "Minimum Pullback %", step = 1, tooltip = "How much should a candle body retrace from its high point (green candles) or low point (red candles) in order to be considered for a liquidity sweep calculation." )

var pullback_type = ""
var pullback_level = 0.0
var pullback_index = 0

transparentcolor = color.new( color.white, 100 )


s_( txt ) =>
    str.tostring( txt )

f_debug_label( txt ) =>
    label.new(bar_index, high, str.tostring( txt ), color = color.lime, textcolor = color.black)

f_debug_label_down( txt ) =>
    label.new(bar_index, low, str.tostring( txt ), color = color.lime, textcolor = color.black, style = label.style_label_up)


// reset pullback level and type if we've closed above/below the pullback we are waiting for
if ( pullback_type == "up" and ( close > pullback_level or open > pullback_level ) ) or ( pullback_type == "down" and ( close < pullback_level or open < pullback_level ) )
    pullback_type := ""
    pullback_level := 0.0
    pullback_index := 0

// check for liquidity sweep
bearish_pullback = false
bullish_pullback = false

if barstate.isconfirmed and ( ( pullback_type == "up" and high > pullback_level and close <= pullback_level and open <= pullback_level ) or ( pullback_type == "down" and low < pullback_level and close >= pullback_level and open >= pullback_level ) )
    line.new( pullback_index, pullback_level, bar_index, pullback_level, color = ( liq_color_by_type ? ( pullback_type == "up" ? color.red : color.green ) : liq_line_color ), style = liq_line_style, width = liq_line_width )
    if i_show_liq_labels
        label.new( pullback_index, pullback_level, "X", color = transparentcolor, textcolor = ( liq_color_by_type ? ( pullback_type == "up" ? color.red : color.green ) : liq_line_color ), style = pullback_type == "up" ? label.style_label_down : label.style_label_up )

    if pullback_type == "up"
        bearish_pullback := true
    else
        bullish_pullback := true

    // reset variables, since we already found a pullback
    pullback_type := ""
    pullback_level := 0.0
    pullback_index := 0

show_up_shape = false
show_down_shape = false
candle_size = percentage ? close * size / 100 : size
pullback_value = ( ( high - low ) / 100 ) * min_pullback

if ( close > open and close < high - pullback_value and high - low >= candle_size ) or ( close < open and close > low + pullback_value and high - low >= candle_size )
    if close > open
        pullback_type := "up"
        pullback_level := high
        pullback_index := bar_index
        show_up_shape := true
    else
        pullback_type := "down"
        pullback_level := low
        pullback_index := bar_index
        show_down_shape := true

plotshape( show_up_shape and i_show_potentials ? show_up_shape : na, "Potential Liquidity Sweep Candle Up", shape.diamond, location.abovebar, color.red, size = size.tiny )
plotshape( show_down_shape and i_show_potentials ? show_down_shape : na, "Potential Liquidity Sweep Candle Down", shape.diamond, location.belowbar, color.green, size = size.tiny )