3. SVI参数化模型拟合

任务目标

对单一到期日的期权隐含波动率微笑数据,使用SVI(Stochastic Volatility Inspired)参数化模型进行最小二乘拟合,得到五个模型参数,并解释每个参数对波动率曲线形状的控制作用。

SVI模型定义

SVI模型将总方差(而非波动率)表示为对数执行价偏离度的函数。令 k = ln(K/F)(K为执行价,F为远期价格),到期日T的总方差为:

w(k) = a + b * (ρ*(k-m) + sqrt((k-m)² + σ²))

其中约束条件:b ≥ 0, |ρ| < 1, σ > 0, a ≥ 0。拟合得到的ATM波动率为 sqrt(a + b*σ),曲线最小方差位置由 m 控制,左右倾斜程度由 ρ 控制,曲率由 σ 和 b 共同决定。

实现代码

import numpy as np
from scipy.optimize import least_squares

def svi_total_variance(k, params):
    """计算SVI总方差 w(k)"""
    a, b, rho, m, sigma = params
    return a + b * (rho * (k - m) + np.sqrt((k - m)**2 + sigma**2))

def svi_implied_vol(k, params, T):
    """将总方差转换为隐含波动率"""
    w = svi_total_variance(k, params)
    return np.sqrt(w / T)

def residuals(params, k, iv_market, T):
    """计算模型波动率与市场波动率的残差"""
    iv_model = svi_implied_vol(k, params, T)
    return iv_model - iv_market

def fit_svi(k, iv_market, T):
    """拟合SVI参数,返回最优参数和拟合质量指标"""
    # 参数边界: a≥0, b≥0, |ρ|<1, σ>0, m无约束
    lb = [0, 0, -0.99, 1e-4, -5]
    ub = [1, 5, 0.99, 5, 5]
    
    # 初始化: 用简单启发式方法
    a0 = np.min(iv_market)**2 * T
    b0 = 0.5
    rho0 = 0.0
    m0 = k[np.argmin(iv_market)]
    sigma0 = 0.5
    x0 = [a0, b0, rho0, m0, sigma0]
    
    result = least_squares(residuals, x0, args=(k, iv_market, T), 
                          bounds=(lb, ub), method='trf')
    
    params = result.x
    # 计算拟合误差(以波动率百分点为单位)
    iv_fitted = svi_implied_vol(k, params, T)
    rmse = np.sqrt(np.mean((iv_fitted - iv_market)**2)) * 100
    max_err = np.max(np.abs(iv_fitted - iv_market)) * 100
    
    return params, iv_fitted, rmse, max_err

# ========== 示例数据与调用 ==========
if __name__ == "__main__":
    # 构造单一到期日的市场波动率微笑数据(示例输入)
    T = 0.5  # 到期时间(年)
    strikes = np.array([0.85, 0.90, 0.95, 1.00, 1.05, 1.10, 1.15])
    F = 1.00  # 远期价格
    k = np.log(strikes / F)
    # 市场隐含波动率(百分比形式,如 18.5 表示 18.5%)
    iv_market_pct = np.array([24.0, 21.0, 18.5, 17.0, 16.5, 17.5, 19.5])
    iv_market = iv_market_pct / 100.0
    
    params, iv_fitted, rmse, max_err = fit_svi(k, iv_market, T)
    
    a, b, rho, m, sigma = params
    print(f"拟合参数: a={a:.4f}, b={b:.4f}, ρ={rho:.4f}, m={m:.4f}, σ={sigma:.4f}")
    print(f"RMSE = {rmse:.2f}%(波动率百分点),最大误差 = {max_err:.2f}%")
    print("\n参数含义:")
    print(f"  a = {a:.4f}: 总方差曲线的整体水平偏移")
    print(f"  b = {b:.4f}: 曲线倾斜与曲率的整体缩放系数")
    print(f"  ρ = {rho:.4f}: 左右倾斜方向(负值表示左高右低,即skew)")
    print(f"  m = {m:.4f}: 曲线最低点对应的对数执行价位置")
    print(f"  σ = {sigma:.4f}: 曲线底部弯曲程度(越大越平缓)")
    
    # 输出拟合对比表
    print("\n执行价   市场IV    模型IV    残差(百分点)")
    for i in range(len(strikes)):
        diff = (iv_fitted[i] - iv_market[i]) * 100
        print(f"{strikes[i]:.2f}    {iv_market_pct[i]:.1f}%   {iv_fitted[i]*100:.1f}%   {diff:+.2f}")

运行方式

需要安装 numpy 和 scipy。将代码保存为 svi_fit.py,在命令行执行:

pip install numpy scipy
python svi_fit.py

验证方法

程序输出五个拟合参数、RMSE与最大误差,并打印每个执行价的模型IV与市场IV对比。通过标准:

  • RMSE小于0.5个百分点(即0.005的波动率值),表明拟合精度良好;
  • 参数满足约束:b > 0,|ρ| < 1,σ > 0,a ≥ 0;
  • 观察ρ为负值(本示例数据呈现典型股票指数skew形态),m接近ATM位置附近,符合市场经验。

参数含义分析

本示例中拟合得到的ρ为负值,说明波动率曲线左侧(低执行价)高于右侧(高执行价),即存在负偏斜(skew),这是股票指数期权市场的典型特征。m值表示曲线最低点对应的执行价位置,若m接近0则最低点接近ATM。σ值越大,曲线底部越平缓,反映ATM附近波动率变化越温和。b作为整体缩放系数,与σ共同控制曲线的曲率大小。

SVI拟合结果:市场IV vs 模型IV 对数执行价 k = ln(K/F) 隐含波动率 (%) 16% 18% 20% 22% 24% -0.16 -0.08 0.00 0.08 0.16 市场IV SVI拟合 高执行价IV较低 (负偏斜) ATM

上图展示了本示例数据拟合后的效果:红色散点为市场报价的隐含波动率,蓝色曲线为SVI模型拟合结果。可以看到模型较好地捕捉了波动率微笑的负偏斜形态和曲率特征。若实际数据拟合误差较大,可尝试调整参数初始值或检查输入数据是否包含异常报价。