你拿到一份期权链:同一到期、几十个行权价,每个对应一个隐含波动率(IV)。把它们对行权价画出来,得到的不是一条平线,而是一条中间低、两边翘的曲线——这就是波动率微笑(smile)。股票期权更常是波动率倾斜(smirk):左侧(虚值看跌)明显更高,因为市场愿意为”崩盘保险”付溢价。
问题来了:这些 IV 报价是带噪声的,不同经纪商、不同快照对不上;更糟的是,原始报价偶尔会隐含无风险套利(比如相邻行权价之间能白捡钱)。任何依赖曲面定价的系统(波动率套利、风险中性密度、Exotic 定价、 Greeks 对冲)都受不了这种脏输入。
这篇文的主角是 SVI(Stochastic Volatility Inspired,Gatheral 2004):一个只要 5 个参数、就能把一整条微笑平滑参数化的工具。我会从形态讲起,用最小二乘逐月拟合,恢复二维曲面,最后用 Breeden-Litzenberger 定理把 SVI 翻译成风险中性密度,并指出”误校准的 SVI 如何给出负密度——也就是蝶式套利”。所有数字与图表均由文末 Python 真实生成。
一、波动率曲面长什么样,为什么难啃#
把 IV 写成两个变量的函数:资金费率 (对数口径,F 为远期价)和到期 。对固定 ,IV 随 的曲线就是”微笑”;不同 的曲线叠起来,就是曲面。

上图是我们在 4 个到期(0.1 / 0.25 / 0.5 / 1.0 年)上合成的”市场”微笑:典型的股票式 smirk——整体随到期升高(期限结构),左侧虚值看跌 IV 更高(负偏),且整体呈凸性。我们还加了 0.2% 量级的轻噪声,模拟真实报价的毛刺。
裸用这些点有三个麻烦:(1) 噪声让相邻点抖动,直接插值会得到锯齿;(2) 不同到期之间不连续;(3) 没有任何机制保证无套利。SVI 一次性解决前两点,并给第三点一个可检查的抓手。
二、SVI 原始参数化:一条 5 参数曲线#
SVI 不是直接对 IV 建模,而是对总方差 建模——总方差在 log-moneyness 上是更平滑、更稳定的量:
五个参数各有含义: 控制整体水平, 控制曲率幅度, 控制倾斜方向(负 即左偏 smirk), 是微笑的最低点位置, 控制微笑的”宽度/尖锐度”。约束 保证函数行为合理。
拟合就是最小二乘:给定某到期的市场点 ,找使 最小的参数。我们用带约束的 scipy.optimize.least_squares,并对多组初值择优——优先选”无套利”的解(总方差处处为正、且由它反推的密度处处非负,见第四节)。

四个到期的拟合结果(IV 口径的 RMSE 全部在 0.002 左右,几乎贴合市场点):
| 到期 T | a | b | ρ | m | σ | IV-RMSE |
|---|---|---|---|---|---|---|
| 0.10 | -0.076 | 0.653 | -0.950 | -0.994 | 0.389 | 0.00177 |
| 0.25 | -0.221 | 1.883 | -0.950 | -1.008 | 0.393 | 0.00211 |
| 0.50 | -0.402 | 3.000 | -0.937 | -0.899 | 0.405 | 0.00188 |
| 1.00 | -0.778 | 3.000 | -0.855 | -0.700 | 0.531 | 0.00222 |
注意 全接近 :这正是 smirk 左偏的数学签名。随到期变长, 更负(曲面整体抬升)、 略增(微笑变宽),都符合”越远越贵、越平”的直觉。
这里有个刻意的设计选择值得点破:SVI 建模的是总方差 ,而不是 IV 本身。原因有二。其一,总方差在 上比 IV 平滑得多——IV 在深虚值处会翘得很陡,平方之后反而更温顺,最小二乘更好收敛;其二,无套利条件(下一节会看到)天然作用在方差而非 IV 上,先落在方差空间里,后面做套利检查更顺。还原时再开方除以 ,就回到我们最终要的 IV。这个”先在方差空间拟合、再转换”的思路,也是绝大多数曲面模型(SSVI、SVI++、甚至局部波动率 calibration)的共识。
三、从逐月到整张曲面#
把每个到期的 SVI 参数拿来,对任意 算出 ,再开方除以 还原 IV,就得到一张连续、平滑、无锯齿的隐含波动率曲面:

这张曲面的价值在于:你可以安全地插值和外推。要某个不在原始报价网格上的 ?直接代入 SVI 公式,而不是在噪声点上做危险的线性插值。波动率套利、日历价差、方差互换定价,都建立在这张干净曲面上。
顺便说一句工程量:逐月拟合 4 条曲线,每次最小二乘跑几个初值,整个流程在普通笔记本上不到一秒,却把几百个带噪报价压缩成了 20 个数字(4 到期 × 5 参数)。这正是参数化曲面的精髓——用极少的、有经济含义的系数,代替又大又脏的原始网格,后续任何计算都更快、更稳、更可微。
四、SVI → 风险中性密度:并亮出套利红旗#
SVI 还有个杀手锏:它解析地给出风险中性密度。Breeden-Litzenberger 说,看涨期权价格对行权价的二阶导就是风险中性密度;Gatheral 把它写成 SVI 总方差的闭式:
其中 是标准正态密度, 都由 SVI 公式直接求导得到()。
一个正确校准、无套利的 SVI,其密度应当处处为正。下面蓝线是我们在 拟合出的无套利 SVI,密度最低点仍有 0.135,全程为正——健康的崩盘保险溢价形态。

