Jump-diffusion: the Greek the smoothing breaks
Learn how Merton jump-diffusion affects option Greeks and why jump-intensity sensitivity can fail under some smoothing and JIT settings.
A diffusion alone can't fit a short-dated volatility smile — Black-Scholes
has no mechanism for a sudden gap, and the market prices one in. Merton's
1976 fix adds a compound-Poisson jump to geometric Brownian motion:
sometimes, with some intensity, the spot jumps by a random lognormal
amount. Recording that on a tape means putting an actual coin flip — did a
jump happen this step, yes or no — through the same reverse-mode machinery
that differentiates a smooth diffusion. Most Greeks are well-behaved, but
at the default smoothing width the jump-intensity Greek is NaN on
cpu-jit and finite on cpu.
The whole story
MertonJumpModel.step's own comment states a precise, easy-to-get-wrong
fact: the martingale-preserving drift compensator for this discretization
is -ln(1 + λκdt), not the textbook continuous-time -λκdt. The smoothed
"at-most-one-jump" factor has expectation exactly 1 + λκdt, not
e^{λκdt}, so only the logarithmic form makes the discounted spot an exact
per-step martingale under this specific scheme — the two forms agree only
to O(dt²). Smooth.lt(rec, u, λ·dt, width) is what makes "at most one
jump this step" differentiable at all: the underlying event is discrete
and stochastic, but P(≥2 jumps per step) = O((λdt)²), so the smoothed
at-most-one-jump approximation becomes exact as the step count grows —
the same fine-grid argument 3.1 used to justify treating a discretely-
monitored Asian option as continuous.
The step, verified against an exact reference
MertonJumpModel.step is validated against a completely independent
oracle: MertonJumpDiffusion.price, the closed-form Poisson-weighted
average of Black-Scholes prices, one term per possible jump count to
expiry. JumpDiffusionShowcase runs both side by side on the same market:
double mc = price(merton, MertonJumpModel.european(OptionType.CALL, t, steps), paths, 42L);
double exact = MertonJumpDiffusion.price(OptionType.CALL, s0, 100, t, r, sigma,
merton.jumpIntensity(), merton.jumpMean(), merton.jumpVol());
At 1.5 million paths, 128 steps: Monte-Carlo 7.4181 against the exact
series 7.5152 — a 1.3% gap, inside the deeper doc's own claimed 1.5%
convergence bound. That's the whole-price check. The interesting part is
what happens when you ask the same recorded tape for a Greek instead of a
price.
The jump-intensity Greek
At the default smoothing width (2×10⁻⁴), a standalone Java probe found
that d(price)/d(jumpIntensity) is NaN with cpu-jit, but finite with
cpu; a central bump also gives a finite result (1.90). This is a
cpu-jit-specific issue, not a property of the model's price.
The real run
JumpDiffusionShowcase also prints the implied-volatility smile both
jump models carve into an otherwise flat Black-Scholes surface, same
strikes, same 6-month maturity:
| strike | Black ivol | Merton ivol | Kou ivol |
|---|---|---|---|
| 80 | 15.00% | 28.98% | 27.08% |
| 100 | 15.00% | 23.77% | 21.34% |
| 120 | 15.00% | 22.50% | 20.48% |
Black-Scholes is flat by construction — one input volatility, one output
volatility, every strike. Both jump models produce a real downward slope
instead, from the same negative jumpMean (−0.09) biasing the jump
distribution toward crashes: a diffusion literally cannot produce this
shape no matter how its single volatility parameter is tuned, which is the
entire reason this model exists.
Try it yourself
Change merton.jumpMean() from -0.09 to +0.09 (a market that fears
melt-ups, not crashes) and predict which side of the smile gets steeper
before you rerun the showcase. (The slope flips: 80-strike ivol falls
from 28.98% to 22.97% and 120-strike ivol rises from 22.50% to
30.19% — a positive jump mean fattens the right tail instead of the
left, the mirror image of the negative-mean smile around the ATM strike.)
▶️ Run it
The TeaVM example uses cpu, so its browser run shows a finite gradient.
The Java showcase below uses cpu-jit, but prints prices and implied
volatilities only; it does not calculate the Greek:
Or run the Java price showcase:
mvn -o -q -pl nablatensor-examples exec:java \
-Dexec.mainClass=com.nablatensor.examples.JumpDiffusionShowcase -Dpaths=1500000
⚠️ What this doesn't do
Only Merton's lognormal jump size is covered in depth here, though Kou's asymmetric double-exponential jump appears in the same showcase; neither Variance-Gamma nor Bates (Heston plus jumps) exist in this codebase yet — the deeper doc's own "Deferred" section names both directly, needing a recordable Gamma subordinator and a Heston-composed step respectively.
What's next
→ Deeper: Jump-diffusion step blocks: Merton and Kou
has the full KouJumpModel API and the pinned test tolerances this page's
numbers are checked against.
→ Chapter 8 (Credit) is complete. Next: VaR and Expected Shortfall: three routes to one number —
Chapter 9 opens with risk aggregation, computed rather than looked up from
a table.