Strasmore Research
Learn am Matt ConnorBy Matt Connor · Updated 2026-08-08

How Dem Dey Calculate Implied Volatility

Implied volatility no get closed-form formula. See how solver dey use iteration, Python and option price take find am, plus why vendors fit show different figures.

Implied volatility dey calculate through iteration, no be formula. No closed-form expression fit turn option market price back into volatility number. So solver go guess one volatility, use Black-Scholes price the option, compare model price with the quoted price, then repeat until both agree down to the last penny. Wetin follow na the complete method: the pricing function, the search loop for standard library Python, plus the reasons two vendors fit publish different numbers for the same contract.

Why implied volatility no get closed-form formula

Black-Scholes dey work for one direction. Give am spot price, strike, time to expiry, interest rate and volatility, e go return theoretical price. Five out of these six quantities dey observable. Volatility no dey. Na assumption about how far the stock go move between now and expiry.

Traders dey turn the problem around. Price dey for screen, while volatility na the unknown. Implied volatility na the volatility input wey make Black-Scholes price equal the option market price. Sigma, wey be the volatility term, dey inside normal distribution function two times, for both d1 and d2, and no algebraic rearrangement fit isolate am. Na there algebra stop. Numerical search come take over. Wetín implied volatility dey measure explain the interpretation; this page explain the machinery.

Two properties of the model dey make the search easy. Call model price dey rise whenever volatility rise, without exception, and e dey move smoothly. Quantity wey only dey climb fit get cornered by squeezing bracket around am.

The solver dey run once for each contract

The output na one number for each contract, no be one for each stock. Contracts for the same stock and the same expiry window fit give different answers. Every Apple (AAPL) option wey get 20 to 45 days remaining and trade on June 30, 2026, grouped by strike as fraction of the share price:

QueryOne solve for each contract: AAPL implied volatility by strike zone, June 30, 2026
The exact SQL behind every number
WITH toFloat64(strike_price) / toFloat64(underlying_close) AS moneyness
SELECT multiIf(moneyness < 0.90, '0.80-0.90',
               moneyness < 0.95, '0.90-0.95',
               moneyness < 1.00, '0.95-1.00',
               moneyness < 1.05, '1.00-1.05',
               moneyness < 1.10, '1.05-1.10',
                                 '1.10-1.20') AS strike_vs_spot,
       round(100 * avg(toFloat64(implied_volatility)), 1) AS implied_vol_pct,
       count() AS contract_count
FROM global_markets.options_greeks
WHERE underlying_symbol = 'AAPL'
  AND date = toDate('2026-06-30')
  AND days_to_expiry BETWEEN 20 AND 45
  AND iv_converged = 1
  AND volume > 0
  AND moneyness BETWEEN 0.80 AND 1.20
GROUP BY strike_vs_spot
ORDER BY min(moneyness)
Run this yourself

As you read the strike ladder, the 0.80-0.90 zone solve to 35.5%, the 0.95-1.00 zone solve to 28.1%, and the 1.10-1.20 zone solve to 27.3%. One company, one session, 6 answers. The bend for that curve get name: volatility skew, and one volatility for each stock no fit draw am.

The Black-Scholes price wey solver need match

S na share price, K na strike, T na time to expiry for years, r na risk-free rate, and N() na standard normal cumulative distribution. E mean say probability wey standard normal draw go land below one given point. Python get that last part inside math.erf, so interpreter alone don do.

apt-get update && apt-get install -y python3

For machine wey you no be root, put sudo for front of both commands. Then save this one as iv.py:

import math

def norm_cdf(x):
    return 0.5 * (1.0 + math.erf(x / math.sqrt(2.0)))

def bs_call(S, K, T, r, sigma):
    if T <= 0.0 or sigma <= 0.0:
        return max(S - K, 0.0)
    d1 = (math.log(S / K) + (r + 0.5 * sigma * sigma) * T) / (sigma * math.sqrt(T))
    d2 = d1 - sigma * math.sqrt(T)
    return S * norm_cdf(d1) - K * math.exp(-r * T) * norm_cdf(d2)

Na the complete forward model be this. Give am volatility, e go return price.

How dem dey calculate implied volatility, step by step

Bisection na the first method to learn. E no fit diverge, and e no need calculus.

  1. Put the answer between 0.01 (1% per year) and 5.0 (500%). Every traded option dey inside this range.
  2. Price the option for the midpoint of the range.
  3. If model price pass the market quote, the guess too high: move the top of the range down reach the midpoint. If e fall below, move the bottom up.
  4. Stop once model price land within one cent of the quote.
