2. 隐含波动率计算与曲面构建

任务目标

本案例基于给定的期权市场报价(行权价、到期时间、期权价格),通过Black-Scholes模型反推隐含波动率(IV),并进一步构建以行权价和剩余期限为轴的隐含波动率曲面,用于观察波动率微笑/偏斜及期限结构特征。

实现要点

隐含波动率是使BS理论价格等于市场价格的波动率。由于BS公式无法解析反解IV,采用牛顿-拉夫逊迭代法数值求解。曲面构建采用网格化插值(线性插值即可),将离散的IV点映射到规则网格上,便于可视化分析。

关键完整代码


import numpy as np
from scipy.stats import norm
from scipy.interpolate import griddata
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

# ---------- 1. BS模型定价 ----------
def bs_price(S, K, T, r, sigma, option_type='call'):
    if T <= 0 or sigma <= 0:
        return np.nan
    d1 = (np.log(S/K) + (r + 0.5*sigma**2)*T) / (sigma*np.sqrt(T))
    d2 = d1 - sigma*np.sqrt(T)
    if option_type == 'call':
        return S*norm.cdf(d1) - K*np.exp(-r*T)*norm.cdf(d2)
    else:
        return K*np.exp(-r*T)*norm.cdf(-d2) - S*norm.cdf(-d1)

# ---------- 2. 牛顿法反推隐含波动率 ----------
def implied_vol(market_price, S, K, T, r, option_type='call',
                init=0.2, tol=1e-6, max_iter=100):
    sigma = init
    for _ in range(max_iter):
        price = bs_price(S, K, T, r, sigma, option_type)
        vega = S * norm.pdf((np.log(S/K) + (r + 0.5*sigma**2)*T) /
                            (sigma*np.sqrt(T))) * np.sqrt(T)
        if abs(vega) < 1e-12:
            break
        diff = price - market_price
        sigma -= diff / vega
        if sigma <= 0:
            sigma = 1e-4
        if abs(diff) < tol:
            break
    return sigma

# ---------- 3. 市场数据(模拟输入) ----------
# 标的资产价格
S0 = 100.0
r = 0.03

# 构造期权报价: (行权价K, 剩余期限T年, 看涨期权市场价格)
# 数据体现波动率微笑与期限结构
quotes = [
    # T=0.1年
    (90, 0.1, 10.85), (95, 0.1, 6.35), (100, 0.1, 2.65),
    (105, 0.1, 0.85), (110, 0.1, 0.25),
    # T=0.3年
    (90, 0.3, 12.50), (95, 0.3, 8.60), (100, 0.3, 5.20),
    (105, 0.3, 2.80), (110, 0.3, 1.35),
    # T=0.6年
    (90, 0.6, 15.20), (95, 0.6, 11.80), (100, 0.6, 8.60),
    (105, 0.6, 5.90), (110, 0.6, 3.85),
]

# ---------- 4. 计算隐含波动率 ----------
iv_data = []
for K, T, price in quotes:
    iv = implied_vol(price, S0, K, T, r, 'call')
    iv_data.append((K, T, iv))
    print(f"K={K:5.0f}  T={T:.1f}  市场价={price:6.2f}  IV={iv:.4f}")

# ---------- 5. 构建波动率曲面 ----------
K_vals = np.array([d[0] for d in iv_data])
T_vals = np.array([d[1] for d in iv_data])
IV_vals = np.array([d[2] for d in iv_data])

# 插值到网格
K_grid = np.linspace(K_vals.min(), K_vals.max(), 50)
T_grid = np.linspace(T_vals.min(), T_vals.max(), 30)
K_mesh, T_mesh = np.meshgrid(K_grid, T_grid)
IV_surface = griddata((K_vals, T_vals), IV_vals,
                      (K_mesh, T_mesh), method='linear')

# ---------- 6. 可视化 ----------
fig = plt.figure(figsize=(10, 7))
ax = fig.add_subplot(111, projection='3d')
surf = ax.plot_surface(K_mesh, T_mesh, IV_surface,
                       cmap='viridis', edgecolor='none', alpha=0.9)
ax.scatter(K_vals, T_vals, IV_vals, color='red', s=30, label='市场IV点')
ax.set_xlabel('行权价 K')
ax.set_ylabel('剩余期限 T (年)')
ax.set_zlabel('隐含波动率')
ax.set_title('隐含波动率曲面')
fig.colorbar(surf, shrink=0.6)
plt.legend()
plt.show()

运行与验证

运行环境:Python 3.8+,需安装 numpy、scipy、matplotlib。

执行方式:直接运行上述脚本。控制台将输出每个期权的隐含波动率数值,并弹出三维曲面图。

通过判定标准:

  • 每个IV值均为正数(通常在0.05~0.60之间),且迭代收敛(无异常报错);
  • 将反推的IV代回BS公式,计算价格与输入市场价的误差小于1e-4(代码中tol=1e-6保证精度);
  • 曲面图呈现:同一期限下,平值期权(K≈100)IV较低、两侧虚值期权IV较高(波动率微笑);同一行权价下,期限越短IV波动越剧烈,期限越长IV趋于平滑(期限结构)。

形态特征分析要点

运行后观察曲面:沿K轴方向呈现“微笑”形态——深度虚值看涨期权(K=110)与深度实值(K=90)的IV高于平值(K=100),反映尾部风险溢价;沿T轴方向,短期限IV曲线弯曲更明显,长期限IV趋于水平,体现波动率均值回归特性。若市场存在明显偏斜(如股票期权),曲面会呈现单边倾斜而非对称微笑。