Approximating implied volatility of European options can be done in a few ways--this is just one. Below is a python implementation that uses Newton Raphson. You can use the implied_volatility
function to find the approximate implied volatility. You can then check it by plugging the output from that back into the option_price
function.
import numpy as np
from scipy.stats import norm
"""
right = 'C' or 'P'
s = Spot Price
k = Strike Price
t = Days to expiration
rfr = Risk-free Rate
sigma = volatility
div = Annual dividend rate. Defaulted to zero.
price = Known option price. Needed for implied_volatility function
"""
def d_one(s, k, t, rfr, sigma, div=0):
"""d1 calculation"""
d_1 = (np.log(s / k) +
(rfr - div + sigma ** 2 / 2) * t) / (sigma * np.sqrt(t))
return d_1
def d_two(s, k, t, rfr, sigma, div=0):
"""d2 calculation"""
d_2 = d_one(s, k, t, rfr, sigma, div) - sigma * np.sqrt(t)
return d_2
def nd_one(right, s, k, t, rfr, sigma, div=0):
"""nd1 calculation"""
if right == 'C':
nd_1 = norm.cdf(d_one(s, k, t, rfr, sigma, div), 0, 1)
elif right == 'P':
nd_1 = norm.cdf(-d_one(s, k, t, rfr, sigma, div), 0, 1)
return nd_1
def nd_two(right, s, k, t, rfr, sigma, div=0):
"""nd2 calculation"""
if right == 'C':
nd_2 = norm.cdf(d_two(s, k, t, rfr, sigma, div), 0, 1)
elif right == 'P':
nd_2 = norm.cdf(-d_two(s, k, t, rfr, sigma, div), 0, 1)
return nd_2
def option_price(right, s, k, t, rfr, sigma, div=0):
"""option price"""
right = right.upper()
t /= 365
if right == 'C':
price = (s * np.exp(-div * t) *
nd_one(right, s, k, t, rfr, sigma, div)
- k * np.exp(-rfr * t) *
nd_two(right, s, k, t, rfr, sigma, div))
elif right == 'P':
price = (k * np.exp(-rfr * t) *
nd_two(right, s, k, t, rfr, sigma, div)
- s * np.exp(-div * t) *
nd_one(right, s, k, t, rfr, sigma, div))
return price
def option_vega(s, k, t, rfr, sigma, div=0):
"""option vega"""
t /= 365
vega = (.01 * s * np.exp(-div * t) * np.sqrt(t)
* norm.pdf(d_one(s, k, t, rfr, sigma, div)))
return vega
def implied_volatility(right, s, k, t, rfr, price, div=0):
"""implied volatility approximation"""
epsilon = 0.00000001
sigma = 1.0
def newton_raphson(right, s, k, t, rfr, sigma, price, epsilon, div=0):
diff = np.abs(option_price(right, s, k, t, rfr, sigma, div) - price)
while diff > epsilon:
sigma = (sigma -
(option_price(right, s, k, t, rfr, sigma, div) - price) /
(option_vega(s, k, t, rfr, sigma, div) * 100))
diff = np.abs(
option_price(right, s, k, t, rfr, sigma, div) - price)
return sigma
iv = newton_raphson(right, s, k, t, rfr, sigma, price, epsilon, div)
return iv