Percentage Range Consolidation Histogram
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © Honestcowboy

//@version=5
indicator("Percentage Range Consolidation", overlay=false)
//tooltips
consolidationLengthTip              = "The amount of bars script will use to measure width from highest high to lowest low in percentage"
percentageFilterTip                 = "The maximum % the zone can be currently for it to be valid (coloring means it's consolidating at low volatility)"
consolidationLengthCheckTip         = "The script will plot on each bar percentage value that the range is. This is the amount of bars back it will look at zone % to calculate averages"
ConsolidationLengthCheckPercentage  = "After checking amount of bars back at zone % this is the percentage used for the white line. At default this is set to 15% meaning that if zone is ranked in bottom 15% of zone widths it will highlight (coloring means it's consolidating at low volatility)"
//use inputs
consolidationStrictness             = input.string(title='consolidation filters', defval='all', options=['percentage', 'median', 'all'], group="settings")
consolidationLength1                = input.int(defval=10,    minval=1,                     title="percentage zone length",                       group="consolidation check 1", tooltip = consolidationLengthTip)
percentageFilter1                   = input.float(defval=15, minval=0, maxval=100,          title="percentage zone % filter",                     group="consolidation check 1", tooltip = percentageFilterTip)
ConsolidationLengthCheckLength1     = input.int(defval=50,   minval=1,                      title="percentage zone PNR length",                   group="consolidation check 1", tooltip = consolidationLengthCheckTip)
ConsolidationLengthCheckPercentage1 = input.float(defval=20, minval=0, maxval=100,          title="percentage zone PNR %",                        group="consolidation check 1", tooltip = ConsolidationLengthCheckPercentage)
consolidationLength2                = input.int(defval=30,   minval=1,                      title="percentage zone length",                       group="consolidation check 2", tooltip = consolidationLengthTip)
percentageFilter2                   = input.float(defval=15, minval=0, maxval=100,          title="percentage zone % filter",                     group="consolidation check 2", tooltip = percentageFilterTip)
ConsolidationLengthCheckLength2     = input.int(defval=50,   minval=1,                      title="percentage zone PNR length",                   group="consolidation check 2", tooltip = consolidationLengthCheckTip)
ConsolidationLengthCheckPercentage2 = input.float(defval=20, minval=0, maxval=100,          title="percentage zone PNR %",                        group="consolidation check 2", tooltip = ConsolidationLengthCheckPercentage)
consolidationLength3                = input.int(defval=80,   minval=1,                      title="percentage zone length",                       group="consolidation check 3", tooltip = consolidationLengthTip)
percentageFilter3                   = input.float(defval=15, minval=0, maxval=100,          title="percentage zone % filter",                     group="consolidation check 3", tooltip = percentageFilterTip)
ConsolidationLengthCheckLength3     = input.int(defval=50,   minval=1,                      title="percentage zone PNR length",                   group="consolidation check 3", tooltip = consolidationLengthCheckTip)
ConsolidationLengthCheckPercentage3 = input.float(defval=20, minval=0, maxval=100,          title="percentage zone PNR %",                        group="consolidation check 3", tooltip = ConsolidationLengthCheckPercentage)
transparancy1                       = input.int(defval=30,   minval=0, maxval=100,          title="color transparancy",                           group="visuals")
transparancy2                       = input.int(defval=80,   minval=0, maxval=100,          title="grays transparancy",                           group="visuals")
transparancy3                       = input.int(defval=50,   minval=0, maxval=100,          title="percentage zone PNR line transparancy",        group="visuals")
useBarColoring                      = input.bool(true,                                      title="",                                             group="bar coloring", inline = "1")
consolidationNumberForColoring      = input.string(defval = "3", options = ["1", "2", "3"], title="consolidation filters needed",                 group="bar coloring", inline = "1")
barColor                            = input.color(defval=color.rgb(215, 0, 0),                      title="",                                             group="bar coloring", inline = "1")

