Fast Implied Volatility Calculation in Python
Asked Answered
R

6

14

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?

Reitman answered 18/4, 2020 at 12:23 Comment(1)
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 helpfulResoluble
U
13

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

Unhitch answered 22/4, 2020 at 14:6 Comment(5)
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?Whinny
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)Unhitch
Is this implementation only for EU style options?Effeminacy
T=11/365 to get a realistic example?Haye
yeah, was probably a fat finger. I was going for T=1Unhitch
U
11

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

Ustkamenogorsk answered 24/8, 2020 at 11:49 Comment(0)
S
4
!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)
Samson answered 23/12, 2020 at 20:27 Comment(2)
Same comment as above. Note that 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
@omdv Do you find a package that can compute option price for American style options?Effeminacy
R
3

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.

Robinson answered 22/12, 2020 at 12:27 Comment(2)
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.Feeble
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 optionsLiddie
B
0

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
Beachlamar answered 11/4, 2021 at 11:20 Comment(0)
A
0

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

Airborne answered 25/5, 2022 at 8:48 Comment(1)
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.Godwin

© 2022 - 2024 — McMap. All rights reserved.