mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-07-27 17:27:43 +00:00
55 lines
1.9 KiB
Plaintext
55 lines
1.9 KiB
Plaintext
// Licensed under the Apache License, Version 2.0
|
|
// © mihakralj
|
|
//@version=6
|
|
indicator("Adaptive Price Channel (APCHANNEL)", "APCHANNEL", overlay=true)
|
|
|
|
//@function Calculates the Adaptive Price Channel using dual EMA on highs and lows.
|
|
//@doc The channel applies exponential smoothing to price highs and lows independently,
|
|
// creating a dynamic envelope that "remembers" significant extremes while gradually
|
|
// fading their influence. Unlike fixed-window Donchian channels that drop extremes
|
|
// abruptly, APCHANNEL decays them smoothly (leaky integration).
|
|
//@param alpha Smoothing factor (0 < alpha <= 1). Higher = faster decay, shorter memory.
|
|
//@returns tuple of [middle, upper, lower] band values
|
|
//@optimized O(1) per bar via EMA recursion; uses FMA pattern: decay*prev + alpha*new
|
|
apchannel(simple float alpha) =>
|
|
if alpha <= 0.0 or alpha > 1.0
|
|
runtime.error("Alpha must be > 0 and <= 1")
|
|
[float(na), float(na), float(na)]
|
|
|
|
float decay = 1.0 - alpha
|
|
|
|
// EMA of highs (upper band)
|
|
var float high_ema = na
|
|
float valid_high = nz(high, nz(high_ema, 0.0))
|
|
if na(high_ema)
|
|
high_ema := valid_high
|
|
else
|
|
high_ema := decay * high_ema + alpha * valid_high
|
|
|
|
// EMA of lows (lower band)
|
|
var float low_ema = na
|
|
float valid_low = nz(low, nz(low_ema, 0.0))
|
|
if na(low_ema)
|
|
low_ema := valid_low
|
|
else
|
|
low_ema := decay * low_ema + alpha * valid_low
|
|
|
|
// Midpoint
|
|
float mid = (high_ema + low_ema) / 2.0
|
|
|
|
[mid, high_ema, low_ema]
|
|
|
|
// ---------- Main loop ----------
|
|
|
|
// Inputs
|
|
i_alpha = input.float(0.2, "Alpha (smoothing factor)", minval=0.01, maxval=1.0, step=0.01)
|
|
|
|
// Calculation
|
|
[middle, upper, lower] = apchannel(i_alpha)
|
|
|
|
// Plot
|
|
plot(middle, "Middle", color=color.yellow, linewidth=2)
|
|
p1 = plot(upper, "Upper", color=color.new(color.blue, 50), linewidth=1)
|
|
p2 = plot(lower, "Lower", color=color.new(color.blue, 50), linewidth=1)
|
|
fill(p1, p2, color=color.new(color.blue, 90))
|