// The MIT License (MIT) // © mihakralj //@version=6 indicator("Bollinger Bands (BBANDS)", "BBANDS", overlay=true) //@function Calculates Bollinger Bands with adjustable period and multiplier //@param source Series to calculate Bollinger Bands from //@param period Lookback period for calculations //@param multiplier Standard deviation multiplier for band width //@returns tuple with [middle, upper, lower] band values //@optimized Uses circular buffer with running sums, O(1) complexity per bar bbands(series float source, simple int period, simple float multiplier) => if period <= 0 or multiplier <= 0.0 runtime.error("Period and multiplier must be greater than 0") var int p = math.max(1, period) var int head = 0 var int count = 0 var array buffer = array.new_float(p, na) var float sum = 0.0 var float sumSq = 0.0 float oldest = array.get(buffer, head) if not na(oldest) sum -= oldest sumSq -= oldest * oldest count -= 1 float current_val = nz(source) sum += current_val sumSq += current_val * current_val count += 1 array.set(buffer, head, current_val) head := (head + 1) % p float basis = nz(sum / count, source) float dev = count > 1 ? multiplier * math.sqrt(math.max(0.0, sumSq / count - basis * basis)) : 0.0 [basis, basis + dev, basis - dev] // ---------- Main loop ---------- // Inputs i_period = input.int(20, "Period", minval=1) i_source = input.source(close, "Source") i_multiplier = input.float(2.0, "StdDev Multiplier", minval=0.001) // Calculation [basis, upper, lower] = bbands(i_source, i_period, i_multiplier) // Plot plot(basis, "Basis", color=color.yellow, linewidth=2) p1 = plot(upper, "Upper", color=color.yellow, linewidth=2) p2 = plot(lower, "Lower", color=color.yellow, linewidth=2) fill(p1, p2, color=color.new(color.blue, 90), title="Band Fill")