With default inputs, the upper band is the 90th percentile of highs, the lower band is the 10th percentile of lows, and the middle band is the median of closes over 100 bars. These are three different samples, not an 80% confidence interval or a probability of future price containment. The current bar enters each sample; live bands and crossing markers can change until the bar closes. This indicator creates no orders or alerts.
Pine Script v6: Adaptive percentile channel indicatorpinescript
//@version=6
indicator("Adaptive Percentile Bands [v6]", overlay = true)
// Input configuration
int lookback = input.int(100, "Lookback Period", minval = 10)
float upperPercentile = input.float(90.0, "Upper Percentile (%)", minval = 50.0, maxval = 100.0)
float lowerPercentile = input.float(10.0, "Lower Percentile (%)", minval = 0.0, maxval = 50.0)
// Calculate interpolated percentiles
float upperBand = ta.percentile_linear_interpolation(high, lookback, upperPercentile)
float lowerBand = ta.percentile_linear_interpolation(low, lookback, lowerPercentile)
float medianBand = ta.percentile_linear_interpolation(close, lookback, 50.0)
// Breakout signals
bool upperBreakout = ta.crossover(close, upperBand)
bool lowerBreakout = ta.crossunder(close, lowerBand)
// Visual plots
plot(upperBand, "Upper Percentile Band", color = color.red, linewidth = 2)
plot(medianBand, "50th Percentile (Median)", color = color.gray, linewidth = 1, style = plot.style_linebr)
plot(lowerBand, "Lower Percentile Band", color = color.green, linewidth = 2)
// Shape markers
plotshape(upperBreakout, "High Percentile Break", shape.triangleup, location.abovebar, color.red, size = size.tiny)
plotshape(lowerBreakout, "Low Percentile Break", shape.triangledown, location.belowbar, color.green, size = size.tiny)
// Dynamic channel fill
fill(plot(upperBand), plot(lowerBand), color = color.new(color.blue, 94), title = "Percentile Distribution Zone")