Jak oblicza się zmienność implikowaną
Zmienność implikowaną wyznacza się iteracyjnie, bez wzoru zamkniętego. Poznaj solver, wycenę Blacka-Scholesa, kod w Pythonie i źródła różnic w wynikach.
Zmienność implikowana jest obliczana iteracyjnie, a nie za pomocą wzoru. Nie istnieje zamknięte wyrażenie, które pozwala przekształcić rynkową cenę opcji z powrotem w wartość zmienności. Solver przyjmuje wartość zmienności, wycenia opcję za pomocą modelu Blacka-Scholesa, porównuje cenę modelową z kwotowaniem i powtarza obliczenia, aż obie wartości będą zgodne co do centa. Poniżej przedstawiono całą metodę: funkcję wyceny, pętlę wyszukiwania w Pythonie korzystającym wyłącznie ze standardowej biblioteki oraz przyczyny, dla których dwóch dostawców publikuje różne wartości dla tego samego kontraktu.
Dlaczego zmienność implikowana nie ma wzoru w postaci zamkniętej
Model Blacka-Scholesa działa w jednym kierunku. Po wprowadzeniu ceny spot, ceny wykonania, czasu do wygaśnięcia, stopy procentowej i zmienności zwraca teoretyczną cenę opcji. Pięć z tych sześciu wartości można obserwować na rynku. Zmienność nie jest obserwowalna. Stanowi założenie dotyczące skali zmiany kursu akcji między chwilą obecną a wygaśnięciem opcji.
Traderzy odwracają ten problem. Cena jest widoczna na ekranie, a zmienność pozostaje niewiadomą. Zmienność implikowana to wartość parametru zmienności, przy której cena z modelu Blacka-Scholesa jest równa rynkowej cenie opcji. Sigma, czyli parametr zmienności, występuje dwukrotnie wewnątrz dystrybuanty rozkładu normalnego — zarówno w d1, jak i w d2 — dlatego nie można jej wyodrębnić za pomocą przekształceń algebraicznych. Na tym kończy się algebra. Następnie stosuje się wyszukiwanie numeryczne. Co mierzy zmienność implikowana omawia interpretację tego parametru, natomiast ta strona opisuje mechanizm obliczeń.
Dwie właściwości modelu ułatwiają wyszukiwanie. Cena call rośnie wraz ze wzrostem zmienności, bez wyjątków, a jej zmiana jest płynna. Wartość, która może tylko rosnąć, można wyznaczyć, zawężając przedział wokół poszukiwanego rozwiązania.
Solver działa raz dla każdego kontraktu
Wynikiem jest jedna liczba dla każdego kontraktu, a nie jedna liczba dla każdej spółki. Kontrakty na te same akcje, z tym samym terminem wygaśnięcia, również różnią się między sobą. Poniżej przedstawiono wszystkie opcje Apple (AAPL), którym w dniu 30 czerwca 2026 r. pozostawało od 20 do 45 dni do wygaśnięcia i które były przedmiotem obrotu tego dnia, pogrupowane według ceny wykonania wyrażonej jako ułamek ceny akcji:
Dokładny kod SQL dla każdej liczby
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)Odczytując drabinę cen wykonania, strefa 0.80-0.90 dała wynik 35.5%, strefa 0.95-1.00 — 28.1%, a strefa 1.10-1.20 — 27.3%. Jedna spółka, jedna sesja, 6 odpowiedzi. Wygięcie tej krzywej ma swoją nazwę: skośność zmienności. Pojedyncza zmienność przypisana do jednej spółki nie jest w stanie go odwzorować.
Cena Blacka–Scholesa, do której solver musi dopasować wynik
S oznacza kurs akcji, K — cenę wykonania, T — czas do wygaśnięcia wyrażony w latach, r — stopę wolną od ryzyka, a N() — dystrybuantę standardowego rozkładu normalnego, czyli prawdopodobieństwo, że realizacja standardowego rozkładu normalnego znajdzie się poniżej określonego punktu. Python udostępnia tę ostatnią funkcję w math.erf, dlatego wystarczy sam interpreter.
apt-get update && apt-get install -y python3
Jeżeli użytkownik nie ma uprawnień root, należy poprzedzić obie komendy prefiksem sudo. Następnie należy zapisać poniższy kod jako 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)
To kompletny model wyjściowy. Po podaniu zmienności otrzymuje się cenę.
Jak oblicza się zmienność implikowaną — krok po kroku
Metodą, od której należy zacząć, jest bisekcja. Nie może prowadzić do rozbieżności i nie wymaga rachunku różniczkowego.
- Należy wyznaczyć przedział obejmujący wynik: od 0,01 (1% rocznie) do 5,0 (500%). Każda notowana opcja mieści się w tym przedziale.
- Należy wycenić opcję w punkcie środkowym przedziału.
- Jeżeli cena modelowa jest wyższa od kwotowania rynkowego, przyjęta zmienność jest zbyt wysoka: górną granicę przedziału należy przesunąć do punktu środkowego. Jeżeli cena modelowa jest niższa, dolną granicę należy przesunąć w górę.
- Należy zakończyć obliczenia, gdy cena modelowa znajdzie się w odległości nie większej niż jeden cent od kwotowania.
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)
# akcje po 100 USD, cena wykonania 100 USD, trzy miesiące, stopy 4%, kwotowanie 5,00 USD
print(round(implied_vol(5.00, 100.0, 100.0, 0.25, 0.04), 4))
Uruchomienie python3 iv.py daje wynik około 0,226, czyli zmienność implikowaną na poziomie około 22,6% rocznie dla tego hipotetycznego kwotowania. W każdej iteracji przedział zmniejsza się o połowę. Przedział o szerokości 4,99 po dwudziestu takich podziałach ma szerokość mniejszą niż 0,00001, dlatego limit 100 iteracji nigdy nie zostanie osiągnięty.
Dlaczego metoda Newtona-Raphsona jest szybsza i gdzie zawodzi
Metoda bisekcji pomija informacje, które model już zawiera. Vega oznacza zmianę ceny opcji przypadającą na jednostkę zmienności. Model Blacka-Scholesa podaje ją w postaci zamkniętej. Metoda Newtona-Raphsona traktuje vegę jako nachylenie: mierzy błąd wyceny, dzieli go przez vegę i o tę wartość przesuwa oszacowanie.
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 # brak nachylenia, przekazanie zadania z powrotem metodzie bisekcji
step = (bs_call(S, K, T, r, sigma) - price) / v
sigma -= step
if sigma <= 0.0:
return None # krok przekroczył granicę i dał bezsensowny wynik
if abs(step) < 1e-6:
return sigma
return None
W pobliżu ceny at the money wynik uzyskuje się po trzech lub czterech iteracjach, podczas gdy metoda bisekcji wymaga ich kilkunastu. Źródłem problemu jest mianownik: vega maleje, gdy cena wykonania coraz bardziej oddala się od ceny akcji. W przypadku tych samych kontraktów na AAPL pokazano średnią vegę dla każdej strefy jako odsetek wartości odczytanej at the money:
Dokładny kod SQL dla każdej liczby
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)Skrzydła mają tylko część tej wrażliwości: 33.1% vegi at the money w strefie 0.80-0.90 oraz 31.6% w strefie 1.10-1.20. Dzielenie błędu wyceny przez tak małą wartość daje ogromny krok. Może on sprowadzić oszacowanie poniżej zera, gdzie model nie ma już nic do przekazania. W zastosowaniach produkcyjnych łączy się obie metody: najpierw wyznacza się przedział, a następnie doprecyzowuje wynik metodą Newtona. Vega zawiera omówienie samej greckiej litery.
Dlaczego dwa źródła podają różną implikowaną zmienność
Model jest publicznie dostępny, a sposób obliczeń nie budzi wątpliwości. Różnica wynika z danych wejściowych.
- Kurs środkowy a ostatnia transakcja. Solver potrzebuje jednej ceny. Kontrakt kwotowany przy ofercie kupna 2,00 USD i ofercie sprzedaży 2,20 USD ma kurs środkowy 2,10 USD, podczas gdy ostatnia transakcja mogła zostać zawarta 90 minut wcześniej po 2,02 USD. W przypadku takiego kontraktu różnica ceny o dziesięć centów ma większe znaczenie niż różnica o jeden punkt procentowy zmienności.
- Dywidendy i koszt finansowania. Powyższa funkcja wycenia europejską opcję call na akcje, które nie wypłacają dywidendy. Dywidenda wypłacana przed wygaśnięciem obniża cenę terminową, a każdy desk stosuje własną korektę i własną stopę procentową.
- Wcześniejsze wykonanie opcji amerykańskiej. Opcje na pojedyncze akcje w USA można wykonać w dowolnym dniu, a związana z tym możliwość ma wartość, której wzór europejski nie uwzględnia. Solver, który ją pomija, przenosi różnicę do zmienności. Drzewa dwumianowe wyceniają prawo do wcześniejszego wykonania bezpośrednio.
- Nieaktualne kwotowania. Strike, na którym ostatnia transakcja została zawarta we wtorek, nadal może mieć widoczne kwotowanie, a solver uznaje przekazaną mu wartość za prawidłową.
Zbieżność obliczeń uwidacznia dwa ostatnie problemy. Poniższy panel obejmuje osiem powszechnie znanych spółek z 30 czerwca 2026 r., zlicza zawarte kontrakty z terminem do wygaśnięcia od 20 do 45 dni oraz przedstawia zarówno zmienność at the money, jak i udział kontraktów, dla których obliczenia zakończyły się zbieżnością:
Dokładny kod SQL dla każdej liczby
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 odnotował najwyższą wartość zmienności at the money wśród 8 spółek — 47.7%, wobec 14.4% dla SPY zajmującej ostatnie miejsce. W łańcuchu TSLA dla 97.8% zawartych kontraktów uzyskano zbieżne rozwiązanie. Pozostałe przypadki dotyczą strike’ów, dla których cena przekazana solverowi znajduje się poza zakresem możliwym do odtworzenia przy użyciu dowolnej zmienności, ceny poniżej wartości wewnętrznej albo rynku przekrzyżowanego. To, czy taka wartość jest wysoka, stanowi odrębną kwestię: czy zmienność implikowana na poziomie 30% jest wysoka omawia ten temat, a oczekiwany ruch przelicza go na przedział wyrażony w USD.
Ten sam kontrakt, ponownie wyliczany podczas każdej sesji
Wartość implied volatility nie jest przechowywana. Jest ponownie wyliczana na podstawie ceny widocznej na ekranie. Poniżej przedstawiono najaktywniej handlowany kontrakt na AAPL z terminem wygaśnięcia 17 lipca 2026 r., obserwowany od 1 czerwca do wygaśnięcia. Cena wykonania i termin wygaśnięcia nie zmieniły się:
Dokładny kod SQL dla każdej liczby
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 dateW ciągu 29 sesji wyliczona wartość wynosiła początkowo 25.1%, przy 46 dniach do wygaśnięcia, a na końcu 26.6%, przy 4 dniach pozostałych do wygaśnięcia. Każdy punkt na tej linii odpowiada jednemu uruchomieniu opisanego wyżej algorytmu dla kwotowania z danej sesji. Na stronach poszczególnych tickerów publikowane jest to samo wyliczenie: implied volatility dla AAPL jest obliczana codziennie dla całego łańcucha opcji, dzięki czemu każdą przedstawioną tam wartość można odtworzyć za pomocą kodu zamieszczonego na tej stronie.
FAQ: obliczanie zmienności implikowanej
Czy istnieje wzór na zmienność implikowaną?
Nie. Model Blacka-Scholesa odwzorowuje zmienność w cenie, ale odwzorowanie to nie ma prostego odwrotnego rozwiązania, ponieważ sigma występuje dwukrotnie we wzorze na rozkład normalny. Każda wartość zmienności implikowanej, z którą można się spotkać tutaj lub w innym miejscu, jest wynikiem działania algorytmu iteracyjnego.
Ile iteracji wymaga obliczenie?
Każdy krok metody bisekcji zmniejsza przedział dwukrotnie. Zakres od 0.01 do 5.0 spada poniżej 0.00001 po dwudziestu krokach, a dopasowanie do kwotowania z dokładnością do najbliższego centa zwykle wymaga około kilkunastu iteracji. Metoda Newtona-Raphsona osiąga wynik po trzech lub czterech iteracjach w przypadku opcji at-the-money, ale jej kroki mogą być niestabilne tam, gdzie vega jest niska.
Dlaczego mój broker i dostawca danych pokazują różne wartości zmienności implikowanej?
Do algorytmu wprowadzono różne dane. Najczęstsze rozbieżności dotyczą średniej ceny bid-ask zamiast ostatniej transakcji, założonej stopy procentowej i dywidendy, a także tego, czy model uwzględnia możliwość wcześniejszego wykonania opcji amerykańskiej. W przypadku nisko płynnego strike'u sama nieaktualna kwotacja może zmienić wynik o kilka punktów procentowych.
Czy opcje call i put z tym samym strike'iem mają taką samą zmienność implikowaną?
W teorii tak. Parzystość put-call wiąże oba typy opcji przy wspólnym strike'u i terminie wygaśnięcia. W praktyce oba kwotowania ustalane są niezależnie, dlatego obliczone wartości nieznacznie się różnią. To kolejny powód, dla którego średnie dla całego łańcucha opcji różnią się między dostawcami.
Czy można obliczyć zmienność implikowaną bez danych rynkowych?
Tak, w przypadku hipotetycznego kwotowania. Powyższy kod przyjmuje cenę, strike, cenę instrumentu bazowego, czas do wygaśnięcia i stopę procentową, które są wprowadzane ręcznie. Dopasowanie wyniku do wartości publikowanej na bieżąco przez dostawcę jest trudniejsze. Wymaga użycia tych samych danych, które wykorzystał dostawca.
Każdy panel przechowuje zapytanie SQL, na podstawie którego został utworzony. Należy otworzyć wybrany panel, a następnie uruchomić to samo obliczenie dla aktualnego łańcucha opcji w terminalu Strasmore.