def implied_vol(price, S, K, T, r, lo=0.01, hi=5.0, tol=0.01):
    for _ in range(100):
        mid = 0.5 * (lo + hi)
        diff = bs_call(S, K, T, r, mid) - price
        if abs(diff) < tol:
            return mid
        if diff > 0.0:
            hi = mid
        else:
            lo = mid
    return 0.5 * (lo + hi)

# $100 stock, $100 strike, three months, 4% rates, $5.00 on the screen
print(round(implied_vol(5.00, 100.0, 100.0, 0.25, 0.04), 4))

Run python3 iv.py. E go print about 0.226, meaning implied volatility near 22.6% per year for that hypothetical quote. Every pass dey halve the range, and when you halve range wey be 4.99 wide twenty times, e go become narrower than 0.00001. So, the 100-iteration limit no go bind.

Why Newton-Raphson dey converge faster, and where e dey fail

Bisection dey throw away information wey model already get. Vega na how much option price dey change for each unit of volatility, and Black-Scholes dey give am in closed form. Newton-Raphson dey treat am like slope: measure pricing error, divide am by vega, then move the estimate by that amount.

def bs_vega(S, K, T, r, sigma):
    d1 = (math.log(S / K) + (r + 0.5 * sigma * sigma) * T) / (sigma * math.sqrt(T))
    return S * math.sqrt(T) * math.exp(-0.5 * d1 * d1) / math.sqrt(2.0 * math.pi)

def implied_vol_newton(price, S, K, T, r, sigma=0.5):
    for _ in range(20):
        v = bs_vega(S, K, T, r, sigma)
        if v < 1e-8:
            return None          # no slope left, hand the job back to bisection
        step = (bs_call(S, K, T, r, sigma) - price) / v
        sigma -= step
        if sigma <= 0.0:
            return None          # the step overshot into nonsense
        if abs(step) < 1e-6:
            return sigma
    return None

Near the money, e dey reach answer for three or four passes, compared with bisection’s dozen. The failure dey come from the denominator: vega dey shrink as strike dey move far from share price. Na the same AAPL contracts, with each zone’s average vega shown as percentage of the at the money reading:

QueryWhere the Newton step dey misbehave: AAPL vega by strike zone, June 30, 2026
The exact SQL behind every number
WITH toFloat64(strike_price) / toFloat64(underlying_close) AS moneyness,
     (
         SELECT avg(toFloat64(vega))
         FROM global_markets.options_greeks
         WHERE underlying_symbol = 'AAPL'
           AND date = toDate('2026-06-30')
           AND days_to_expiry BETWEEN 20 AND 45
           AND iv_converged = 1
           AND volume > 0
           AND abs(toFloat64(strike_price) / toFloat64(underlying_close) - 1) < 0.025
     ) AS atm_vega
SELECT multiIf(moneyness < 0.90, '0.80-0.90',
               moneyness < 0.95, '0.90-0.95',
               moneyness < 1.00, '0.95-1.00',
               moneyness < 1.05, '1.00-1.05',
               moneyness < 1.10, '1.05-1.10',
                                 '1.10-1.20') AS strike_vs_spot,
       round(100 * avg(toFloat64(vega)) / atm_vega, 1) AS vega_pct_of_atm,
       count() AS contract_count
FROM global_markets.options_greeks
WHERE underlying_symbol = 'AAPL'
  AND date = toDate('2026-06-30')
  AND days_to_expiry BETWEEN 20 AND 45
  AND iv_converged = 1
  AND volume > 0
  AND moneyness BETWEEN 0.80 AND 1.20
GROUP BY strike_vs_spot
ORDER BY min(moneyness)
Run this yourself

The wings get only small part of the sensitivity: 33.1% of the at the money vega for the 0.80-0.90 zone, and 31.6% for the 1.10-1.20 zone. If you divide pricing error by number wey small reach like that, the step go become enormous. E fit push the estimate below zero, where the model no get anything left to talk. Production solvers dey combine both methods: dem bracket am first, then use Newton to polish the result. Vega dey explain the greek itself.

Why two sources dey report different implied volatility

The model dey public and the arithmetic don settle, so the disagreement dey come from the inputs.

  • Mid versus last. The solver need one price. Contract wey get $2.00 bid and $2.20 offer get $2.10 midpoint, while the last print fit be $2.02 from ninety minutes ago. For contract like that, ten cents for price worth pass one point of volatility.
  • Dividends and carry. The function above dey price European call for stock wey no dey pay anything. Dividend before expiry dey reduce the forward price, and each desk dey use its own adjustment and rate.
  • American early exercise. US single stock options fit get exercised any day, and that right get value wey the European formula no get where to put. Solver wey ignore am go push the difference enter volatility. Binomial trees dey price the exercise right directly.
  • Stale quotes. Strike wey last trade on Tuesday still dey show quote, and the solver dey treat anything wey dem give am as truth.

