impliedVolatility

Black-Scholes

Computes implied volatility from a market option price using Newton-Raphson.

Avg. gas

11,668 / 11,743

Max abs. error

2e-6

when σ < 1

Max rel. error

1e-6

when σ ≥ 1

Signature

solidity
function impliedVolatility(
    uint128 spot,
    uint128 strike,
    uint32  timeToExp,
    uint64  rate,
    uint128 optionPrice,
    bool    isCall
) internal pure returns (uint256 volatility)

Parameters

NameTypeDescription
spotuint128Current spot price, 18-decimal fixed-point.
strikeuint128Strike price, 18-decimal fixed-point. Precision-tuned for the no-arbitrage band against spot — see Bounds.
timeToExpuint32Time to expiration in seconds. Must be > 0 — timeToExp == 0 reverts (unlike the pricer, which treats it as expired).
rateuint64Annualized risk-free rate, 18-decimal fixed-point.
optionPriceuint128Observed market option price, 18-decimal fixed-point. Must lie within the no-arbitrage band, otherwise the solver reverts.
isCallbooltrue if optionPrice is a call price, false if it's a put price.

Returns

NameTypeDescription
volatilityuint256Implied volatility in 18-decimal fixed-point, clamped to [0.01%, 1800%].

Bounds

BoundValue
MIN_SPOT1e-6 smallest allowed spot price (1e12)
MAX_SPOT1e15 largest allowed spot price (1e33)
MAX_STSP_RATIO5× (strike must lie within [spot/5, spot·5])
MAX_EXPIRATION32 years (1,009,152,000 seconds)
MAX_RATE400% annual (4e18)
MIN_VOL_IV0.01% floor on the recovered vol (1e14)
MAX_VOL_IV1800% ceiling on the recovered vol (18e18)
IV_MAX_ITER30 Newton-Raphson iterations before reverting

Behavior

  • Validates all inputs against module-wide constants and reverts with a typed error on any violation.
  • Unlike the pricer and greeks, timeToExp == 0 is not allowed — a zero expiry reverts with TimeToExpiryLowerBoundError (there is no volatility to recover from an expired option).
  • The observed optionPrice must lie within the no-arbitrage band [max(S − K·e^(−rT), 0), S] for calls (analogously for puts) — otherwise PriceOutOfBoundsError.
  • Newton-Raphson from a fixed 55% seed, up to 30 iterations, converging when the price residual falls within ~1e6 wei. Reverts NoConvergenceError if it fails to converge or if vega gets too small to invert. Typical convergence is 4–6 iterations.
  • The recovered volatility is clamped to [MIN_VOL_IV, MAX_VOL_IV] — i.e. [0.01%, 1800%] — on every step.
  • Each iteration reuses precomputed state and evaluates the call / put price together with vega (the derivative Newton-Raphson needs) in a single pass. Pure internal function; no external calls, no storage.

How it works

impliedVolatility inverts the Black-Scholes pricer: given a market price, it finds the volatility σ that reproduces it. There is no closed form, so DeFiMath uses Newton-Raphson on the pricing residual:

σn+1=σnBS(σn)Pmarketvega(σn)\sigma_{n+1} = \sigma_n - \frac{\text{BS}(\sigma_n) - P_{\text{market}}}{\text{vega}(\sigma_n)}

Each step needs both the option price and its derivative with respect to vol (vega) at the current σ. These share almost all of their intermediate work — d₁, d₂, the density and CDF — so DeFiMath computes them together from cached state (ln(S/K), √T, the discount factor) that never changes across iterations, keeping each step cheap.

The solver seeds at σ₀ = 55%, caps at 30 iterations, and stops once the price residual is within IV_TOLERANCE ≈ 1e6 wei; the running estimate is clamped into [0.01%, 1800%] each step so it can't wander out of the supported range. Convergence is a round-trip guarantee: IV(price(σ)) ≈ σ to within a relative 1e-6 where σ ≥ 1 and an absolute 2e-6 where σ < 1 — head-to-head measurements live in defimath-compare.

Errors

ErrorTrigger
SpotLowerBoundErrorspot ≤ MIN_SPOT
SpotUpperBoundErrorspot ≥ MAX_SPOT
StrikeLowerBoundErrorstrike · 5 < spot
StrikeUpperBoundErrorspot · 5 < strike
TimeToExpiryUpperBoundErrortimeToExp ≥ MAX_EXPIRATION
TimeToExpiryLowerBoundErrortimeToExp == 0
RateUpperBoundErrorrate ≥ MAX_RATE
PriceOutOfBoundsErroroptionPrice outside the no-arbitrage band
NoConvergenceErrorsolver failed to converge (or vega too small to invert)

Example

solidity
import "defimath-lib/contracts/derivatives/BlackScholes.sol";

uint256 iv = BlackScholes.impliedVolatility(
    1000e18,         // spot = $1,000
    980e18,          // strike = $980
    60 days,         // 60 days to expiry
    0.05e18,         // 5% risk-free rate
    99.4e18,         // observed market price ≈ $99.40
    true             // call
);
// iv ≈ 0.60e18  (recovers ~60% vol)