mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-07-27 17:27:43 +00:00
69 lines
2.7 KiB
Plaintext
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")
|