I am looking for a library which i can use for faster way to calculate implied volatility in python. I have options data about 1+ million rows for which i want to calculate implied volatility. what would be the fastest way i can calculate IV's. I have tried using py_vollib but it doesnt support vectorization. It takes about 5 mins approx. to calculate. Are there any other libraries which can help in faster calculation. What do people use in real time volatility calculations where there are millions of rows coming in every second?
You have to realize that the implied volatility calculation is computationally expensive and if you want realtime numbers maybe python is not the best solution.
Here is an example of the functions you would need:
import numpy as np
from scipy.stats import norm
N = norm.cdf
def bs_call(S, K, T, r, vol):
d1 = (np.log(S/K) + (r + 0.5*vol**2)*T) / (vol*np.sqrt(T))
d2 = d1 - vol * np.sqrt(T)
return S * norm.cdf(d1) - np.exp(-r * T) * K * norm.cdf(d2)
def bs_vega(S, K, T, r, sigma):
d1 = (np.log(S / K) + (r + 0.5 * sigma ** 2) * T) / (sigma * np.sqrt(T))
return S * norm.pdf(d1) * np.sqrt(T)
def find_vol(target_value, S, K, T, r, *args):
MAX_ITERATIONS = 200
PRECISION = 1.0e-5
sigma = 0.5
for i in range(0, MAX_ITERATIONS):
price = bs_call(S, K, T, r, sigma)
vega = bs_vega(S, K, T, r, sigma)
diff = target_value - price # our root
if (abs(diff) < PRECISION):
return sigma
sigma = sigma + diff/vega # f(x) / f'(x)
return sigma # value wasn't found, return best guess so far
Computing a single value is quick enough
S = 100
K = 100
T = 11
r = 0.01
vol = 0.25
V_market = bs_call(S, K, T, r, vol)
implied_vol = find_vol(V_market, S, K, T, r)
print ('Implied vol: %.2f%%' % (implied_vol * 100))
print ('Market price = %.2f' % V_market)
print ('Model price = %.2f' % bs_call(S, K, T, r, implied_vol))
Implied vol: 25.00%
Market price = 35.94
Model price = 35.94
But if you try to compute many, you will realize that it takes some time...
%%time
size = 10000
S = np.random.randint(100, 200, size)
K = S * 1.25
T = np.ones(size)
R = np.random.randint(0, 3, size) / 100
vols = np.random.randint(15, 50, size) / 100
prices = bs_call(S, K, T, R, vols)
params = np.vstack((prices, S, K, T, R, vols))
vols = list(map(find_vol, *params))
Wall time: 10.5 s
PUT
side of the above equations? Right now I have a method def bs_put(S, K, r, vol, T) - return bs_call(S, K, r, vol, T) - S + np.exp(-r*(T))*K
but I'm uncertain as to how that would impact the def find_vol
method... can you assist? –
Whinny find_vol
function is basically the newton raphson method for finding roots and uses a function and its derivative. The derivative of the bs formula to price a call and a put in respect to the vol is the same (vega) so you just have to replace the function to determine the prices accordingly (change call to put). You can either price a put throught put call parity or changind the pricing formula to K * np.exp(-r * T) * N(-d2) - S * N(-d1)
–
Unhitch T=11/365
to get a realistic example? –
Haye If you change all calls to norm.cdf()
-method into ndtr()
, you will get a 2.4 time performance increase.
And if you change norm.pdf()
-method into norm._pdf()
, you will get another (huge) increase.
With both changes implemented, the example above dropped from 17.7 s down to 0.99 s on my machine.
You will lose error checking etc. but in this case you probably don't need all that.
See: https://github.com/scipy/scipy/issues/1914
ndtr()
is in scipy.special
!pip install py_vollib
This will return greeks along with black_scholes price and iv
import py_vollib
from py_vollib.black_scholes import black_scholes as bs
from py_vollib.black_scholes.implied_volatility import implied_volatility as iv
from py_vollib.black_scholes.greeks.analytical import delta
from py_vollib.black_scholes.greeks.analytical import gamma
from py_vollib.black_scholes.greeks.analytical import rho
from py_vollib.black_scholes.greeks.analytical import theta
from py_vollib.black_scholes.greeks.analytical import vega
import numpy as np
#py_vollib.black_scholes.implied_volatility(price, S, K, t, r, flag)
"""
price (float) – the Black-Scholes option price
S (float) – underlying asset price
sigma (float) – annualized standard deviation, or volatility
K (float) – strike price
t (float) – time to expiration in years
r (float) – risk-free interest rate
flag (str) – ‘c’ or ‘p’ for call or put.
"""
def greek_val(flag, S, K, t, r, sigma):
price = bs(flag, S, K, t, r, sigma)
imp_v = iv(price, S, K, t, r, flag)
delta_calc = delta(flag, S, K, t, r, sigma)
gamma_calc = gamma(flag, S, K, t, r, sigma)
rho_calc = rho(flag, S, K, t, r, sigma)
theta_calc = theta(flag, S, K, t, r, sigma)
vega_calc = vega(flag, S, K, t, r, sigma)
return np.array([ price, imp_v ,theta_calc, delta_calc ,rho_calc ,vega_calc ,gamma_calc])
S = 8400
K = 8600
sigma = 16
r = 0.07
t = 1
call=greek_val('c', S, K, t, r, sigma)
put=greek_val('p', S, K, t, r, sigma)
py_vollib
and underlying lets_be_rational
libraries are limited to European style options. The comment in the github is a bit misleading as well, as I found that py_vollib basically fails to work deep ITM American-style options. Keep this in mind before you venture too deep into it. –
Feeble As of recent, there is a vectorized version of py_vollib
available at py_vollib_vectorized, which is built on top of the py_vollib
and makes pricing thousands of options contracts and calculating greeks much faster.
You could use a binary search to find the implied vol quickly
def goalseek(spot_price: float,
strike_price: float,
time_to_maturity: float,
option_type: str,
option_price: float):
volatility = 2.5
upper_range = 5.0
lower_range = 0
MOE = 0.0001 # Minimum margin of error
max_iters = 100
iter = 0
while iter < max_iters: # Don't iterate too much
price = proposedPrice(spot_price=spot_price,
strike_price=strike_price,
time_to_maturity=time_to_maturity,
volatility=volatility,
option_type=option_type) # BS Model Pricing
if abs((price - option_price)/option_price) < MOE:
return volatility
if price > option_price:
tmp = volatility
volatility = (volatility + lower_range)/2
upper_range = tmp
elif price < option_price:
tmp = volatility
volatility = (volatility + upper_range)/2
lower_range = tmp
iter += 1
return volatility
please use py_vollib.black_scholes.greeks.numerical instead of analytical for back testing purpose. Analytical throwing errors when option strike prices are deep out or in the money as well as illiquid contract, for this case use historical volatility instead of implied volatility to calculate option greeks. try: with iv and except: with hv
© 2022 - 2024 — McMap. All rights reserved.