Back to Research
Volatility & Risk September 12, 2026 • 11 min read

Catching the Flinch: The Lee-Mykland Jump Test

A big candle can be volatility or it can be a jump — a liquidation cascade, a news shock, a repricing in a single tick. They demand opposite responses, and the eye can't tell them apart. The Lee-Mykland test can: it flags which returns are genuine jumps, and exactly when.

Volatility is the market breathing. A jump is the market flinching. They look alike on a chart — a big candle is a big candle — but they are different animals, and treating one as the other is how risk models get surprised. A burst of ordinary volatility is diffusion: continuous, self-similar, the kind of movement your variance estimate already expects. A jump is a discontinuity: a liquidation cascade, an earnings shock, a headline that repriced the asset in a single tick. The first you ride; the second you hedge against. So the practical question is not how much did it move, but which moves were jumps, and exactly when.

1. Why realized variance can't answer this

Aggregate measures blur the distinction on purpose. Realized variance sums every squared return and cannot tell a jump from a run of large diffusive moves. Bipower variation — which we covered in the article on bipower variation — does better: by multiplying adjacent absolute returns it stays robust to a lone spike, so the gap between realized variance and bipower variation estimates the total jump contribution over a window. But that is a verdict on the whole sample: it says jumps were present and how much variance they added, not which bar was the jump. For execution, risk, and stop placement, timing is the whole point.

2. The Lee-Mykland idea: standardize by local volatility

Lee & Mykland (2008), in "Jumps in Financial Markets: A New Nonparametric Test and Jump Dynamics," make the test local. For each return they build a standardized statistic — the return divided by an estimate of the instantaneous volatility right before it:

L(i) = rᵢ / σ̂(tᵢ)

The local volatility σ̂ is a jump-robust bipower average over the K returns immediately preceding bar i — and, crucially, the return being tested is excluded from its own benchmark, so a jump cannot inflate the very volatility it is being measured against. On a calm stretch, ordinary returns produce L-values of order one. A genuine jump, measured against the quiet volatility that came before it, produces an L-value that is enormous.

3. From a big number to a real test

A large statistic is suggestive; a jump test needs a threshold that controls false alarms across a whole series, not just one bar. Under the no-jump null, each L(i) is approximately standard normal, so the maximum of |L| over n bars follows an extreme-value (Gumbel) law. That gives a critical value calibrated so that random noise almost never trips a single false positive over the entire sample:

|L(i)| > Sₙ·β* + Cₙ,   β* = −log(−log(1−α))

with Cₙ and Sₙ the Gumbel location and scale for n test points and α the significance level. What survives the threshold is a jump you can defend statistically — pinned to the exact bar, with a sign. This is a far stricter and far more informative statement than a per-sample variance split, and it is exactly the discipline a crypto book needs when every violent wick invites the reflexive cry of "manipulation" — we made that case for a trading audience in our note on telling a real jump from noise.

4. What it does not promise

The test finds jumps in volatility units, so its sensitivity depends on the window K: too short and the local-volatility estimate is noisy, too long and it smears across regimes. Lee & Mykland show that a window on the order of √n satisfies the asymptotics, which is the sensible default, but it should track your sampling frequency. And the test detects that a discontinuity occurred, not why — it is a measurement, not a narrative. Read it as an honest jump clock, not a crystal ball.

5. Computing it

Our open-source orderflow-metrics library ships the test dependency-free, in TypeScript and Python — the local bipower volatility, the standardized statistics, and the Gumbel critical value all included:

import { leeMyklandJumps, leeMyklandStatistics } from "orderflow-metrics";

// log returns; one abnormal move sits at index 8
const returns = [0.004,-0.003,0.005,-0.004,0.003,-0.005,0.004,-0.003,0.06,-0.004,0.003,-0.005];

leeMyklandJumps(returns, { windowSize: 4 });
// [{ index: 8, statistic: 11.968, direction: 1 }] — one real jump, upward

leeMyklandStatistics(returns, { windowSize: 4 })[8]; // 11.968 — far beyond the ~3.83 threshold

The lone big move at index 8 posts a statistic of nearly 12 against a critical value of about 3.83, so it is flagged as a genuine jump; every ordinary bar stays well under the line. The Python distribution exposes the same functions (lee_mykland_jumps, lee_mykland_statistics, lee_mykland_critical_value). They sit beside the bipower jump tools and the rest of the market-microstructure toolkit we build in the open — install from our open-source page (npm and PyPI, MIT-licensed).

6. Conclusion

A jump and a jitter are not the same risk, and the difference is worth a real test rather than a glance. The Lee-Mykland statistic standardizes each move by the calm that preceded it and holds the result to an extreme-value threshold, so what it flags is a discontinuity you can point to on the clock — the bar, and the direction. Explore the rest of the toolkit in our quantitative research library, or read the implementation in our open-source metrics.

For more on volatility, jump detection, and open-source tooling, visit our official resources:

🧩 Open Source 💻 orderflow-metrics on GitHub 📚 More Research