红线是同一个到期下一个误校准的 SVI:总方差依然处处为正,但密度跌到了 ,约 4% 的区域内为负。密度为负在金融上意味着”你可以构造一个稳赚不赔的组合”——也就是蝶式套利(butterfly arbitrage)。这正是对原始 SVI 最著名的批评:它参数少、拟合好,但无约束拟合很容易掉进套利陷阱,尤其在稀疏报价、远处外推、或多到期各自独立拟合却互不协调时。
实务要点:原始 SVI 逐月独立拟合虽然方便,但无法保证跨到期的日历套利(calendar arbitrage) 不存在(总方差必须随 T 非减)。生产中常用它的改良版 SSVI(Surface SVI),把参数设为 T 的确定性函数,从一开始就锁死无套利。本文聚焦原始 SVI 的直觉,落地请用 SSVI 或加套利约束的拟合。
五、别踩这些坑#
- 原始 SVI ≠ 自动无套利:拟合 RMSE 低不代表没套利。务必做密度非负 + 跨期单调性检查(见第四节)。
- 远处外推危险:SVI 在 很大时近似线性,外推到极虚值/极实值会放大套利。只在拟合区间内使用,外推要设护栏。
- 参数冗余/病态:原始 SVI 的 存在近似等价组合,优化器可能漂进极端值(如极大 配极小 )。务必设合理上下界并多初值择优。
- IV 来源要先清洗:用 midpoint IV 而非 last;剔除明显错价(IV 为负、离谱高)的报价再拟合。
- forward 要用对:资金费率 里的 要用期权隐含的远期(认沽看涨平价反推),别用即期近似,否则整个曲面会系统性偏移。
附:可复现 Python#
纯 numpy/scipy 的核心实现(文中数字与图表即由此算得):
import numpy as np
from scipy.optimize import least_squares
def svi_w(k, a, b, rho, m, sig):
return a + b * (rho * (k - m) + np.sqrt((k - m)**2 + sig**2))
def svi_density(k, a, b, rho, m, sig):
"""Gatheral 风险中性密度(以 k=ln(K/F) 为变量)"""
d = np.sqrt((k - m)**2 + sig**2)
w = a + b * (rho * (k - m) + d)
wp = b * (rho + (k - m) / d)
wpp = b * sig**2 / d**3
sq = np.sqrt(w)
phi = np.exp(-k**2 / (2 * w)) / np.sqrt(2 * np.pi * w)
g = 1 - (k / (2 * w)) * wp + (1/4) * (1/w - 1/(4*w**2)) * wp**2 + 0.5 * wpp
return phi * g
def fit_svi(k, w_mkt):
def resid(p):
return svi_w(k, *p) - w_mkt
inits = [[w_mkt.mean()*0.9, 0.5, -0.5, 0.0, 0.3],
[w_mkt.mean()*0.8, 1.0, -0.7, -0.3, 0.5]]
lb = [-np.inf, 0.05, -0.95, -np.inf, 0.05]
ub = [ np.inf, 3.00, 0.95, np.inf, 1.20]
best = None
for p0 in inits:
sol = least_squares(resid, p0, bounds=(lb, ub), max_nfev=20000)
af = np.all(svi_density(k, *sol.x) > 0) and np.all(svi_w(k, *sol.x) > 0)
key = (0 if af else 1, float(np.sum(sol.fun**2)))
if best is None or key < best[0]:
best = (key, sol.x)
return best[1]
# ---- 演示: 合成微笑并拟合 ----
rng = np.random.default_rng(20260712)
ks = np.linspace(-0.4, 0.4, 41); T = 0.5
iv_mkt = (0.20 + 0.05*np.sqrt(T)) + (-0.25 - 0.10*np.sqrt(T))*ks + (0.60 + 0.30*np.sqrt(T))*ks**2
iv_mkt += rng.normal(0, 0.002, ks.size)
w_mkt = (iv_mkt**2) * T
a, b, rho, m, sig = fit_svi(ks, w_mkt)
iv_fit = np.sqrt(np.maximum(svi_w(ks, a, b, rho, m, sig), 1e-8) / T)
print("拟合参数 a=%.3f b=%.3f ρ=%.3f m=%.3f σ=%.3f" % (a, b, rho, m, sig))
print("IV-RMSE = %.5f" % np.sqrt(np.mean((iv_fit - iv_mkt)**2)))
# 误校准 SVI -> 负密度(蝶式套利)
g_bad = svi_density(ks, -0.30, 0.60, -0.50, -0.60, 0.60)
print("误校准密度最低点 = %.4f (负=套利)" % g_bad.min())python跑一遍你会看到:五参数 SVI 把带噪微笑拟合到 RMSE 千分之二,而无套利版本密度全程为正、误校准版本却跌成负值——一条曲线的参数,就是”干净曲面”与”隐形套利”之间的距离。