//Consolidation Function
f_consolidationZone(consolidationStrictness, consolidationLength, percentageFilter, ConsolidationLengthCheckLength, ConsolidationLengthCheckPercentage) =>
    bandsTop                        = ta.percentile_nearest_rank(close,consolidationLength,100) // you can change these so the zone will % will not be created from top and bottom but more middle values
    bandsBottom                     = ta.percentile_nearest_rank(close,consolidationLength,0) // you can change these so the zone will % will not be created from top and bottom but more middle values
    percentageZone                  = ((bandsTop-bandsBottom)/bandsBottom)*100
    percentageZonePNR               = ta.percentile_nearest_rank(percentageZone, ConsolidationLengthCheckLength, ConsolidationLengthCheckPercentage)
    consolidating                   = consolidationStrictness=="all"?percentageZone<percentageZonePNR and percentageZone<percentageFilter:
      consolidationStrictness=="percentage"?percentageZone<percentageFilter:
      consolidationStrictness=="median"?percentageZone<percentageZonePNR:false
    [percentageZone,percentageZonePNR,consolidating]
//get values
[percentageZone1,percentageZonePNR1,consolidating1] = f_consolidationZone(consolidationStrictness, consolidationLength1, percentageFilter1, ConsolidationLengthCheckLength1, ConsolidationLengthCheckPercentage1)
[percentageZone2,percentageZonePNR2,consolidating2] = f_consolidationZone(consolidationStrictness, consolidationLength2, percentageFilter2, ConsolidationLengthCheckLength2, ConsolidationLengthCheckPercentage2)
[percentageZone3,percentageZonePNR3,consolidating3] = f_consolidationZone(consolidationStrictness, consolidationLength3, percentageFilter3, ConsolidationLengthCheckLength3, ConsolidationLengthCheckPercentage3)
//coloring
zoneColor1= consolidating1?color.new(color.yellow,transparancy1):color.new(color.gray,transparancy2)
zoneColor2= consolidating2?color.new(color.orange,transparancy1):color.new(color.gray,transparancy2)
zoneColor3= consolidating3?color.new(color.blue,transparancy1):color.new(color.gray,transparancy2)
//Bar coloring
numberOfConsolidations  = 0
numberOfConsolidations  := consolidating1 ? numberOfConsolidations+1 : numberOfConsolidations
numberOfConsolidations  := consolidating2 ? numberOfConsolidations+1 : numberOfConsolidations
numberOfConsolidations  := consolidating3 ? numberOfConsolidations+1 : numberOfConsolidations
isConsolidating = consolidationNumberForColoring == "1" ? numberOfConsolidations>=1 : consolidationNumberForColoring == "2" ? numberOfConsolidations>=2 : numberOfConsolidations>=3
barcolor(isConsolidating ? barColor : na)
//Breakout Logic
float breakTop            = na
float breakBottom         = na
breakTop                  := (isConsolidating and not isConsolidating[1]) ? high : (isConsolidating and isConsolidating[1] and high>breakTop[1])   ? high : breakTop[1]
breakBottom               := (isConsolidating and not isConsolidating[1]) ? low  : (isConsolidating and isConsolidating[1] and low<breakBottom[1]) ? low  : breakBottom[1]
breaksTop                 = close>breakTop
breaksBottom              = close<breakBottom
breakTop                  := (breaksTop or breaksBottom) and (not isConsolidating) ? na : breakTop
breakBottom               := (breaksTop or breaksBottom) and (not isConsolidating) ? na : breakBottom
//plotting
plot(percentageZone3,    color=zoneColor3,                           style=plot.style_columns,              title="Percentage zone 3")
plot(percentageZonePNR3, color=color.new(color.white,transparancy3),                           linewidth=3, title="percentage zone PNR 3")
plot(percentageZone2,    color=zoneColor2,                           style=plot.style_columns,              title="Percentage zone 2")
plot(percentageZonePNR2, color=color.new(color.white,transparancy3),                           linewidth=3, title="percentage zone PNR 2")
plot(percentageZone1,    color=zoneColor1,                           style=plot.style_columns,              title="Percentage zone 1")
plot(percentageZonePNR1, color=color.new(color.white,transparancy3),                           linewidth=3, title="percentage zone PNR 1")
//Alerts
bgcolor(breaksTop ? color.rgb(0, 158, 8) : breaksBottom ? color.rgb(215, 0, 0) : na)
alertcondition(isConsolidating and not isConsolidating[1],title="Consolidation start")
alertcondition(breaksTop,title="break top of rane")
alertcondition(breaksBottom,title="breaks bottom of range")