TradingView indicators

Zero Lag Exponential Moving Average: Construction and Overshoot

The zero lag exponential moving average (ZLEMA) smooths a lag-compensated price series: double the current price, subtract a past price, then apply an EMA. It can respond faster to a price step, but the correction can push the line beyond the observed price. The name does not promise zero delay on every price path.

A checkable result

With length 5 and lag 2, a step from 100 to 110 produces ZLEMA values of 106.6667, then 111.1111. Price never exceeds 110. The calculation and reproducible Pine example below explain why.

Compensate the input, then smooth it

Let x[t] be the selected price source and N a positive integer length. This page uses the following floor-based convention:

L = floor((N − 1) / 2)
u[t] = 2 × x[t] − x[t − L]
alpha = 2 / (N + 1)
Z[t] = alpha × u[t] + (1 − alpha) × Z[t − 1]

The input u adds the change over L bars to the current price. In a steady rise, this moves the input ahead of price before smoothing. It uses past data; it does not read a future bar. A change of direction or sudden jump can make the compensation excessive.

The EMA coefficient follows TradingView's moving average formula. The exact lag convention is an implementation choice: Sierra Chart documents ceiling, giving L = 10 at N = 20, while this example uses L = 9. Match rounding before comparing plots.

For a constant-slope ramp after initialization transients decay, an EMA with this alpha lags by (N − 1) / 2 bars in the ramp sense. Subtracting L leaves a residual of 0 bars for odd N and 0.5 bar for even N under floor rounding. This is a result for that input shape, not a universal crossover lead.

Recompute a step response and its overshoot

Use N = 5, L = 2 and alpha = 1/3. Before bar 1, price has stayed at 100 and both averages equal 100. Price rises to 110 at bar 1 and stays there. These are synthetic values, not market returns.

Values rounded to four decimals for display; recurrence uses unrounded values.
Bar after stepPrice x[t]x[t − 2]Adjusted u[t]EMAZLEMA
0 (before step)100100100100.0000100.0000
1 (first step bar)110100120103.3333106.6667
2110100120105.5556111.1111
3110110110107.0370110.7407
4110110110108.0247110.4938
5110110110108.6831110.3292

On bar 1: u = 2 × 110 − 100 = 120, so Z = 120/3 + 2 × 100/3 = 106.6667. On bar 2 the input remains 120, so Z = 120/3 + 2 × 106.6667/3 ≈ 111.1111. From bar 3, the delayed price is also 110 and the compensated input returns to 110.

The peak exceeds the new price by 1.1111 points, or 11.1111% of the 10-point step. This percentage describes the filter experiment, not a trading return. The excess then decays by a factor of 2/3 per bar. A price-below-ZLEMA condition appears on bar 2 without any fall in price.

Length, rounding and warm-up boundaries

Dataset indices start at 0. First valid input assumes a non-missing source on every bar.
Length NFloor lag LEMA alphaFirst valid input indexConsequence
1010Output equals the source.
202/30No input compensation; equals the 2-bar EMA.
521/32The step example below.
2092/219Floor and ceiling differ by one bar.
21101/1110Floor and ceiling agree.

There are two separate checks. First, the lagged source must exist. For length 20, the first nine adjusted inputs are unavailable; this code leaves them as na. Replacing a missing past price with zero would create an artificial jump in the input.

Second, the EMA needs time to lose sensitivity to its initial state. A numeric value is not proof of convergence. Once two runs receive the same inputs, their seed difference decays by (1 − alpha) each update. Compare an overlapping interval using additional history and choose a tolerance in price units or ticks.

Changing length affects both smoothing and compensation. Lengths 19 and 20 both use L = 9 with floor rounding, but have different alpha values. Length 21 also moves the lag to 10. Keep source, symbol, timeframe, session and price adjustments identical when comparing implementations.

Pine Script v6: ZLEMA beside the same-length EMA

Paste this indicator into TradingView's Pine Editor, save it and add it to a chart. The default uses close and length 20. The script plots both averages and makes the compensated input available in the Data Window. It contains no orders or alert rules.

Pine Script v6
//@version=6
indicator("ZLEMA and EMA comparison", overlay=true)

length = input.int(20, "Length", minval=1, maxval=500)
priceSource = input.source(close, "Source")
useStep = input.bool(false, "Synthetic 100 to 110 step (set Length to 5)")

// The step occurs at dataset bar 100. Earlier bars are exactly 100.
source = useStep ? (bar_index < 100 ? 100.0 : 110.0) : priceSource
// This example chooses floor; other platforms can use different rounding.
lag = int(math.floor((length - 1) / 2.0))
adjusted = 2.0 * source - source[lag]
zlema = ta.ema(adjusted, length)
ema = ta.ema(source, length)

plot(zlema, "ZLEMA", color=color.blue, linewidth=2)
plot(ema, "EMA", color=color.orange, linewidth=2)
plot(useStep ? source : na, "Synthetic source", color=color.gray)
plot(adjusted, "Adjusted input", display=display.data_window)
  1. To reproduce the table, set Length to 5 and enable the synthetic step input.
  2. Use a dataset with at least 105 bars. The step starts at dataset bar_index 100; table bar 1 corresponds to that bar, and table bar 2 to bar_index 101.
  3. Inspect the Data Window: adjusted input should be 120 for two bars, then 110. Compare the orange EMA and blue ZLEMA values with the table.
  4. Disable the synthetic input before analyzing market prices. On a live bar, close and both averages can change. If you add signals, state whether they require a confirmed bar.

Pine's operator documentation explains why the history offset needs an integer and why unavailable history returns na. The execution model explains recalculation on realtime updates.

ZLEMA, DEMA and TEMA use different corrections

ZLEMA applies one EMA to the compensated source. If E1 is EMA(x, N), E2 is EMA(E1, N) and E3 is EMA(E2, N), DEMA is 2 × E1 − E2 and TEMA is 3 × E1 − 3 × E2 + E3. Their subtraction occurs between smoothing stages rather than between current and delayed prices.

Use the separate DEMA and TEMA guides for those constructions. Almost Zero Lag EMA is a related named variant; its label alone does not establish formula equivalence.

Test signal rules separately from the line

Overshoot, changing live-bar values and repeated crossings in sideways prices can all affect a trading rule. A faster step response does not establish better entries or profitability. Specify confirmation timing, entries, exits, sizing and costs, then evaluate unseen data. This page is technical education, not investment advice.

Continue the comparison in Pineify

Use Pine Script AI Coding Agent to request changes to the example. Give it the rounding convention and a checkable expected output so the generated script can be reviewed against the same experiment.

Compare a 20-bar EMA with ZLEMA using floor((N − 1) / 2), the same source and no plot offset. Keep the synthetic 100-to-110 step test. Add confirmed-bar crossover markers and explain how overshoot can create a crossing while price is flat.

Review the generated code, validate its syntax and compare its chart values before using it. Code generation does not establish that a signal works, and this example does not execute trades.

Open Pine Script AI Coding Agent

ZLEMA questions

Sources and calculation scope

Reviewed October 17, 2026. Sources document the EMA construction, platform conventions and Pine behavior. The floor convention, ramp derivation and synthetic table are explicitly defined calculations on this page.

Browse TradingView indicator guides