波动率建模实战:ARCH族与Heston模型详解及Python实现

发布时间:2026/10/26 2:57:32
波动率建模实战:ARCH族与Heston模型详解及Python实现

波动率这个东西,做过衍生品定价或者量化风控的人应该都有体会——它不像价格那样能直接观察到,却又实实在在影响着每一个定价结果和每一笔风险敞口。我刚入行那会儿,总觉得历史波动率算一算就够了,后来被市场反复教育才明白,波动率本身是动态的、有时变特征的,静态假设在真实市场里根本站不住脚。这也是为什么ARCH族模型和Heston模型会成为这个领域绕不开的两套工具:前者从离散时间序列出发刻画波动率的聚集与均值回复,后者从连续时间随机过程出发给波动率一个独立的随机源。这篇内容我打算把这两套模型的来龙去脉、参数含义、实操实现和踩坑经验完整梳理一遍,适合有一定统计基础、正在做波动率建模或者准备上手期权定价的朋友参考,零基础也能看懂大框架,有基础的可以直接抄代码跑起来。

1. 为什么波动率必须动态建模

1.1 静态波动率假设的三个致命伤

先说清楚问题,才知道工具为什么长这样。静态波动率假设——也就是假设波动率是一个常数——在教科书里很常见,Black-Scholes公式就是建立在这个前提上的。但真实市场里这个假设有三个绕不过去的硬伤。

第一个是波动率聚集。你去看任何一只标的的收益率序列,大幅波动往往扎堆出现,平静期也是一段一段的。今天暴跌3%,明天大概率还是高波动,不会立刻回到均值。这种“大波动跟着大波动”的现象,静态模型完全无法刻画,因为它假设每一天的波动率都一样。

第二个是均值回复。波动率不会无限发散,长期来看它会围绕某个中枢上下摆动。市场恐慌时波动率飙升,但终究会回落;市场沉寂时波动率低迷,也终究会被某个事件打破。这种拉回中枢的倾向,是动态模型必须捕捉的特征。

第三个是杠杆效应。收益率和波动率之间往往存在负相关——价格下跌时波动率上升得更猛,上涨时波动率反而温和。这个不对称性在股票市场尤其明显,静态模型对此无能为力。

我见过不少团队一开始用滚动窗口算历史波动率硬套,回测看着还行,一到实盘遇到波动率 regime 切换就原形毕露。所以动态建模不是锦上添花,是刚需。

1.2 离散与连续两条技术路线

面对动态波动率,业界发展出两条主要技术路线,正好对应标题里的两个模型。

ARCH族走的是离散时间路线。它把波动率看成过去残差平方的函数——今天的方差取决于昨天、前天……的冲击大小。Engle在1982年提出ARCH,Bollerslev在1986年扩展成GARCH,核心思想是“波动的记忆”。这条路线的优势是实现简单、参数少、对历史数据拟合直接,特别适合做风险度量(比如VaR)和波动率预测。

Heston走的是连续时间随机波动率路线。它假设波动率本身服从一个均值回复的随机过程(CIR过程),并且和标的价格的布朗运动相关。这条路线的优势是能给出期权定价的解析解(特征函数形式),能同时刻画波动率微笑和期限结构,特别适合做衍生品定价和校准。

两条路线不是替代关系,而是互补关系。做风控预测我优先用GARCH,做期权定价我优先用Heston。下面分别拆开讲。

2. ARCH族模型:从ARCH到GARCH的演进逻辑

2.1 ARCH(q)的基本结构与参数含义

ARCH(q)模型的核心表达式很简洁。设收益率 $r_t = \mu + \varepsilon_t$,其中 $\varepsilon_t = \sigma_t z_t$,$z_t$ 是标准化的白噪声(通常假设标准正态或t分布)。关键在于条件方差:

$$\sigma_t^2 = \omega + \sum_{i=1}^{q} \alpha_i \varepsilon_{t-i}^2$$

三个参数各有分工。$\omega > 0$ 是方差的基准水平,相当于“底噪”;$\alpha_i \geq 0$ 衡量过去第 $i$ 期冲击对当前方差的影响权重。所有 $\alpha_i$ 之和必须小于1,否则方差会发散——这是平稳性条件,实操中一定要检查。

