Exponential Moving Average(EMA)
A moving average weighting recent closes more heavily, decaying geometrically.
ema(prices, period: int)An exponential moving average weights each observation by a factor that decays geometrically with age. Nothing ever fully leaves the calculation, so there is no drop-out artefact — the response to a large move decays smoothly instead of ending abruptly N bars later.
The practical consequence is that an EMA turns sooner than an SMA of the same nominal period. Whether that is an improvement depends entirely on what you are trading: it means less lag at a turning point and more reaction to noise in a range. Neither is universally better, and the choice between them is a real modelling decision rather than a preference.
The period argument maps to a smoothing factor internally rather than a hard window, which is why an EMA and an SMA of the same period are not comparable objects even though the argument looks identical.
It is worth knowing the conversion, because it explains the behaviour. The smoothing factor is two divided by the period plus one, so a 12-period EMA weights the newest close at roughly 15 per cent and a 26-period one at roughly 7 per cent. The word period is a nickname for that weight rather than a count of bars, and every value in the series carries some contribution from every bar before it.
Where it misleads
- Faster response also means faster response to noise. In a choppy market an EMA crossover trades more than the SMA equivalent, not less.
- The early values of an EMA depend on how the series was seeded. On a short backtest that initialisation is a meaningful fraction of your results.
- Comparing an EMA to an SMA "of the same period" is comparing two different things — the effective lookbacks differ.
In code
from quantide import fetch_data, ema, crossunder
data = fetch_data("BTC-USD", "2020-01-01", "2025-01-01")
fast = ema(data["Close"], period=12)
slow = ema(data["Close"], period=26)
exits = crossunder(fast, slow)