Come si calcola la volatilità implicita
La volatilità implicita si ricava per iterazione dal prezzo di un’opzione: metodo, solver Python con standard library e cause delle differenze tra vendor.
La volatilità implicita si calcola per iterazione, non tramite una formula diretta. Non esiste un’espressione in forma chiusa che trasformi il prezzo di mercato di un’opzione in un valore di volatilità. Un algoritmo di soluzione ipotizza quindi una volatilità, calcola il prezzo dell’opzione con Black-Scholes, confronta il prezzo del modello con la quotazione e ripete il processo finché i due valori coincidono al centesimo. Di seguito è illustrato l’intero metodo: la funzione di pricing, il ciclo di ricerca in Python con la standard library e i motivi per cui due vendor pubblicano valori diversi per lo stesso contratto.
Perché la volatilità implicita non ha una formula in forma chiusa
Black-Scholes funziona in una sola direzione. Si inseriscono prezzo spot, strike, tempo alla scadenza, tasso d’interesse e volatilità, e il modello restituisce un prezzo teorico. Cinque di queste sei grandezze sono osservabili. La volatilità non lo è. È un’ipotesi sull’ampiezza del movimento del titolo tra oggi e la scadenza.
I trader invertono il problema. Il prezzo è disponibile sullo schermo e la volatilità è l’incognita. La volatilità implicita è il valore della volatilità che rende il prezzo Black-Scholes uguale al prezzo di mercato dell’opzione. Sigma, il termine della volatilità, compare due volte nella funzione di distribuzione normale, sia in d1 sia in d2, e non può essere isolata con alcuna trasformazione algebrica. L’algebra si ferma qui. Subentra la ricerca numerica. Cosa misura la volatilità implicita tratta l’interpretazione; questa pagina descrive il meccanismo.
Due proprietà del modello rendono semplice la ricerca. Il prezzo teorico di una call aumenta ogni volta che aumenta la volatilità, senza eccezioni, e varia in modo continuo. Una grandezza che cresce soltanto può essere individuata restringendo progressivamente un intervallo attorno al suo valore.
Il solver viene eseguito una volta per contratto
L’output è un numero per contratto, non uno per azione, e i contratti sulla stessa azione nella stessa finestra di scadenza producono risultati diversi. Ecco tutte le opzioni su Apple (AAPL) con una vita residua compresa tra 20 e 45 giorni, negoziate il 30 giugno 2026 e raggruppate in base allo strike espresso come frazione del prezzo dell’azione:
L'esatto SQL dietro ogni numero
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)Lungo la scala degli strike, la zona 0.80-0.90 ha prodotto 35.5%, la zona 0.95-1.00 ha prodotto 28.1% e la zona 1.10-1.20 ha prodotto 27.3%. Una società, una seduta, 6 risultati. La curvatura di quella linea ha un nome, skew di volatilità, e una singola volatilità per azione non è in grado di rappresentarla.
Il prezzo Black-Scholes che il solver deve replicare
S è il prezzo dell’azione, K lo strike, T il tempo alla scadenza espresso in anni, r il risk free rate e N() la funzione di distribuzione cumulativa normale standard, cioè la probabilità che un’estrazione dalla normale standard assuma un valore inferiore a un determinato punto. Python include quest’ultimo componente in math.erf, quindi è sufficiente l’interprete.
apt-get update && apt-get install -y python3
Su una macchina in cui non si dispone dei privilegi root, anteporre sudo a entrambi i comandi. Salvare quindi il codice seguente come 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)
Questo è il forward model completo. Si inserisce una volatilità e si ottiene un prezzo.
Come si calcola la volatilità implicita, passo dopo passo
Il metodo della bisezione è il primo da imparare. Non può divergere e non richiede il calcolo differenziale.
- Racchiudi la soluzione tra 0,01 (1% annuo) e 5,0 (500%). Ogni opzione negoziata rientra in questo intervallo.
- Calcola il prezzo dell’opzione usando il punto medio dell’intervallo.
- Se il prezzo del modello è superiore alla quotazione di mercato, la stima è troppo alta: porta il limite superiore dell’intervallo al punto medio. Se è inferiore, porta il limite inferiore al punto medio.
- Interrompi il calcolo quando il prezzo del modello si trova entro un centesimo dalla quotazione.
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)
# Azione a $100, strike a $100, tre mesi, tassi al 4%, $5,00 sullo schermo
print(round(implied_vol(5.00, 100.0, 100.0, 0.25, 0.04), 4))
Esegui python3 iv.py. Il risultato è circa 0,226: per quella quotazione ipotetica, la volatilità implicita è vicina al 22,6% annuo. A ogni passaggio l’intervallo si dimezza. Un intervallo iniziale ampio 4,99, dimezzato venti volte, è più stretto di 0,00001; per questo il limite di 100 iterazioni non viene mai raggiunto.
Perché Newton-Raphson converge più rapidamente e dove si interrompe
La bisezione scarta informazioni già disponibili nel modello. Vega misura la variazione del prezzo dell’opzione per ogni unità di volatilità, e Black-Scholes la fornisce in forma chiusa. Newton-Raphson la tratta come una pendenza: misura l’errore di pricing, lo divide per vega e modifica di conseguenza la stima.
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 # non resta alcuna pendenza, si restituisce il compito alla bisezione
step = (bs_call(S, K, T, r, sigma) - price) / v
sigma -= step
if sigma <= 0.0:
return None # il passo ha superato il limite, entrando in un risultato privo di senso
if abs(step) < 1e-6:
return sigma
return None
In prossimità del prezzo at the money, il risultato arriva in tre o quattro passaggi, contro la dozzina richiesta dalla bisezione. Il punto debole è il denominatore: vega diminuisce quando lo strike si allontana dal prezzo dell’azione. Per gli stessi contratti su AAPL, con la vega media di ciascuna zona indicata come percentuale del valore at the money:
L'esatto SQL dietro ogni numero
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)Le ali della distribuzione hanno una frazione della sensibilità: 33.1% della vega at the money nella zona 0.80-0.90, 31.6% nella zona 1.10-1.20. Dividere un errore di pricing per un numero così piccolo produce un passo enorme, che può portare la stima sotto zero, dove il modello non ha più nulla da dire. I solutori in produzione combinano i due metodi: prima costruiscono un intervallo e poi lo rifiniscono con Newton. Vega illustra il greek in dettaglio.
Perché due fonti riportano una volatilità implicita diversa
Il modello è pubblico e i calcoli sono definiti, quindi il disaccordo dipende dagli input.
- Mid rispetto all’ultimo prezzo. Il solver ha bisogno di un solo prezzo. Un contratto quotato a 2,00 $ denaro e 2,20 $ lettera ha un midpoint di 2,10 $, mentre l’ultimo print potrebbe essere stato 2,02 $ novanta minuti prima. Su un contratto di questo tipo, una differenza di dieci centesimi sul prezzo vale più di un punto di volatilità.
- Dividendi e carry. La funzione precedente calcola il prezzo di una call europea su un’azione che non paga dividendi. Un dividendo prima della scadenza riduce il prezzo forward, e ogni desk applica il proprio aggiustamento e il proprio tasso.
- Esercizio anticipato in stile americano. Le opzioni su singole azioni statunitensi possono essere esercitate in qualsiasi giorno, e questo diritto ha un valore che la formula europea non può incorporare. Un solver che lo ignora trasferisce la differenza nella volatilità. Gli alberi binomiali valutano direttamente il diritto di esercizio.
- Quotazioni stale. Uno strike scambiato l’ultima volta martedì può mostrare ancora una quotazione, e il solver tratta qualunque valore riceva come corretto.
La convergenza rende visibili gli ultimi due fattori. Il pannello seguente considera otto nomi molto scambiati il 30 giugno 2026, conta i contratti negoziati con 20-45 giorni alla scadenza e riporta sia la volatilità at the money sia la quota di contratti per i quali il calcolo è convergente:
L'esatto SQL dietro ogni numero
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 ha registrato il valore at the money più elevato tra i 8 nomi, pari a 47.7%, contro 14.4% per SPY, all’ultimo posto. Sulla catena di TSLA, il 97.8% dei contratti negoziati ha prodotto un risultato convergente. I restanti contratti riguardano strike per i quali il prezzo fornito al solver è al di fuori dell’intervallo riproducibile da qualsiasi volatilità: una quotazione inferiore al valore intrinseco oppure un mercato crossed. Stabilire se un valore di questo tipo sia alto è una questione distinta: una IV del 30% è alta la esamina, mentre il movimento atteso lo converte in un intervallo espresso in dollari.
Lo stesso contratto, ricalcolato a ogni seduta
Non viene memorizzato nulla sulla volatilità implicita. Viene ricalcolata in base al prezzo visualizzato sullo schermo. Di seguito è riportato il contratto AAPL più scambiato con scadenza il 17 luglio 2026, seguito dal 1° giugno fino alla scadenza. Lo strike e la scadenza sono rimasti invariati:
L'esatto SQL dietro ogni numero
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 dateNel corso di 29 sedute, il valore calcolato è passato da 25.1%, con 46 giorni residui, a 26.6%, con 4 giorni alla scadenza. Ogni punto della linea corrisponde a un’esecuzione del ciclo descritto sopra sulla quotazione di quella seduta. Le nostre pagine per ticker pubblicano lo stesso calcolo: volatilità implicita di AAPL lo esegue ogni giorno sull’intera catena di opzioni, così il lettore può riprodurre qualsiasi dato riportato usando il codice presente in questa pagina.
FAQ sul calcolo della volatilità implicita
Esiste una formula per la volatilità implicita?
No. Black-Scholes mappa la volatilità sul prezzo, ma questa relazione non ha un’inversa elementare, perché sigma compare due volte all’interno della distribuzione normale. Ogni valore di volatilità implicita che si incontra, qui o altrove, è ottenuto con un solver iterativo.
Quante iterazioni richiede il calcolo?
A ogni passaggio del metodo di bisezione l’intervallo si dimezza. Un intervallo da 0,01 a 5,0 scende sotto 0,00001 in venti passaggi. Per allineare il risultato a una quotazione al centesimo servono di norma circa una dozzina di passaggi. Il metodo di Newton-Raphson arriva al risultato in tre o quattro iterazioni vicino at the money, ma può dare risultati instabili quando il vega è ridotto.
Perché il mio broker e un data vendor mostrano volatilità implicite diverse?
Hanno fornito al solver input diversi. Le differenze più comuni riguardano il mid quote rispetto all’ultimo trade, l’ipotesi sul tasso e sui dividendi e la gestione, o meno, dell’esercizio anticipato delle opzioni American. Su uno strike con pochi scambi, anche una quotazione non aggiornata può modificare il risultato di diversi punti.
Le call e le put con lo stesso strike hanno la stessa volatilità implicita?
In teoria sì. La put-call parity le collega allo stesso strike e alla stessa scadenza. Nella pratica, le due quotazioni vengono fissate in modo indipendente e i valori calcolati differiscono leggermente. È un ulteriore motivo per cui le medie sull’intera chain variano da un vendor all’altro.
Posso calcolare la volatilità implicita senza market data?
Sì, per una quotazione ipotetica. Il codice qui sopra utilizza un prezzo, uno strike, uno spot, il tempo alla scadenza e un tasso, tutti inseriti manualmente. Replicare il valore live di un vendor è la parte più complessa: richiede gli stessi input utilizzati dal vendor.
Ogni pannello qui conserva la query SQL sottostante. Aprine uno, quindi esegui lo stesso calcolo su una chain live nel terminale Strasmore.