q的阶数怎么定?理论上可以用信息准则(AIC/BIC)或者残差平方的自相关图来判断。但我实测下来,金融收益率数据用q=1到q=5基本够用,阶数再高容易过拟合,而且参数估计的稳定性会下降。ARCH(q)有个明显缺陷:要刻画长记忆需要很大的q,参数一多估计就飘。

2.2 GARCH(1,1)为什么成为事实标准

Bollerslev的改进很巧妙——在ARCH的基础上加入方差自身的滞后项:

$$\sigma_t^2 = \omega + \alpha \varepsilon_{t-1}^2 + \beta \sigma_{t-1}^2$$

别小看这个 $\beta \sigma_{t-1}^2$ 项,它让模型能用很少的参数捕捉长记忆。GARCH(1,1)只有三个参数,却能拟合绝大多数金融时间序列的波动率特征,这就是它成为业界默认选择的原因。

参数解读要记牢:$\alpha$ 是“冲击反应系数”,越大说明市场对新信息反应越剧烈;$\beta$ 是“记忆衰减系数”,越大说明波动率越粘滞、回复越慢;$\alpha + \beta$ 是“持续性”,越接近1说明波动率冲击消退越慢。股票指数上 $\alpha+\beta$ 经常在0.95以上,意味着一次冲击要很久才消化完。

注意:$\alpha + \beta < 1$ 是协方差平稳的必要条件。如果估计出来接近甚至超过1,说明模型设定有问题,或者数据存在结构性断点,别硬套。

2.3 非对称扩展:EGARCH与GJR-GARCH

标准GARCH有个盲点——它对正负冲击一视同仁,因为用的是 $\varepsilon_{t-1}^2$。但前面说的杠杆效应要求模型能区分涨跌。两个常用扩展:

EGARCH(Nelson, 1991)对对数方差建模,天然保证方差为正,还能直接刻画不对称:

$$\ln \sigma_t^2 = \omega + \alpha(|z_{t-1}| - E|z_{t-1}|) + \gamma z_{t-1} + \beta \ln \sigma_{t-1}^2$$

其中 $\gamma$ 就是不对称系数,负值表示负冲击推高波动更猛。

GJR-GARCH(Glosten-Jagannathan-Runkle)更直观,加一个示性项:

$$\sigma_t^2 = \omega + \alpha \varepsilon_{t-1}^2 + \gamma \varepsilon_{t-1}^2 I(\varepsilon_{t-1}<0) + \beta \sigma_{t-1}^2$$

$I(\cdot)$ 是示性函数,负冲击时多一个 $\gamma$ 的额外影响。我一般先用GARCH(1,1)打底,如果残差诊断发现不对称性显著,再上GJR-GARCH,参数解释更符合直觉。

3. Heston模型:连续时间随机波动率的完整拆解

3.1 双随机过程的数学结构

Heston模型的核心是把波动率也变成一个随机过程,用两个耦合的随机微分方程描述:

$$dS_t = \mu S_t dt + \sqrt{v_t} S_t dW_t^S$$ $$dv_t = \kappa(\theta - v_t)dt + \xi \sqrt{v_t} dW_t^v$$

其中 $dW_t^S$ 和 $dW_t^v$ 的相关系数是 $\rho$。五个参数各司其职:$\kappa$ 是方差过程的均值回复速度,$\theta$ 是长期方差水平,$\xi$ 是方差过程的波动率(vol of vol),$\rho$ 是价格与方差的相关性(通常为负,对应杠杆效应),$v_0$ 是初始方差。

这个结构妙在哪?方差过程 $v_t$ 用的是CIR过程(平方根过程),保证了方差非负(只要满足Feller条件 $2\kappa\theta > \xi^2$)。而 $\rho$ 的存在让模型能生成波动率微笑——这正是Black-Scholes做不到的。

3.2 特征函数与半解析定价

Heston模型之所以在业界流行,关键在于它给出了期权价格的半解析解。通过傅里叶变换,欧式看涨期权价格可以写成:

$$C = S_0 P_1 - K e^{-rT} P_2$$

