Consolidation indicator
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © cyatophilum

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

timeframe       = input.timeframe('','timeframe')
smoothing_length = input.int(4,'price smoothing length',minval=1)
range_len = 14//input.int(14,'Avg range length')
NR_threshold = input.float(80,'% Threshold for Narrow Range')
consecutive_ranges = input.int(3,'Consecutive Narrow Ranges for Consolidation')
consolidation_candle_color = input.color(color.rgb(43, 255, 0),'Candle color')
var int cpt = 0

_priceRange = ta.sma(high - low,smoothing_length)
_averageRange = ta.rma(_priceRange, range_len)

offset = timeframe == timeframe.period ? 0 : 1
[priceRange, averageRange, HTFClose] = request.security(syminfo.tickerid, timeframe,
 [
 _priceRange[offset], 
 _averageRange[offset],
 close[offset]
 ], 
 lookahead = barmerge.lookahead_on)

bool is_new_period = ta.change(HTFClose)

narrowRange = priceRange < NR_threshold * averageRange / 100

if is_new_period 
    if narrowRange
        cpt := cpt + 1
    else
        cpt := 0

breakout = cpt[1] >= consecutive_ranges[1] and not narrowRange

transp = cpt == 0 ? 100 : 100 - cpt * 100 / consecutive_ranges

hma = ta.hma(close,range_len)
is_bullish = ta.rising(hma,1)
is_bearish = ta.falling(hma,1)

long = breakout and is_bullish
short = breakout and is_bearish

candlescolor = narrowRange ? color.new(consolidation_candle_color, transp) : chart.bg_color
wickcolor    = narrowRange ? (consolidation_candle_color) : color.new(chart.fg_color,10)
bordercolor  = narrowRange ? (consolidation_candle_color) : color.new(chart.fg_color,10)
plotcandle(open,high,low,close,'consolidation', candlescolor, wickcolor = wickcolor, bordercolor = bordercolor)
plot(narrowRange or breakout  ? hma : na, 'direction line', is_bullish ? color.rgb(33, 150, 243) : color.red, 4, plot.style_linebr)
// plotchar(breakout ? close : na,'breakout','💥',location.belowbar,text='Breakout',textcolor = color.orange)

plotshape(long,'long breakout', shape.labelup, location.belowbar,color.rgb(0, 0, 0), text='Breakout💥', textcolor=color.lime)
plotshape(short,'short breakout', shape.labeldown, location.abovebar,color.rgb(0, 0, 0), text='Breakout💥', textcolor=color.red)

alertcondition(narrowRange and not narrowRange[1],'Consolidation Begins','')
alertcondition(long,'Long Breakout','')
alertcondition(short,'Short Breakout','')
