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?
-
For those of us who are not experts in financial math, can you define the implied volatility function? Some sample input data would also be helpful – Code Different Apr 18 '20 at 14:29
6 Answers
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

- 644
- 4
- 11
-
hi @David Duarte do you have the `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? – JC23 Nov 27 '20 at 17:40
-
The `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)` – David Duarte Nov 28 '20 at 19:23
-
-
-
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

- 136
- 1
- 4
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.
-
Just to mention that this is based on py_vollib, which is limited to European-style options, as this is a bit misleading - I've spent time exploring this path before finding it out. – Oleg Medvedyev Jan 21 '21 at 04:08
-
the vectorized package mentioned here works really well. And @oleg while true it technically is only for euro-options, there is a near null incentive to exercise an option early, so it is a fine proxy for american options – Jhirschibar Aug 19 '23 at 11:09
!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)

- 638
- 8
- 28
-
2Same comment as above. Note that `py_vollib` and underlying `lets_be_rational` libraries are [limited to European style options](https://github.com/vollib/py_vollib/issues/7). 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. – Oleg Medvedyev Jan 21 '21 at 04:12
-
@omdv Do you find a package that can compute option price for American style options? – user1424739 Nov 07 '21 at 19:29
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

- 11
- 1
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

- 3
- 3
-
Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community May 25 '22 at 09:10