其中 $P_1, P_2$ 是通过特征函数积分得到的概率。特征函数的显式形式涉及复对数,这里不展开完整推导,但要提醒一个实操大坑:复对数分支问题。直接按教科书公式实现,在某些参数区域会出现积分不连续,导致定价结果跳变。业界常用“Little Heston Trap”修正方案(Albrecher等,2007),把特征函数里的复数项处理成连续形式。我早期没注意这个,校准出来的参数看着合理,定价却偶尔离谱,排查了半天才发现是分支切割问题。

3.3 参数校准:从市场期权价格反推

Heston的参数不能像GARCH那样直接从收益率序列估计,得用市场期权价格反推——这就是校准(calibration)。目标是最小化模型价格与市场价格的加权误差:

$$\min_{\Theta} \sum_{i} w_i (C_i^{model}(\Theta) - C_i^{market})^2$$

实操要点:权重 $w_i$ 通常用Vega加权或者按1/买卖价差加权,避免深度虚值期权主导目标函数。优化算法我推荐先用差分进化(Differential Evolution)做全局搜索,再用Levenberg-Marquardt做局部精修。直接上局部优化极容易陷进局部最优,校准出来的参数虽然拟合当前曲面,但毫无经济意义。

提示:校准前务必检查期权数据的流动性,剔除买卖价差异常大、成交量极低的合约。垃圾数据进,垃圾参数出,这是铁律。

4. 实操落地:两套模型的完整实现路径

4.1 环境准备与数据预处理

我习惯用Python做原型,statsmodels和arch包能覆盖GARCH族,Heston需要自己写或者用QuantLib。先装依赖:

pip install numpy pandas scipy statsmodels arch matplotlib

数据预处理有几个关键动作。第一,收益率用对数收益率 $r_t = \ln(P_t/P_{t-1})$,别用简单收益率。第二,检查平稳性,ADF检验走一遍。第三,处理极端值——但别随便删,金融数据的厚尾是真实特征,删了反而失真,建议用Winsorize在1%和99%分位截尾。第四,样本量至少1000个交易日,否则GARCH参数估计不稳。

4.2 GARCH建模的完整代码流程

先跑一个标准GARCH(1,1):

import numpy as np import pandas as pd from arch import arch_model # 假设 returns 是已经算好的对数收益率序列(百分比形式) returns = returns * 100 # arch包建议用百分比,数值更稳定 model = arch_model(returns, vol='Garch', p=1, q=1, dist='t') res = model.fit(disp='off') print(res.summary())

这里dist='t'很关键。金融收益率厚尾明显,用正态分布会低估极端风险,t分布的自由度参数能自动适配厚尾程度。我对比过,同一组数据用正态和t分布,VaR回测的通过率差很多,t分布明显更稳。

拟合完看几个东西:$\alpha+\beta$ 是否小于1、t分布自由度是否合理(通常3到8之间)、标准化残差是否还有自相关。如果残差诊断不过关,考虑加GARCH阶数或者换GJR-GARCH。

预测波动率:

forecast = res.forecast(horizon=5, reindex=False) print(forecast.variance.iloc[-1])

horizon=5给出未来5期的方差预测。注意GARCH的预测会随期限拉长收敛到长期方差 $\omega/(1-\alpha-\beta)$,这是均值回复的体现。

4.3 Heston定价与校准的实现骨架

Heston的特征函数实现(采用Little Heston Trap修正):

import numpy as np def heston_char_func(u, T, kappa, theta, xi, rho, v0): """Heston特征函数,带分支修正""" d = np.sqrt((rho*xi*1j*u - kappa)**2 + xi**2*(1j*u + u**2)) g = (kappa - rho*xi*1j*u - d) / (kappa - rho*xi*1j*u + d) C = (kappa*theta/xi**2) * ((kappa - rho*xi*1j*u - d)*T - 2*np.log((1 - g*np.exp(-d*T))/(1 - g))) D = ((kappa - rho*xi*1j*u - d)/xi**2) * ((1 - np.exp(-d*T))/(1 - g*np.exp(-d*T))) return np.exp(C + D*v0 + 1j*u*np.log(1.0)) # 假设S0=1归一化

定价用数值积分(如Gauss-Legendre或梯形法)对特征函数做傅里叶逆变换。校准部分用scipy的差分进化:

