Files
QuanTAlib/lib/channels/accbands/accbands.pine
T

69 lines
2.7 KiB
Plaintext

// 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<float> bufferAdjHigh = array.new_float(p, na)
var array<float> bufferAdjLow = array.new_float(p, na)
var array<float> 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")