mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-07-27 17:27:43 +00:00
71 lines
2.4 KiB
Plaintext
71 lines
2.4 KiB
Plaintext
// Licensed under the Apache License, Version 2.0
|
|
// © mihakralj
|
|
//@version=6
|
|
indicator("Adaptive Price Zone", "APZ", overlay=true)
|
|
|
|
//@function Calculates Adaptive Price Zone using double-smoothed EMA
|
|
//@param source Series to calculate middle line from
|
|
//@param period Lookback period (sqrt applied internally for smoothing)
|
|
//@param bandPct Band width multiplier
|
|
//@returns tuple with [middle, upper, lower] band values
|
|
//@optimized Uses compound warmup compensation for nested EMAs, O(1) complexity per bar
|
|
apz(series float source, simple int period, simple float bandPct) =>
|
|
if period <= 0
|
|
runtime.error("Period must be greater than 0")
|
|
if period > 5000
|
|
runtime.error("Period exceeds maximum of 5000")
|
|
if bandPct <= 0.0
|
|
runtime.error("Band multiplier must be greater than 0")
|
|
|
|
float smoothPeriod = math.sqrt(period)
|
|
float alpha = 2.0 / (smoothPeriod + 1.0)
|
|
float beta = 1.0 - alpha
|
|
|
|
var float ema1_price = 0.0
|
|
var float ema2_price = 0.0
|
|
var float ema1_range = 0.0
|
|
var float ema2_range = 0.0
|
|
var float e = 1.0
|
|
var bool warmup = true
|
|
|
|
float current_price = nz(source)
|
|
float current_range = nz(high - low)
|
|
|
|
ema1_price := alpha * current_price + beta * ema1_price
|
|
ema2_price := alpha * ema1_price + beta * ema2_price
|
|
|
|
ema1_range := alpha * current_range + beta * ema1_range
|
|
ema2_range := alpha * ema1_range + beta * ema2_range
|
|
|
|
float middle = ema2_price
|
|
float adaptiveRange = ema2_range
|
|
|
|
if warmup
|
|
e *= beta * beta
|
|
float compensator = 1.0 / (1.0 - e)
|
|
middle := compensator * ema2_price
|
|
adaptiveRange := compensator * ema2_range
|
|
warmup := e > 1e-10
|
|
|
|
float width = bandPct * adaptiveRange
|
|
float upper = middle + width
|
|
float lower = middle - width
|
|
|
|
[middle, upper, lower]
|
|
|
|
// ---------- Main loop ----------
|
|
|
|
// Inputs
|
|
i_period = input.int(20, "Period", minval=1, maxval=5000)
|
|
i_bandPct = input.float(2.0, "Band Multiplier", minval=0.001, step=0.1)
|
|
i_source = input.source(close, "Source")
|
|
|
|
// Calculation
|
|
[middle, upper, lower] = apz(i_source, i_period, i_bandPct)
|
|
|
|
// Plot
|
|
plot(middle, "Middle", color=color.yellow, linewidth=2)
|
|
p1 = plot(upper, "Upper", color=color.new(color.yellow, 50), linewidth=1)
|
|
p2 = plot(lower, "Lower", color=color.new(color.yellow, 50), linewidth=1)
|
|
fill(p1, p2, color=color.new(color.yellow, 90), title="Band Fill")
|