Skip to main content

Zero-Lag EMA Envelope (ZLEMA)

Warmup Window

Minimum bars needed: length bars (default params: 200 bars (length=200))

The ZLEMA center line needs length bars to initialize. The ATR bands additionally need atr_length bars. After warmup, both update in real-time.

After the warmup window is filled, this indicator produces a new value on every incoming bar in real-time.

Lagging Indicator

The center line has near-zero lag; the ATR-based bands still lag.

EventLagDetail
Center line reacts to price reversal≈ 0 barsZLEMA compensates EMA lag via close + (close − close[lag])
Upper/lower bands react to volatility changeatr_length / 2 barsBands are offset by ATR; ATR smoothing introduces lag of atr_length / 2

Formula for custom params: center ≈ 0; bands ≈ atr_length / 2

The Zero-Lag EMA Envelope combines a Zero-Lag Exponential Moving Average (ZLEMA) with ATR-based bands and multi-bar swing confirmation. The ZLEMA compensates for the inherent lag of a standard EMA by using a lag-compensated source (close + (close - close[lag])). Trend state is confirmed when multiple consecutive bars close beyond a band while the ZLEMA slope agrees.

Calculation:

  • lag = floor((length - 1) / 2)
  • compensated = close + (close - close[lag])
  • ZLEMA = EMA(compensated, length)
  • Upper = ZLEMA + ATR × mult
  • Lower = ZLEMA - ATR × mult
  • Bull: close > Upper for N bars AND ZLEMA rising
  • Bear: close < Lower for N bars AND ZLEMA falling
def zero_lag_ema_envelope(
data: Union[PdDataFrame, PlDataFrame],
source_column: str = 'Close',
length: int = 200,
mult: float = 2.0,
atr_length: int = 21,
confirm_bars: int = 2,
upper_column: str = 'zlema_upper',
lower_column: str = 'zlema_lower',
middle_column: str = 'zlema_middle',
trend_column: str = 'zlema_trend',
signal_column: str = 'zlema_signal',
) -> Union[PdDataFrame, PlDataFrame]:

Example

from investing_algorithm_framework import download

from pyindicators import zero_lag_ema_envelope

pl_df = download(
symbol="btc/eur",
market="binance",
time_frame="1d",
start_date="2023-12-01",
end_date="2023-12-25",
save=True,
storage_path="./data"
)
pd_df = download(
symbol="btc/eur",
market="binance",
time_frame="1d",
start_date="2023-12-01",
end_date="2023-12-25",
pandas=True,
save=True,
storage_path="./data"
)

# Calculate Zero-Lag EMA Envelope for Polars DataFrame
pl_df = zero_lag_ema_envelope(pl_df, source_column="Close", length=200, mult=2.0)
pl_df.show(10)

# Calculate Zero-Lag EMA Envelope for Pandas DataFrame
pd_df = zero_lag_ema_envelope(pd_df, source_column="Close", length=200, mult=2.0)
pd_df.tail(10)

ZERO_LAG_EMA_ENVELOPE

Chart Parameters

The image above uses the following parameters:

ParameterValue
source_columnClose
length200
mult2.0