Trend indicator · Dual EMA · Fixed example length 10

Almost Zero Lag EMA: inspect the formula behind the name

Pineify names this indicator Zero Lag EMA, but its implementation is exactly the DEMA expression: twice an EMA minus an EMA of that EMA. The subtraction changes its response and permits overshoot. The name does not promise zero delay, a fixed distance from price or profitable crossovers.

Two EMA passes, followed by subtraction

For positive integer length n, let α = 2/(n + 1). EMA1 updates from the input price, and EMA2 applies the same smoothing to EMA1. The final output is EMA1 + (EMA1 − EMA2) = 2 × EMA1 − EMA2. EMA2 alone is double smoothing; the final subtraction is what distinguishes this output.

EMA1[t] = α × source[t] + (1 − α) × EMA1[t−1]
EMA2[t] = α × EMA1[t] + (1 − α) × EMA2[t−1]
output[t] = 2 × EMA1[t] − EMA2[t]

TradingView documents this DEMA formula and credits Patrick Mulloy's 1994 publication. With matching source, length and initialization, the displayed function and Pineify's DEMA function are algebraically equivalent. The function names and argument order differ.

An EMA's low-frequency delay is often summarized as (n − 1)/2 bars. That is not a constant time shift for every price path or frequency. It does not justify a claim that this formula removes exactly 30% of lag or stays within a specified percentage of market price.

A reproducible example that overshoots

Use a synthetic series that has stayed at 100 long enough for both EMA states to equal 100. Set n = 3, so α = 0.5. Price then rises to 110 and remains there. Apply the recurrence above once per row.

StepPriceEMA1EMA22 × EMA1 − EMA2
Initial100100100100
1110105102.5107.5
2110107.5105110
3110108.75106.875110.625
4110109.375108.125110.625

The third output is above every input price in this example. A price-below-line condition can therefore appear while price has remained at 110; it need not mean price has started falling. The output eventually converges toward 110 as both EMA states converge. These arithmetic results are not a market backtest.

For length 1, α = 1: both EMA passes equal the source and the corrected line also equals the source. With source set to close, a strict close-versus-line crossover then cannot occur. This boundary case helps distinguish a plotting formula from an entry system.

Pine Script implementation

The original function and plotting source are retained below. It calls the function on close with length 10 and draws one blue line with width 1. Its zero-lag label is a name; the calculation is the DEMA expression described above.

Pine Script v6
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © Pineify

//@version=6
indicator(title="Zero Lag EMA", overlay=true, max_labels_count=500)

// ZLEMA — Dual EMA smoothing with lag correction
// Parameters: source=close, length=10
p_ta_almost_zero_lag_ema(series float source, simple int length) =>
    ema1 = ta.ema(source, length)
    ema2 = ta.ema(ema1, length)
    d = ema1 - ema2
    zlema = ema1 + d
    zlema

p_ind_1 = p_ta_almost_zero_lag_ema(close, 10) // zeroLagEMA

plot(p_ind_1, "zeroLagEMA", color.rgb(41, 98, 255, 0), 1)

Open TradingView's Pine Editor using the Pine icon in the chart's right toolbar, paste the source and select Add to chart. There are no editable source or length Inputs in this script. Its function arguments must be changed in code, or exposed explicitly in a separately validated adaptation.

Pineify Zero Lag EMA chart preview

The plot does not display entry markers, generate custom crossover alerts or submit strategy orders. Its max-labels setting does not create labels. The chart preview is illustrative and supplies no measured signal accuracy.

Crossovers, confirmation and fair comparisons

A close-over-line crossover requires the current close to be strictly above the current line and the previous close to be at or below its previous line value. A close already above the line is a state, not another crossover. Requiring a second close above is an additional persistence rule; it is not part of the definition of a crossover.

The current close and both EMA values can change while the bar is forming. Shifting only the moving average by one bar still leaves current price fluid. Confirm the whole condition on bar close, or evaluate completed-bar values consistently. Read TradingView's repainting documentation before adding higher-timeframe inputs. This displayed script makes no higher-timeframe requests.

For a comparison with ordinary EMA or HMA, fix the price source, chart type, symbol, session, date range and initialization period. Measure the quantity of interest: distance from price, turning delay under a stated turning-point rule, or crossover frequency. No one metric establishes trading profitability, and equal length numbers do not give different filters identical smoothing.

Testing a proposed filter

  1. Specify a completed-bar entry rule and the later executable fill price. Do not count a close signal as a fill at an earlier price.
  2. Choose exit, holding limit, position size, spread, commission and slippage assumptions before comparing filters.
  3. If testing ADX, use its actual output: the third result of TradingView's DMI tuple, after +DI and −DI. The second result is −DI, not ADX.
  4. Compare the same baseline with and without the filter on a held-out period. Report trade counts and losses as well as any return metric. A threshold such as ADX 20 or a 200-bar EMA is a test specification, not evidence of an improved win rate.

A stop fixed at entry minus 1.5 ATR is an initial stop. Calling it trailing requires an explicit update rule. Neither a moving-average touch nor a stop price guarantees a fill, particularly across gaps. This indicator implements neither kind of stop.

Request an adaptation with a defined formula

A useful coding request is: expose the source and a positive length as inputs; preserve 2 × EMA(source, n) − EMA(EMA(source, n), n); add closed-bar crossover markers; keep trading orders out of the indicator. Specify a strategy separately if you need a testable entry, exit and cost model.

Pineify's coding agent can assist with an adaptation. Review the returned source, compile it and compare its output with this recurrence before relying on it. Access and usage depend on the current account and plan; this page does not promise unlimited free generation.

View the coding agent

Frequently asked questions

For the displayed implementation, yes: EMA1 + (EMA1 − EMA2) equals 2 × EMA1 − EMA2, the DEMA formula. A name containing zero lag does not identify one unique algorithm. Compare formulas and initialization before comparing chart outputs.

No. It is a causal filter of current and past prices. It can differ from price and overshoot after a price step. A faster response does not establish an earlier profitable entry or a fixed percentage reduction in lag.

The displayed script hard-codes close and length 10 in its function call. It contains no input declarations. Changing those arguments requires editing the source; an adapted script can expose inputs after validation.

No best length or timeframe is established here. Length counts chart bars, so ten daily bars and ten five-minute bars represent different observations. Compare settings with the same source, session, initialization, execution costs and a separate evaluation sample.

Shifting only the line does not freeze a comparison that still uses the current changing close. Evaluate the whole condition on confirmed chart bars or use completed-bar values consistently. Higher-timeframe requests need their own confirmation handling.

No. It plots one blue line on the price chart. It has no orders, custom alert conditions, multi-timeframe requests, stop logic or performance statistics.