mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-08-17 10:08:05 +00:00
- Updated BBWN, BBWP, CCV, CV, CVI, EWMA, GKV, HLV, HV, Jvolty, JVOLTYN, MASSI, NATR, RSV, RV, RVI, TR, UI, VOV, VR, YZV indicators with documentation links. - Added documentation links for Aberration, Acceleration Bands, Andrews' Pitchfork, Adaptive Price Zone, ATR Bands, Bollinger Bands, Center of Gravity, Donchian Channels, Decay Min-Max Channel, Detrended Synthetic Price, EACP, EBSW, HOMOD, Jurik Volatility Bands, Keltner Channel, MA Envelope, Min-Max Channel, Price Channel, Regression Channels, Standard Deviation Channel, Stoller Average Range Channel, Super Trend Bands, Ultimate Bands, Ultimate Channel, VWAP Bands, and VWAP with Standard Deviation Bands.
89 lines
2.5 KiB
Plaintext
89 lines
2.5 KiB
Plaintext
// The MIT License (MIT)
|
|
// © mihakralj
|
|
//@version=6
|
|
indicator("HEMA (Exponential Hull Analog)", "HEMAx", overlay=true)
|
|
|
|
//@function Calculates Hull Exponential Moving Average (EMA-domain HMA analog)
|
|
//@param src Series to calculate HEMA from
|
|
//@param N Period in half-life bars (>= 2)
|
|
//@returns HEMA value with reduced lag
|
|
//@optimized Uses cascaded EMA de-lag structure with O(1) complexity per bar
|
|
|
|
// Half-life -> alpha (exponential definition)
|
|
alphaFromHalfLife(float hl) =>
|
|
hl := math.max(1.0, hl)
|
|
-math.expm1(-math.log(2.0) / hl)
|
|
|
|
// Exponential Hull Analog (EMA-domain HMA)
|
|
hema(series float src, simple int N) =>
|
|
// --- guardrails ---
|
|
float n = math.max(float(N), 2.0) // HMA-like structure needs N>=2 to avoid fast==slow weirdness
|
|
|
|
// --- alphas (period converted immediately to half-life alpha) ---
|
|
float aS = alphaFromHalfLife(n)
|
|
float aF = alphaFromHalfLife(math.max(1.0, n * 0.5))
|
|
float aM = alphaFromHalfLife(math.max(1.0, math.sqrt(n)))
|
|
|
|
float bS = 1.0 - aS
|
|
float bF = 1.0 - aF
|
|
float bM = 1.0 - aM
|
|
|
|
// --- lag-derived ratio for the de-lag combiner ---
|
|
float lagS = bS / aS
|
|
float lagF = bF / aF
|
|
float r = lagF / lagS
|
|
r := math.min(math.max(r, 0.0), 0.999999) // keep denom sane
|
|
|
|
// --- state (unbiased EMA warmup) ---
|
|
var bool warmup = true
|
|
var float dS = 1.0
|
|
var float dF = 1.0
|
|
var float dM = 1.0
|
|
var float eSraw = 0.0
|
|
var float eFraw = 0.0
|
|
var float eMraw = 0.0
|
|
|
|
float eS = na
|
|
float eF = na
|
|
float out = na
|
|
|
|
// raw EMAs
|
|
eSraw := aS * (src - eSraw) + eSraw
|
|
eFraw := aF * (src - eFraw) + eFraw
|
|
|
|
if warmup
|
|
// update decays for unbiased correction
|
|
dS *= bS
|
|
dF *= bF
|
|
dM *= bM
|
|
|
|
float invS = 1.0 / math.max(1.0 - dS, 1e-12)
|
|
float invF = 1.0 / math.max(1.0 - dF, 1e-12)
|
|
float invM = 1.0 / math.max(1.0 - dM, 1e-12)
|
|
|
|
eS := eSraw * invS
|
|
eF := eFraw * invF
|
|
|
|
float deLag = (eF - r * eS) / (1.0 - r)
|
|
|
|
eMraw := aM * (deLag - eMraw) + eMraw
|
|
out := eMraw * invM
|
|
|
|
// end warmup only when ALL stages are effectively unbiased
|
|
warmup := math.max(dS, math.max(dF, dM)) > 1e-10
|
|
else
|
|
eS := eSraw
|
|
eF := eFraw
|
|
float deLag = (eF - r * eS) / (1.0 - r)
|
|
eMraw := aM * (deLag - eMraw) + eMraw
|
|
out := eMraw
|
|
|
|
out
|
|
|
|
// Inputs
|
|
i_period = input.int(10, "Period (half-life bars)", minval=1)
|
|
i_source = input.source(close, "Source")
|
|
|
|
hema_value = hema(i_source, i_period)
|
|
plot(hema_value, "HEMAx", color=color.yellow, linewidth=2)
|