Files
QuanTAlib/lib/trends_IIR/zlema/Zlema.md
T
Miha Kralj 86fe32a682 SIMD Refactor: Merge simd-dev into dev (#55)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: aider (openrouter/anthropic/claude-sonnet-4) <aider@aider.chat>
Co-authored-by: Warp <agent@warp.dev>
2026-01-18 19:02:03 -08:00

3.8 KiB

ZLEMA: Zero-Lag Exponential Moving Average

EMA with lag compensation via a zero-lag signal

"ZLEMA does not erase lag. It predicts just enough to act early, then pays the price in overshoot."

ZLEMA takes a standard EMA and feeds it a zero-lag signal: current price minus a lagged price. This produces a smoother that responds faster than EMA without going fully raw. It is not magic. It shifts some lag into controlled overshoot.

Historical Context

ZLEMA is a widely used variation on EMA intended to reduce delay without abandoning exponential smoothing. It appears in multiple technical analysis toolkits and is often described as a "predictive EMA." The prediction is simple: extrapolate the current price by subtracting a lagged value.

Architecture & Physics

Pipeline

  1. Lag estimate
\text{lag} = \max(1, \text{round}((N-1)/2))
  1. Zero-lag signal
s_t = 2 \cdot x_t - x_{t-\text{lag}}
  1. EMA smoothing
\text{ZLEMA}_t = \text{EMA}(s_t, \alpha)

Warmup compensation

ZLEMA uses EMA bias compensation during warmup:

y_t^{*} = \frac{y_t}{1 - (1 - \alpha)^t}

This avoids the early-stage bias toward zero and makes the first values usable.

Math Foundation

EMA update:

y_t = y_{t-1} + \alpha (s_t - y_{t-1})

Zero-lag signal:

s_t = 2 \cdot x_t - x_{t-\text{lag}}

Alpha from period:

\alpha = \frac{2}{N + 1}

Performance Profile

Operation Count (Streaming Mode, Scalar)

Hot path (after warmup, compensation complete):

Operation Count Cost (cycles) Subtotal
FMA 2 4 8
MUL 1 3 3
Total 3  ~11 cycles

The hot path consists of:

  1. Zero-lag signal: FMA(2.0, val, -lagged)  1 FMA
  2. EMA core: FMA(zlemaRaw, beta, alpha * signal)  1 FMA + 1 MUL

Warmup path (with bias compensation):

Operation Count Cost (cycles) Subtotal
FMA 2 4 8
MUL 2 3 6
DIV 1 15 15
CMP 2 1 2
Total 7  ~31 cycles

Additional warmup operations:

  • Decay tracking: e *= beta  1 MUL
  • Bias compensation: zlemaRaw / (1 - e)  1 DIV
  • Hot/compensated checks  2 CMP

Batch Mode (SIMD Analysis)

ZLEMA is an IIR filter with lag buffer dependency  not directly vectorizable across bars. However, within-bar operations use FMA intrinsics.

Optimization Benefit
FMA instructions ~11 cycles vs ~14 scalar
stackalloc buffer Zero heap allocation for lag d256

Quality Metrics

Metric Score Notes
Accuracy 8/10 Matches PineScript reference
Timeliness 8/10 Faster response than EMA
Overshoot 6/10 Predictive signal causes overshoot on reversals
Smoothness 7/10 Between EMA and raw price

Validation

ZLEMA is validated against a PineScript reference implementation.

Library Status Tolerance Notes
TA-Lib N/A - No ZLEMA in TA-Lib
Skender N/A - No ZLEMA in Skender
Tulip Partial - Tulip has zlema but not used here
Ooples N/A - No ZLEMA in Ooples
PineScript ? Passed 1e-10 Matches lib/trends_IIR/zlema/zlema.pine

Common Pitfalls

  1. Overshoot on turns

    The zero-lag signal is a forward estimate. It can overshoot when price reverses sharply. This is expected behavior.

  2. Period semantics

    ZLEMA uses EMA alpha; the lag term is derived from period but not equivalent to a window length. Do not compare ZLEMA period directly to SMA window length.

  3. Warmup discipline

    Use IsHot / WarmupPeriod before acting on signals. Early values are bias-corrected but still unstable.

  4. Non-finite data

    NaN or Infinity is replaced with the last valid value. Before the first valid sample, output is NaN.