from scipy.optimize import differential_evolution def calibrate_heston(market_prices, strikes, maturities, S0, r): def objective(params): kappa, theta, xi, rho, v0 = params # 参数边界约束 if 2*kappa*theta <= xi**2: # Feller条件 return 1e6 error = 0.0 for K, T, C_mkt in zip(strikes, maturities, market_prices): C_model = heston_price(S0, K, T, r, kappa, theta, xi, rho, v0) error += (C_model - C_mkt)**2 return error bounds = [(0.1, 10), (0.01, 1), (0.01, 2), (-0.99, 0.99), (0.01, 1)] result = differential_evolution(objective, bounds, seed=42, maxiter=200) return result.x

参数边界要设合理:$\kappa$ 别超过10,$\xi$ 别超过2,$\rho$ 严格在(-1,1)内。Feller条件作为硬约束加进去,否则校准出来的参数可能让方差过程触零,定价失真。

4.4 两套模型的对比与选用建议

维度GARCH族Heston
时间框架离散连续
数据输入收益率序列期权价格曲面
参数数量3-5个5个
主要用途波动率预测、VaR期权定价、曲面拟合
实现难度低中高
计算速度快校准较慢
波动率微笑不直接刻画天然支持

选用逻辑很简单:做风险管理和波动率预测,GARCH够用且高效;做衍生品定价和需要拟合波动率曲面,Heston更合适。有些团队会把两者结合——用GARCH预测的波动率作为Heston的初始 $v_0$ 或者先验,这个思路我在几个项目里试过,校准稳定性确实有提升。

5. 常见问题与排查技巧实录

5.1 GARCH参数估计不收敛怎么办

这是最高频的问题。排查顺序:先看数据有没有极端值或者结构性断点,画个收益率时序图一眼就能发现;再看样本量够不够,少于500个观测基本别指望稳定;然后检查是否用了百分比形式,原始小数形式的收益率数值太小,优化器容易卡住。如果都正常还不收敛,试试换优化器(arch包支持method='nm'或'bfgs'),或者给参数加初值。

5.2 Heston校准结果不稳定、参数乱跳

校准不稳定通常三个原因。第一,市场数据质量差,深度虚值期权价格噪声大,建议按Vega加权或者只保留平值附近±2个标准差的合约。第二,目标函数多峰,局部优化必然陷进去,必须用全局优化打底。第三,参数冗余——Heston的五个参数在某些数据下存在近似共线性,可以固定 $\theta$ 或者 $v_0$ 减少自由度。我一般固定 $v_0$ 为短期ATM隐含波动率的平方,校准其余四个。

5.3 波动率预测总是滞后于市场

GARCH的预测本质上是“向后看”的,它依赖历史冲击,遇到突发的 regime 切换必然滞后。这不是模型bug,是结构特性。缓解办法:一是缩短估计窗口(比如用滚动500天而非全样本),让模型更快适应;二是在预测里加入外生变量(如VIX类指标、成交量),用GARCH-X扩展;三是设置预测的置信区间,别只给点估计,把不确定性也呈现出来。

5.4 常见问题速查表

问题现象可能原因排查动作
GARCH方差不收敛数据含极端值/断点画时序图,Winsorize处理
$\alpha+\beta \geq 1$非平稳或结构断点分段估计,检查样本期
Heston定价跳变复对数分支问题采用Little Trap修正
校准参数无经济意义局部最优换全局优化,加参数约束
预测滞后市场模型结构特性缩短窗口,加外生变量
期权价格拟合好但曲面扭曲权重设置不当改Vega加权,剔除低流动性合约

实操心得:每次建模前先做数据质量报告——缺失值比例、极端值分布、平稳性检验、自相关结构,这四样过一遍,能省掉后面80%的排查时间。我吃过亏,曾经因为一个未处理的数据断点,GARCH参数估计完全失真,查了两天才定位到。

最后分享一个我在实际项目里反复验证的小技巧:GARCH和Heston不要孤立地用,做期权定价时用GARCH预测的短期波动率去约束Heston的 $v_0$,做风险度量时用Heston校准出的长期方差 $\theta$ 去校验GARCH预测的收敛水平,两套模型互相印证,比单打独斗靠谱得多。这个思路后续还可以往跳跃扩散、粗糙波动率方向扩展,但那是另一个话题了。