Implied volatility
For every option contract, at every minute, the platform solves three implied volatilities: one from the bid, one from the mid (bid + ask)/2, and one from the ask. They bracket the contract's true IV as iv_bid <= iv_mid <= iv_ask on a normal two-sided quote, and mid is the quote basis the read returns by default. Each is a per-strike, per-contract mark solved on its own quote. This is not a fitted, arbitrage-free surface, and the difference matters the moment you feed it to something that assumes one. This page covers how the solve works, how quote quality is graded, and where the marks stop being reliable. The full production pipeline is described in how every number is produced.
How IV is solved
The platform has the market price and every other pricing input, so it inverts the option pricing model for the one volatility that reproduces the price. It does this three times per contract per minute, once against the bid, once against the mid, and once against the ask, which is where the iv_bid <= iv_mid <= iv_ask bracket comes from.
Two pricing paths run underneath. European-exercise contracts use a fast analytic inversion. A narrow, gated subset of American-exercise contracts uses a model that accounts for early exercise (see when the early-exercise model is used).
The inputs to each solve:
0 in the solveThe dividend handling is the one non-obvious choice. The platform does not feed a dividend yield to the solver. Instead it escrows dividends into the spot: the present value of every dividend expected before expiration is subtracted from the raw stock close, and the solve runs at zero yield. That prices every maturity through one consistent mechanism. The spot itself starts from the raw, unadjusted stock close, not a split- or dividend-adjusted series.
The five greeks are computed at the mid IV, so they stay internally consistent with the mark you read.
When a solve is rejected
A solve that fails to converge, or that lands on a degenerate value, is not accepted. The IV for that row is null. The only value treated as structurally invalid is a non-positive volatility, which is what the solver returns for a mark sitting at or below the option's intrinsic floor.
A deliberately wide plausibility screen sits on top of that. It is set generously on purpose, wide enough that genuine extreme-vol wing and 0DTE prints survive it: very short-dated marks legitimately solve to very high vols, with time floored at one minute near expiry, and deep in-the-money marks legitimately solve to very low ones. A finite, positive solve inside the band is kept as is. One that lands outside it is nulled and labeled OUT_OF_BAND. The band limits are not published, so if your use case needs a tighter screen, filter on DTE and the quality signals below rather than assuming this one already did that work.
Quality, not merely present or absent
Each mark carries a quality label, and the label is the point. A quote can be priceable and still noisy, so the platform prices what it can and grades it, instead of silently dropping messy rows.
A mid IV is present for three kinds of quote:
- A clean, two-sided quote inside spread tolerance.
- A wide-spread quote, priced and flagged so you can down-weight it, not discarded.
- A zero-bid, one-sided quote (
bid = 0,ask > 0), where mid is taken as half the ask.
A mid IV is null for the rest:
- No market, both bid and ask zero.
- A mark below the no-arbitrage intrinsic floor that could not be recovered.
- A solver failure.
- A mark that fell outside the plausibility band (
OUT_OF_BAND). - A missing required input, such as spot or time.
So a non-clean label is not a missing value. A wide-spread or one-sided row still has a usable mid IV; it is graded, not gone. Alongside the label, the pipeline computes companion quality signals for weighting: the relative spread, a one-sided-wing flag, a below-intrinsic flag, a parity-recovered flag, and how stale the matched spot was. These per-row quality and provenance flags are computed but not readable through any accessor. A read blends across whatever marks exist without telling you which were clean (see what you read).
The wide-spread gate
A quote counts as too wide only when it is wide on both axes at once: relatively wide, spread greater than roughly 40% of mid, and absolutely wide, bid-ask greater than roughly $0.10. The gate is an AND on purpose.
A one-tick spread on a $0.02 option is relatively enormous, a 100%-plus spread, but it is the tightest market that option can have. A pure relative gate would flag those minimum-tick penny markets as garbage and null a chunk of otherwise clean wing quotes. Requiring an absolute dollar spread as well exempts them, and only marks a quote wide when it is wide in both percentage and dollars.
Zero-bid wings are handled separately: with no bid, mid is defined as half the ask, and the ask IV stands as a genuine upper bound on that contract's volatility.
Put-call-parity recovery
Deep in-the-money options are hard to invert. Their value is almost all intrinsic, so a small price error swings the implied vol wildly or pushes the mark below the floor where no volatility can reproduce it.
For those unsolvable in-the-money rows, the platform recovers the mid IV from the same-strike opposite-right contract, which is out-of-the-money there and well-conditioned. Under put-call parity a call and a put at the same strike and expiry share an implied vol, so the mirror is exact for a European pair. The recovered row is flagged parity-recovered.
The mirror touches the mid only. The bid and ask IVs stay honest direct solves and are never parity-adjusted. This same-strike mirror is the one place a contract's IV borrows from another contract. Nothing smooths across neighboring strikes or across expiries.
When the early-exercise model is used
Exercise style is series metadata, resolved per underlying, not guessed per quote. Index-style products that are cash-settled and European-settled are always priced with the European model and are never routed through the American path. Everything else, including index and single-name products that settle into shares, is American-style and eligible for an early-exercise correction.
Eligible is not the same as corrected. The American re-price is gated to where early exercise actually changes the price:
- In-the-money puts.
- In-the-money calls only when an ex-dividend is imminent or carry is high.
Every other row, all out-of-the-money and at-the-money options, all in-the-money calls in the normal case, and every European-style series, uses the European model. The vast majority of rows fall there. Which model priced each row is recorded internally so the two paths never mix within one contract's three IVs, though that provenance flag is not readable through an accessor.
Is this IV arbitrage-free?
No. The published IV is a per-strike, per-contract mark, not an arbitrage-free surface. This is a design choice, and a fitted arbitrage-free surface is a separate layer on top of these marks, not computed here.
Each contract's IV is solved independently from that contract's own price. Nothing in this layer couples one strike to its neighbors or one expiry to the next, so the marks are locally correct, each reproduces its own option's price, and globally unconstrained. In practice:
- Smiles can cross or lose convexity (butterfly arbitrage). Adjacent strikes are independent inversions, so in the noisy wings the curve can imply a negative probability density.
- Term structure can invert (calendar arbitrage). Total variance is not forced to increase with maturity at a fixed moneyness.
- The wings are least reliable, exactly the wide, one-sided, and parity-recovered points the quality flags identify.
Only two mechanisms ever touch more than one contract, and neither builds a surface. Same-strike parity recovery copies one opposite-right IV into the mid. One implied forward per expiration centers log-moneyness and reports carry. That is the extent of the coupling. There is no smile fit, no smoothing, and no arbitrage repair at this layer.
For point-in-time, per-contract questions, what is the 30-delta put IV right now, these marks are precisely what you want. Grid them raw and feed them to something that assumes a clean, arbitrage-consistent surface, local vol, a risk-neutral density, variance-swap replication, and you will hit the violations above. The arbitrage-free volatility surface that answers that second question is a separate layer, not computed here and distinct from the per-contract read described next.
What you read: option.iv()
Read implied volatility with the option.iv() accessor. It returns mid IV by default; pass iv_type="bid" or iv_type="ask" for the two sides of the bracket, and use_ex_earn_iv=true for the ex-earnings variant. The accessor is documented in full under data accessors.
// 30-DTE mid IV, the default quote basis
option.iv(30)Every read is 2D bilinear interpolated in DTE and in delta-or-log-moneyness across the contracts that bracket your target. When the chain is too sparse to bracket the target, or the underlying marks failed to solve, the read is null. It is never extrapolated past the available marks. Because the per-row quality and provenance flags are not surfaced, the interpolation blends across whatever marks exist, clean, wide, one-sided, or parity-recovered alike, without signaling which.
Read the bid/ask bracket to size the quote's own uncertainty:
// The bid/ask IV bracket at 30 DTE
iv_bid = option.iv(30, iv_type="bid")
iv_ask = option.iv(30, iv_type="ask")
iv_ask - iv_bidThe ex-earnings variant is null for names and dates with no pending earnings event, so coalesce it back onto regular IV when you want a continuous series:
// Ex-earnings IV, coalesced back onto regular IV where it is null
coalesce(option.iv(30, use_ex_earn_iv=true), option.iv(30))coalesce and sampling are covered under operators and functions. option.iv() returns at 1-minute resolution, so any rolling window over it counts minutes, not days; sample to daily first for an "over N days" window.
To read an interpolated IV at a target dte and delta or moneyness, use option.iv(). To read the mark on one specifically selected contract, contract selection through option.contract(...) and a leg's fields expose that contract's own iv column, which is its mid-price implied volatility, alongside strike, dte, the five Greeks, mid, bid, ask, underlying_price, and moneyness. That iv column is the raw solved mark on the selected contract; option.iv() interpolates across the contracts that bracket your target, so the two differ whenever the target falls between real strikes or expiries.