Skip to content

Newton vs Halley for implied volatility

Implied volatility is a root-finding problem in disguise: the Black-Scholes price is strictly increasing in σ, so the vol that matches a market quote solves f(σ) = BS(σ) − market_price = 0.

Newton follows the tangent line and converges quadratically (correct digits double per step); Halley uses the second derivative as well and converges cubically (digits triple):

Newton:  σ ← σ − f/f′                    f′ = vega  = S·φ(d1)·√T
Halley:  σ ← σ − (f/f′)/(1 − c)          c  = f·f″/(2·f′²),  f″ = volga = vega·d1·d2/σ

All derivatives are closed-form, so Halley costs a few extra flops per iteration, nothing more. On a 7-day at-the-money option (true σ = 1.2):

iteration Newton |f| Halley |f|
1 3.1e-02 3.1e-02
2 1.2e-07 1.3e-10
3 1.4e-14 0.0

The core of each solver, minus safeguards:

def iv_newton(price, s, k, t, r):
    sigma = (price / s) * (2.0 * math.pi / t) ** 0.5  # Brenner-Subrahmanyam guess
    while abs((f := bs(s, k, t, r, sigma) - price)) > 1e-12:
        sigma -= f / vega(s, k, t, r, sigma)
    return sigma

def iv_halley(price, s, k, t, r):
    sigma = (price / s) * (2.0 * math.pi / t) ** 0.5
    while abs((f := bs(s, k, t, r, sigma) - price)) > 1e-12:
        v = vega(s, k, t, r, sigma)
        sigma -= (f / v) / (1 - f * volga(s, k, t, r, sigma) / (2 * v * v))
    return sigma

polars_vol.implied_vol(..., method="newton" | "halley") wraps both steps in a [1e-7, 10] bracket with a bisection fallback, making them equally robust. In batch backfills the wall-clock difference is nil — each iteration is dominated by the two CDF evaluations both methods share, and Halley only saves about one of ~5 iterations. Halley earns its keep when each function evaluation is expensive (PDE pricing, calibration inner loops). Either way, deep-ITM/OTM quotes barely pin σ (vega → 0): the recovered IV is only determined to about price-precision / vega.