Hoe wordt implied volatility berekend?
Ontdek hoe een solver implied volatility uit een optiewaarde afleidt met iteratie, Python en Black-Scholes, en waarom dataleveranciers verschillende uitkomsten publiceren.
Implied volatility wordt berekend via iteratie, niet met een formule. Er bestaat geen gesloten vorm waarmee de marktprijs van een optie kan worden teruggerekend naar een volatilitycijfer. Een solver kiest daarom een volatility, berekent met Black-Scholes de optiewaarde, vergelijkt die modelprijs met de marktkoers en herhaalt dit proces totdat beide bedragen tot op de cent overeenkomen. Hieronder volgt de volledige methode: de pricingfunctie, de zoeklus in standaard-Python en de redenen waarom twee dataleveranciers verschillende cijfers voor hetzelfde contract publiceren.
Waarom implied volatility geen gesloten formule heeft
Black-Scholes werkt in één richting. U voert een spotprijs, een uitoefenprijs, een resterende looptijd, een rente en een volatility in. Het model geeft vervolgens een theoretische prijs. Vijf van deze zes grootheden zijn observeerbaar. Volatility niet. Het is een aanname over de afstand die het aandeel tussen nu en expiratie zal afleggen.
Traders draaien het probleem om. De prijs staat op het scherm en volatility is de onbekende. Implied volatility is de volatility-input die ervoor zorgt dat de Black-Scholes-prijs gelijk is aan de market price van de optie. Sigma, de volatility-term, staat tweemaal in de cumulative normal distribution function: in zowel d1 als d2. Geen enkele algebraïsche herschikking kan sigma isoleren. Daar houdt de algebra op. Vervolgens neemt een numerieke zoekmethode het over. Wat implied volatility meet behandelt de interpretatie; deze pagina behandelt de werking.
Twee eigenschappen van het model maken de zoekopdracht eenvoudig. De modelprijs van een call stijgt altijd wanneer volatility stijgt. Er zijn geen uitzonderingen. De prijs beweegt bovendien geleidelijk. Een grootheid die alleen maar stijgt, kan worden benaderd door er een interval omheen steeds kleiner te maken.
De solver draait eenmaal per contract
De output is één getal per contract, niet één getal per aandeel. Contracten op hetzelfde aandeel met dezelfde resterende looptijd wijken van elkaar af. Dit zijn alle Apple (AAPL)-opties met nog 20 tot 45 dagen looptijd die op 30 juni 2026 zijn verhandeld, gegroepeerd naar de uitoefenprijs als fractie van de aandelenkoers:
De exacte SQL achter elk getal
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)Als u de ladder van uitoefenprijzen van boven naar beneden doorloopt, kwam de zone 0.80-0.90 uit op 35.5% en de zone 0.95-1.00 op 28.1%. De zone 1.10-1.20 kwam uit op 27.3%. Eén onderneming, één handelsdag, 6 antwoorden. De knik in die curve heeft een naam: de volatility skew. Eén volatility voor een aandeel kan die niet weergeven.
De Black-Scholes-prijs die de solver moet reproduceren
S is de aandelenkoers, K de uitoefenprijs, T de resterende looptijd in jaren, r de risk-free rente en N() de cumulatieve standaardnormale verdelingsfunctie. Dat is de kans dat een trekking uit de standaardnormale verdeling onder een bepaald punt uitkomt. Python biedt die laatste component in math.erf. De interpreter alleen volstaat daarom.
apt-get update && apt-get install -y python3
Voeg op een machine waarop u geen rootrechten hebt sudo toe aan het begin van beide commando’s. Sla dit vervolgens op als 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)
Dit is het volledige forward model. Voer een volatility in en u krijgt een prijs.
Hoe implied volatility stap voor stap wordt berekend
Bisection is de methode die u als eerste moet leren. Deze methode kan niet divergeren en vereist geen calculus.
- Begrens de oplossing tussen 0,01 (1% per jaar) en 5,0 (500%). Elke verhandelde optie valt binnen die bandbreedte.
- Bereken de option price bij het middelpunt van de bandbreedte.
- Ligt de modelprijs boven de marktkoers, dan was de schatting te hoog. Verlaag de bovengrens naar het middelpunt. Ligt de modelprijs eronder, verhoog dan de ondergrens naar het middelpunt.
- Stop zodra de modelprijs binnen één cent van de quote ligt.
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)
# aandeel van $100, strike price van $100, drie maanden, rente van 4%, $5,00 op het scherm
print(round(implied_vol(5.00, 100.0, 100.0, 0.25, 0.04), 4))
Voer python3 iv.py uit. De code geeft ongeveer 0,226 als uitkomst: een implied volatility van circa 22,6% per jaar bij deze hypothetische quote. Bij elke iteratie wordt de bandbreedte gehalveerd. Een bandbreedte van 4,99 die twintig keer wordt gehalveerd, is smaller dan 0,00001. De limiet van 100 iteraties wordt daarom nooit bereikt.
Waarom Newton-Raphson sneller convergeert en waar de methode faalt
Bisection negeert informatie die al in het model aanwezig is. Vega is de verandering van de optieprijs per eenheid volatiliteit. Black-Scholes geeft deze waarde in gesloten vorm. Newton-Raphson gebruikt vega als helling: meet de prijsafwijking, deel die door vega en pas de schatting met die uitkomst aan.
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 # geen helling meer; geef de berekening terug aan bisection
step = (bs_call(S, K, T, r, sigma) - price) / v
sigma -= step
if sigma <= 0.0:
return None # de stap schoot door naar een ongeldige waarde
if abs(step) < 1e-6:
return sigma
return None
Bij opties rond de at-the-money-prijs is de uitkomst na drie of vier iteraties bereikt, tegenover ongeveer twaalf bij bisection. De oorzaak van de fout ligt in de noemer: vega neemt af naarmate de strike verder van de aandelenkoers afwijkt. Voor dezelfde AAPL-contracten, met de gemiddelde vega per zone weergegeven als percentage van de at-the-money-waarde:
De exacte SQL achter elk getal
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)De wings hebben slechts een fractie van de gevoeligheid: 33.1% van de at-the-money-vega in de 0.80-0.90-zone en 31.6% in de 1.10-1.20-zone. Een prijsafwijking delen door zo'n klein getal levert een zeer grote stap op. Daardoor kan de schatting onder nul uitkomen, waar het model geen bruikbare uitkomst meer geeft. Solvers in productieomgevingen combineren de twee methoden. Zij bepalen eerst een interval en verfijnen de uitkomst daarna met Newton. Vega behandelt de greek zelf.
Waarom twee bronnen een verschillende implied volatility rapporteren
Het model is openbaar en de rekenmethode staat vast. Het verschil zit in de inputs.
- Mid versus last. De solver heeft één prijs nodig. Een contract met een bid van $2,00 en een offer van $2,20 heeft een midpoint van $2,10, terwijl de laatste print $2,02 kan zijn geweest, negentig minuten eerder. Bij zo’n contract is tien cent prijsverschil meer waard dan één punt volatility.
- Dividenden en carry. De bovenstaande functie waardeert een Europese call op een aandeel dat geen dividend uitkeert. Een dividend vóór expiratie verlaagt de forward price. Elke trading desk past daarbij een eigen correctie en eigen rente toe.
- Vervroegde uitoefening bij Amerikaanse opties. Amerikaanse opties op individuele aandelen kunnen op elke handelsdag worden uitgeoefend. Aan dat recht is waarde verbonden, maar de Europese formule kan die waarde niet verwerken. Een solver die dit negeert, verwerkt het verschil in de volatility. Binomial trees waarderen het uitoefeningsrecht rechtstreeks.
- Verouderde quotes. Een strike waarop dinsdag voor het laatst is gehandeld, kan nog steeds een quote tonen. De solver behandelt die quote als de waarheid.
Convergence maakt de laatste twee punten zichtbaar. Het onderstaande panel neemt acht bekende aandelen op 30 juni 2026, telt de verhandelde contracten met nog 20 tot 45 dagen looptijd en rapporteert zowel de at-the-money volatility als het aandeel contracten waarvoor de solve convergeerde:
De exacte SQL achter elk getal
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 DESCTSLA noteerde de hoogste at-the-money volatility van de 8 namen op 47.7%, tegenover 14.4% voor SPY onderaan. In de TSLA-option chain leverde 97.8% van de verhandelde contracten een geconvergeerd resultaat op. De overige contracten hebben strikes waarbij de aan de solver verstrekte prijs buiten het bereik ligt dat met enige volatility kan worden gereproduceerd, bijvoorbeeld een quote onder de intrinsic value of een crossed market. Of een cijfer als dit hoog is, is een afzonderlijke vraag: is 30% IV hoog behandelt die vraag, en de verwachte beweging vertaalt deze naar een bandbreedte in dollars.
Hetzelfde contract, elke sessie opnieuw opgelost
Er wordt niets over implied volatility opgeslagen. De waarde wordt opnieuw berekend op basis van de prijs die op het scherm staat. Hieronder staat het meest verhandelde AAPL-contract met expiratie op 17 juli 2026, gevolgd vanaf 1 juni tot aan expiratie. De strike en de expiratiedatum veranderden niet:
De exacte SQL achter elk getal
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 dateGedurende 29 sessies opende de berekende waarde op 25.1%, met nog 46 dagen te gaan, en eindigde deze op 26.6%, met nog 4 dagen resterend. Elk punt op die lijn is één uitvoering van de bovenstaande lus op basis van de quote van die sessie. Op onze pagina’s per ticker publiceren we dezelfde berekening: implied volatility van AAPL wordt dagelijks voor de volledige keten berekend, zodat u elk cijfer daar kunt reproduceren met de code op deze pagina.
Veelgestelde vragen over de berekening van implied volatility
Bestaat er een formule voor implied volatility?
Nee. Black-Scholes koppelt volatility aan de prijs, maar die koppeling heeft geen elementaire inverse omdat sigma twee keer in de normale verdeling voorkomt. Elk getal voor implied volatility dat u hier of elders tegenkomt, komt uit een iteratieve solver.
Hoeveel iteraties vergt de berekening?
Elke bisection-pass halveert het interval. Een bereik van 0.01 tot 5.0 krimpt in twintig passes tot minder dan 0.00001. Een quote tot op de dichtstbijzijnde cent matchen vergt doorgaans ongeveer een dozijn iteraties. Newton-Raphson bereikt dat niveau bij at-the-money opties in drie of vier stappen, maar de stappen kunnen instabiel worden wanneer vega klein is.
Waarom tonen mijn broker en een data-vendor verschillende implied volatility?
Zij hebben verschillende inputs in de solver ingevoerd. De meest voorkomende verschillen zijn de mid quote versus de laatste trade, de rente- en dividendaanname en de vraag of het model rekening houdt met vervroegde uitoefening van Amerikaanse opties. Bij een strike met weinig handel kan alleen al een verouderde quote het resultaat met meerdere punten doen verschillen.
Geven calls en puts met dezelfde strike dezelfde implied volatility?
In theorie wel. Put-call parity koppelt beide opties aan dezelfde strike en expiry. In de praktijk worden de twee quotes onafhankelijk vastgesteld. De berekende waarden verschillen daardoor enigszins. Dat is een extra reden waarom gemiddelden over de volledige option chain per vendor verschillen.
Kan ik implied volatility berekenen zonder marktdata?
Ja, voor een hypothetische quote. De bovenstaande code gebruikt een prijs, een strike, een spot, de resterende looptijd en een rente die u handmatig invoert. Een live waarde van een vendor matchen is het moeilijkere deel. Daarvoor zijn dezelfde inputs nodig als die welke de vendor heeft gebruikt.
Elk paneel hier bevat de achterliggende SQL. Open een paneel en voer dezelfde solve uit op een live chain in de Strasmore-terminal.