Python 中的快速隐含波动率计算

13

我正在寻找一种可以在Python中更快地计算隐含波动率的库。我有大约1百万行期权数据需要计算隐含波动率。有什么最快的方法可以计算隐含波动率呢?我尝试过使用 py_vollib,但它不支持向量化。计算需要大约5分钟左右。是否有其他库可以帮助加速计算?人们在实时波动率计算中使用什么,当每秒钟会出现数百万行数据时?


1
对于我们这些不是金融数学专家的人来说,您能定义一下隐含波动率函数吗?提供一些样本输入数据也会很有帮助。 - Code Different
6个回答

13

您需要意识到,隐含波动率计算是计算密集型的,如果您想要实时数据,也许Python不是最佳解决方案。

以下是您需要的函数示例:

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

计算单个值足够快

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))

隐含波动率:25.00%

市场价格= 35.94

模型价格= 35.94

但是,如果您尝试计算很多次,您会意识到这需要一些时间...

%%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))

耗时:10.5秒


嗨David Duarte,你有上述方程的“PUT”侧吗?目前我有一个方法def bs_put(S,K,r,vol,T),它返回bs_call(S,K,r,vol,T) - S + np.exp(-r * (T)) * K,但我不确定这将如何影响“def find_vol”方法...你能帮忙吗? - JC23
find_vol函数基本上是使用函数及其导数的牛顿-拉弗森方法来寻找根。用于定价看涨期权和看跌期权的BS公式的导数相对于波动率的变化(vega)是相同的,因此您只需更改函数以相应地确定价格(将看涨期权更改为看跌期权)。您可以通过看涨期权和看跌期权的平价关系或将定价公式更改为K * np.exp(-r * T) * N(-d2) - S * N(-d1)来定价看跌期权。 - David Duarte
这个实现只适用于欧式期权吗? - user1424739
"T=11/365" 可以得到一个现实的例子? - midtownguru
是的,可能是手指有点肥。我本来想设置 T=1。 - David Duarte

10
如果你将所有对norm.cdf()方法的调用更改为ndtr(),你将获得2.4倍的性能提升。如果将norm.pdf()方法更改为norm._pdf(),您将获得另外一个(巨大的)增长。实施这两个更改后,上面的示例从17.7秒降至0.99 s。虽然您可能不需要所有这些,但您将失去错误检查等。参见:https://github.com/scipy/scipy/issues/1914。在scipy.special中有ndtr()方法。

3

最近,py_vollib 的向量化版本已经发布在 py_vollib_vectorized 上。该版本基于 py_vollib 构建,可以更快地定价数千个期权合约并计算希腊值。


仅提一下,这基于py_vollib,它仅限于欧洲风格期权,因此有点具有误导性——在发现这一点之前,我曾花时间探索这条路。 - Oleg Medvedyev
这里提到的向量化软件包非常好用。虽然从技术上讲它只适用于欧式期权,但实际上几乎没有动力提前行使期权,因此它可以很好地代表美式期权。 - Jhirschibar

2
!pip install py_vollib

这将返回希腊字母和Black-Scholes价格以及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)

2
请注意,py_vollib 和其底层的 lets_be_rational 库仅适用于欧式期权(https://github.com/vollib/py_vollib/issues/7)。还有,GitHub 中的评论有些误导,我发现 py_vollib 基本上无法处理深度 ITM 的美式期权。在您深入研究之前,请牢记这一点。 - Oleg Medvedyev
@omdv,请问您是否找到可以计算美式期权价格的包? - user1424739

0
请在回测时使用py_vollib.black_scholes.greeks.numerical而不是analytical。当期权行权价格深度超出或低于实际价格以及合约流动性不足时,analytical会抛出错误。对于这种情况,请使用历史波动率而不是隐含波动率来计算期权希腊值。尝试:使用iv,如果失败则使用hv。

你的回答可以通过提供更多支持信息来改进。请编辑以添加进一步的细节,例如引用或文档,以便他人可以确认你的答案是正确的。您可以在帮助中心中找到有关如何编写良好答案的更多信息。 - Community

0
您可以使用二分查找快速找到隐含波动率。
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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接