Convergence dey make the last two clear. The panel below take eight household names on June 30, 2026, count traded contracts wey get 20 to 45 days left, and report both the at the money volatility and the share of contracts wey the solve converge:

QueryAt-the-money implied volatility and solver convergence, eight names, June 30, 2026
The exact SQL behind every number
WITH abs(toFloat64(strike_price) / toFloat64(underlying_close) - 1) AS distance_from_spot
SELECT underlying_symbol AS symbol,
       round(100 * avgIf(toFloat64(implied_volatility), iv_converged = 1 AND distance_from_spot < 0.05), 1) AS atm_iv_pct,
       round(100 * countIf(iv_converged = 1) / count(), 1) AS solved_pct,
       count() AS contract_count
FROM global_markets.options_greeks
WHERE date = toDate('2026-06-30')
  AND underlying_symbol IN ('AAPL', 'MSFT', 'NVDA', 'AMZN', 'TSLA', 'SPY', 'KO', 'JNJ')
  AND days_to_expiry BETWEEN 20 AND 45
  AND volume > 0
GROUP BY symbol
HAVING countIf(iv_converged = 1 AND distance_from_spot < 0.05) > 0
ORDER BY atm_iv_pct DESC
Run this yourself

TSLA carry the highest at the money reading among the 8 names at 47.7%, against 14.4% for SPY at the bottom. For the TSLA chain, 97.8% of traded contracts produce a converged answer. The rest na strikes where the price wey dem give the solver dey outside wetin any volatility fit reproduce, quote under intrinsic value or crossed market. Whether number like that high na separate question: is 30% IV high explain am, and the expected move convert am to dollar range.

The same contract, every session dem dey solve am again

Nothing dey stored for implied volatility. Dem dey calculate am again from whichever price dey show for screen. Below na the AAPL contract wey traders trade pass, and wey go expire July 17, 2026. Dem follow am from June 1 reach expiry. The strike no move, and the expiry no move:

QueryOne AAPL contract, re-solve am every session reach im July 17, 2026 expiry
The exact SQL behind every number
WITH (
         SELECT ticker
         FROM global_markets.options_greeks
         WHERE underlying_symbol = 'AAPL'
           AND date = toDate('2026-06-30')
           AND expiration_date = toDate('2026-07-17')
           AND iv_converged = 1
           AND volume > 0
         ORDER BY volume DESC
         LIMIT 1
     ) AS pinned_contract
SELECT date,
       round(100 * avg(toFloat64(implied_volatility)), 1) AS implied_vol_pct,
       round(avg(days_to_expiry)) AS days_to_expiry
FROM global_markets.options_greeks
WHERE ticker = pinned_contract
  AND date BETWEEN toDate('2026-06-01') AND toDate('2026-07-17')
  AND iv_converged = 1
  AND volume > 0
GROUP BY date
ORDER BY date
Run this yourself

Across 29 sessions, the calculated reading open at 25.1% with 46 days remaining, then finish at 26.6% with 4 days left. Every point for that line na one run of the loop above using that session quote. Our pages for each ticker publish the same calculation: AAPL implied volatility dey run am daily across the whole chain. So reader fit reproduce any figure there with the code for this page.

Implied volatility calculation FAQ

Implied volatility get formula?

No. Black-Scholes dey map volatility to price, but that mapping no get simple inverse formula because sigma dey inside normal distribution two times. Every implied volatility number wey you see here or anywhere else come from iterative solver.

How many iterations calculation dey take?

Each bisection pass dey cut the bracket by half. So, range from 0.01 to 5.0 go shrink below 0.00001 after twenty passes. To match quote to the nearest cent, calculation usually need about a dozen passes. Newton-Raphson fit reach answer in three or four passes when e near the money. But steps fit misbehave where vega small.

Why my broker and data vendor dey show different implied volatility?

Na because dem put different inputs inside the solver. Common differences na mid quote versus last trade, rate and dividend assumption, plus whether model handle American early exercise at all. For thin strike, stale quote alone fit move the answer by several points.

Calls and puts for the same strike dey give the same implied volatility?

For theory, yes. Put-call parity tie dem together for the same strike and expiry. For market, the two quotes dey set independently. So the solved numbers fit differ small. Na another reason chain-wide averages dey vary between vendors.

I fit calculate implied volatility without market data?

Yes, for hypothetical quote. The code above take price, strike, spot, time to expiry and rate, all typed by hand. To match live vendor number na the harder part. You need use the same inputs wey vendor use.


Every panel for here store the SQL wey dey behind am. Open one, then run the same solve against live chain for the Strasmore terminal.

#implied volatility#options#black-scholes#python#how-to