// Licensed under the Apache License, Version 2.0 // © mihakralj //@version=6 indicator("Acceleration Bands (ACCBANDS)", "ACCBANDS", overlay=true) //@function Calculates Acceleration Bands using Price Headley's original formula //@param high Series of high prices //@param low Series of low prices //@param close Series of close prices //@param period Lookback period for the moving average //@param factor Multiplier for normalized width (default 4.0 per Headley) //@returns tuple with [middle, upper, lower] band values //@optimized Uses circular buffers with O(1) complexity per bar accbands(series float high, series float low, series float close, simple int period, simple float factor = 4.0) => if period <= 0 or factor <= 0.0 runtime.error("Period and factor must be greater than 0") var int p = math.max(1, period) var int head = 0 var int count = 0 var array bufferAdjHigh = array.new_float(p, na) var array bufferAdjLow = array.new_float(p, na) var array bufferClose = array.new_float(p, na) var float sumAdjHigh = 0.0 var float sumAdjLow = 0.0 var float sumClose = 0.0 float oldestAdjHigh = array.get(bufferAdjHigh, head) float oldestAdjLow = array.get(bufferAdjLow, head) float oldestClose = array.get(bufferClose, head) if not na(oldestAdjHigh) sumAdjHigh -= oldestAdjHigh sumAdjLow -= oldestAdjLow sumClose -= oldestClose count -= 1 float currentHigh = nz(high) float currentLow = nz(low) float currentClose = nz(close) // Headley's per-bar normalized width float denom = currentHigh + currentLow float w = denom != 0.0 ? (currentHigh - currentLow) / denom : 0.0 float adjHigh = currentHigh * (1.0 + factor * w) float adjLow = currentLow * (1.0 - factor * w) sumAdjHigh += adjHigh sumAdjLow += adjLow sumClose += currentClose count += 1 array.set(bufferAdjHigh, head, adjHigh) array.set(bufferAdjLow, head, adjLow) array.set(bufferClose, head, currentClose) head := (head + 1) % p float smaAdjHigh = nz(sumAdjHigh / count) float smaAdjLow = nz(sumAdjLow / count) float smaClose = nz(sumClose / count) [smaClose, smaAdjHigh, smaAdjLow] // ---------- Main loop ---------- // Inputs i_period = input.int(20, "Period", minval=1) i_factor = input.float(4.0, "Factor", minval=0.001) // Calculation [middle, upper, lower] = accbands(high, low, close, i_period, i_factor) // Plot plot(middle, "Middle", 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")