Earnings volatility and implied move
An upcoming earnings release loads one trading day with a burst of expected variance on top of the stock's everyday movement. This page explains how the platform separates those two pieces. For a symbol with an earnings calendar, it fits a variance model across the expirations that straddle the event and recovers three quantities: ambient daily variance (the everyday component), event daily variance (the earnings jump), and the implied move (the expected absolute move on earnings day). Stripping the event component from each contract's implied volatility leaves ex-earnings IV, the one earnings output you can read today through an accessor. The decomposition runs entirely in variance, which is additive over time, so an option expiring after earnings carries both components and one expiring before carries only the ambient part.
Scope
Only symbols with an earnings calendar produce any of this. A single company with a scheduled quarterly report has a defined event date to solve against. Broad ETFs and indices have no single earnings event, so the earnings stage never runs for them.
For SPY, ex-earnings IV is null on every row, and so are the earnings metrics. Read data coverage for which symbols carry an earnings calendar.
The variance decomposition
At each timestamp the platform builds one at-the-money IV per expiration, then fits a two-parameter variance model across those expirations.
The per-expiration IV is a vega-weighted average of mid-IVs across the near-money strikes, not a single ATM strike. It keeps strikes with 0.05 <= |delta| <= 0.95, averages the put and call at each strike, then weights each strike by its vega. Vega-weighting up-weights the most vol-sensitive strikes and cuts measurement noise. At least two strikes are required for an expiration to be used.
With one variance point per expiration, the model is
total_variance_i = X * (N_days_i - E_i) + Y * E_iwhere N_days_i is days to expiration i, E_i = 1 when expiry i falls on or after the event and 0 otherwise, X is ambient daily variance, and Y is event daily variance. A weighted least-squares fit across the straddling expirations recovers X and Y. Each expiration is weighted by 1/t^2, where t is its time to expiry, so the near-term expirations, which carry the most information about the event, dominate the fit and long-dated expirations cannot swamp it. At least two expirations are required, with at least one landing after the event, so the fit can tell the everyday variance apart from the one-day jump. A negative or degenerate solution (either variance at or below zero, or a singular system) is rejected and the metrics for that timestamp are set to null, never NaN.
The three headline metrics
From X and Y the platform reports three numbers, one row per timestamp:
sqrt(365 * X)sqrt(365 * Y)sqrt(Y) * sqrt(2/pi) * 100The implied move uses sqrt(2/pi), the mean absolute move of a normal distribution, so a value of 5.0 means roughly a plus-or-minus 5% move on earnings day.
Event timing: BMO vs AMC
The announcement time decides which expirations count as post-earnings. The platform compares the announcement moment to 16:00 ET.
- Before close (hour < 16, BMO): the first affected date is the announcement date itself, so the event affects expirations on or after that date.
- At or after close (hour >= 16, AMC): the first affected date is the calendar day after the announcement date.
That first affected date is the published next earnings date. The engine adds one calendar day for an after-close print with no trading-day roll, so an at-close Friday print lands on Saturday and there is no holiday or half-day adjustment. The date is only ever compared against real expirations through expiration >= effective_date, so the earnings-inclusion flag is unaffected either way.
Fit defaults and null rules
The fit uses expirations out to about 0.75 years (nine months). The near floor is split by which side of the event an expiration sits on: a pre-earnings expiration enters the fit only beyond about 3/365 (roughly three days), while a post-earnings expiration is floored at about 1/365 (roughly one day). The lower post-event floor keeps the short front expiration that straddles the event, the single most informative point about the earnings jump, inside the fit, while a very short pre-earnings expiration, which carries only noisy ambient information, stays out. Each expiration needs at least two strikes in the delta band to contribute an IV point, and the fit needs at least two expirations spanning the event.
When the solution is degenerate the metrics go to null for that timestamp:
- Fewer than two usable expirations in the window.
- No expiration reaching the event, so
Ycannot be identified. - A negative or non-finite fit for either
XorY.
Ex-earnings IV
Once the event variance is known, the platform strips it from each post-earnings contract's IV so you see the term and skew structure without the earnings bump. It computes a per-expiration variance scale factor from an ATM reference, floored by the ambient vol and clamped to [0, 1], then applies it in variance space: ex_earn_iv = sqrt(iv^2 * scale) for bid, mid, and ask.
Three cases determine the result:
- Pre-earnings contract (expires before the event): no earnings component to remove, so ex-earnings IV equals the regular IV.
- Post-earnings contract, fit succeeded: ex-earnings IV is the earnings-stripped value.
- Post-earnings contract, fit failed: falls back to the regular IV.
Because pre-earnings and failed-fit contracts both retain the regular IV, ex-earnings IV is genuinely null only for no-calendar symbols (and wherever the underlying regular IV was itself null).
What you read
Ex-earnings IV is exposed through the option accessor. Pass use_ex_earn_iv=true on option.iv(...) and it returns the ex-earnings IV for the chosen quote basis. Because the value is null for no-calendar symbols (and wherever the underlying regular IV was itself null), read it without gaps by coalescing with regular IV:
// Ex-earnings 30-DTE mid IV, falling back to regular IV where unavailable
coalesce(option.iv(30, use_ex_earn_iv=true), option.iv(30))The coalesce operator returns the first non-null value at each timestamp, so a no-calendar symbol or a failed decomposition falls through to standard IV instead of leaving a gap. use_ex_earn_iv defaults to false, so a plain option.iv(...) call returns standard IV with the earnings jump intact.
The three headline metrics have no accessor. Event vol, ambient vol, the implied move (the headline trader number), the next earnings date, and the event timing are all computed and stored, but none is readable from a Signal today. Only ex-earnings IV is readable now; do not reach for the others by name.
Grain note
The earnings metrics live at one row per (symbol, timestamp), a separate grain from the per-contract option chain. Ex-earnings IV, by contrast, attaches to each contract, which is why it reaches you through option.iv(...) on the per-contract chain while the metrics timeline stays one row per timestamp.