简介:这份PPT课件面向金融学、计量经济学方向的学生与研究人员,系统讲解GARCH类模型在金融时间序列波动性分析中的原理与应用。内容从Engle提出的ARCH过程切入,梳理条件异方差性的来源与ARCH(q)的建模思路,进而展开GARCH(1,1)及高阶GARCH(p,q)的形式、参数含义、最大似然估计与ARCH-LM检验方法,并延伸到EGARCH、TGARCH、GARCH-M等变体,结合上证指数GARCH(1,1)实证案例演示波动率预测与杠杆效应的刻画。资源包共1个PPT文件,约749KB,结构按ARCH过程、模型检验与估计、模型扩展三节递进,配套学习目标与实证图表,便于课堂讲授或自学时对照梳理知识框架。目前已有266人学习,适合需要理解金融波动聚集性、尖峰厚尾特征与风险管理建模方法的读者作为入门与复习参考。
1. 从波动丛聚到条件异方差:第六章GARCH模型分析与应用想解决的问题
第六章GARCH模型分析与应用这份课件里有个案例值得先看:把上证指数1990年12月19日到2006年8月31日的3855个日收益率丢进一个AR(1)模型,残差用Ljung-Box检验,p值很大,干净得像白噪声;可把残差平方再做一次自相关,滞后1到10阶几乎全部显著。同一份数据,一次说“没有自相关”,一次说“强相关”,差别只在于对残差做了什么变换。这就是课件要处理的核心矛盾——收益率本身几乎不可预测,收益率的方差却高度可预测。
课件的骨架是四段:ARCH过程的提出背景与金融异方差特征、GARCH(1,1)的均值方程与条件方差方程、ARCH-LM检验与残差平方相关图这套检验估计流程、以及EGARCH、TGARCH、GARCH-M三类扩展加一个上证指数实证。做量化想给仓位加波动率约束的、做风控要给VaR找一个会动的分母的、以及被教材里一堆符号绕晕的,都能从这份材料里拿到能直接上手的东西。
2. ARCH过程与GARCH(1,1):均值方程和条件方差方程怎么摆
2.1 金融时间序列的三个典型事实
传统线性模型默认扰动项同方差,这个假设在金融数据上基本站不住。课件第一节花了不少笔墨描述的现象,落到建模层面可以归纳成三条,它们决定了后面为什么必须拆出第二个方程。
| 特征 | 数据表现 | 对建模的直接含义 |
|---|---|---|
| 尖峰厚尾 | 收益率分布峰度远大于3,尾部概率高于正态 | 正态似然会低估极端风险,需考虑t分布或GED |
| 波动丛聚 | 大幅波动后面跟着大幅波动,小幅波动扎堆 | 条件方差本身要有自回归结构 |
| 杠杆效应 | 同幅度的负冲击比正冲击带来更大波动 | 对称的GARCH(1,1)结构上就刻画不了 |
波动丛聚是最容易验证的一条,把残差平方序列画出来,或者直接看它的自相关图,就能看到明显的衰减拖尾。恩格尔1982年在分析通胀数据时注意到的正是这件事:预测误差的方差取决于后续扰动项的大小,误差的方差里含有可提取的相关性。
2.2 ARCH(q)的构造:把残差平方当成可回归的对象
ARCH模型的全称是自回归条件异方差模型,它的思路不是去预测收益率,而是去预测收益率的方差。把序列写成均值方程加扰动项的形式:
y_t = a0 + a1 * y_{t-1} + e_t e_t = sqrt(h_t) * v_t, v_t ~ iid N(0, 1)关键在于第二步的乘法结构:e_t 被拆成“一个标准化的白噪声”乘上“当期标准差”,方差 h_t 因此可以随时间变化。ARCH(q) 把 h_t 写成过去 q 期残差平方的线性函数:
h_t = a0 + a1 * e_{t-1}^2 + a2 * e_{t-2}^2 + ... + aq * e_{t-q}^2参数含义上,a0 是方差的地板,ai 度量第 i 期冲击对当前波动的影响强度,所有 ai 非负以保证方差不会为负。用一段模拟代码可以直观看到这种“大波动扎堆”是长什么样:
import numpy as np np.random.seed(2024) n = 2000 a0, a1 = 0.4, 0.6 e = np.zeros(n) h = np.zeros(n) h[0] = a0 / (1 - a1) for t in range(1, n): # 当期方差由上一期残差平方决定 h[t] = a0 + a1 * e[t - 1] ** 2 e[t] = np.sqrt(h[t]) * np.random.randn() # 观察残差平方的自相关:前几阶通常显著非零 sq = e ** 2 acf1 = np.corrcoef(sq[1:], sq[:-1])[0, 1] print("残差平方一阶自相关:", round(acf1, 4))这段代码只做了一件事:人为制造一个异方差过程,再回头验证它确实留下了可检测的自相关痕迹。把 a1 调大,波动丛聚会更夸张;调成0,残差平方的自相关就掉到统计上不显著的水平。后面做真实数据时,判断标准是同一套逻辑,只是残差由均值方程估计得到。
2.3 GARCH(1,1):用两个参数吃掉无穷阶ARCH
ARCH(q) 的麻烦在于阶数。金融高频数据的波动记忆很长,要拟合充分往往得取到 q=10 甚至更高,参数一多就难估、容易违反非负约束。Bollerslev 1986年的做法是给条件方差方程再套一层自回归结构,让无穷阶的ARCH被两个参数近似掉:
h_t = w + a1 * e_{t-1}^2 + b1 * h_{t-1}这就是 GARCH(1,1) 的条件方差方程,配合均值方程 y_t = X_t * b + e_t 构成完整模型。三个参数的分工可以用一张表说清:
| 参数 | 名称 | 作用 | 取值范围 |
|---|---|---|---|
| w | 常数项 | 长期方差的地板,等于 (1-a1-b1) 乘无条件方差 | w > 0 |
| a1 | ARCH项系数 | 度量上一期“新息”冲击的即时反应 | a1 ≥ 0 |
| b1 | GARCH项系数 | 度量波动记忆的延续长度 | b1 ≥ 0 |
| a1+b1 | 持久性 | 越接近1,波动冲击衰减越慢 | 必须小于1 |
a1+b1 是建模时第一个要盯的数字。它小于1,模型才是协方差平稳的,无条件方差才等于 w/(1-a1-b1);等于1就是IGARCH,冲击永不衰减;大于1在多数软件里会直接跑到不收敛或者给出无意义的估计。想估算冲击衰减多快,可以用半衰期 ln(0.5)/ln(a1+b1) 换算,比如 a1+b1=0.98 时半衰期大约是34期。
从ARCH到GARCH这一步,本质上是用一个更节约的参数化形式替代长滞后,代价是对冲击衰减形状施加了指数衰减的约束。如果实际数据的波动记忆不是指数衰减,就得考虑后面几章的长记忆或非对称扩展。
3. GARCH类模型的检验与估计:ARCH-LM、残差平方相关图与最大似然
3.1 建模顺序:先均值方程,再残差,最后条件方差
一份能复现的GARCH建模流程,顺序不能乱。常见做法是下面五步:
- 对收益率序列做平稳性检验,确认均值方程里该放几阶滞后;
- 估计均值方程(AR、ARMA或带外生变量的回归),拿到残差 e_t;
- 对 e_t 做ARCH效应检验,确认还有没有东西可建模;
- 加入条件方差方程,用极大似然联合估计均值方程和方差方程的参数;
- 检验标准化残差 z_t = e_t / sqrt(h_t) 是否已经是白噪声,并做分布诊断。
第2步和第3步最容易被跳过。如果均值方程没估干净,残差里混着没提取的自相关,ARCH-LM 会把均值设定错误误判成异方差,最后拟合出一个拟合优度很高但没有任何预测意义的方差方程。
3.2 ARCH-LM检验:辅助回归和两个统计量的读法
ARCH-LM 检验的原假设是残差序列直到 q 阶都不存在ARCH效应,即 a1 = a2 = … = aq = 0。检验方式是把残差平方对自身滞后做辅助回归:
e_t^2 = c0 + c1 * e_{t-1}^2 + ... + cq * e_{t-q}^2 + u_t课件里提到会得到两个统计量,实务中理解它们的区别很重要。F统计量是对所有滞后残差平方项的联合显著性检验,适合小样本;另一个是观测数乘以辅助回归的 R²,渐近服从自由度为 q 的卡方分布。EViews输出的 Obs*R-squared 用的是有效观测数 (T-q) 乘 R²,所以会和课件上写的 T×R² 差一个 lag 的量级,样本量大时无关紧要,样本只有几百个时别混用。
import numpy as np from statsmodels.stats.diagnostic import het_arch # resid 来自上一步均值方程的残差 resid = np.asarray(resid) lm_stat, lm_p, f_stat, f_p = het_arch(resid, nlags=10) print(f"LM统计量={lm_stat:.3f}, p={lm_p:.4f}") print(f"F统计量={f_stat:.3f}, p={f_p:.4f}")nlags是辅助回归的滞后阶数,通常先试10。p值小于0.05就拒绝原假设,说明残差平方里还有可提取的结构,可以继续做GARCH;p值很大则说明ARCH效应不明显,硬上GARCH只会估出一堆不显著的参数。het_arch默认不做自由度修正,和EViews的数字对不上属于正常范围。
3.3 残差平方相关图与Ljung-Box Q
ARCH-LM 给的是联合检验的结论,残差平方相关图给的是结构信息。它显示残差平方序列在指定滞后阶数上的自相关和偏自相关系数,并给出对应阶数的 Ljung-Box Q 统计量。判读规则可以整理成这样:
| 图上现象 | Q统计量 | 结论 |
|---|---|---|
| AC在1~3阶显著,之后快速衰减 | 低阶p值小,高阶p值大 | 短记忆ARCH/GARCH,取q=1~2 |
| AC缓慢拖尾,10阶仍显著 | 所有滞后p值都小 | 波动记忆长,考虑高阶或长记忆模型 |
| AC/PAC全在置信带内 | 各阶p值都大 | 无ARCH效应,不必建方差方程 |
偏自相关在低阶截尾时,可以据此给ARCH项定阶;但GARCH(1,1)的ACF是缓慢衰减的,看图形定阶的意义有限,实践中更常用的是从 GARCH(1,1) 起步,再看更高阶项是否显著、AIC是否下降。
3.4 最大似然估计与分布假设的选择
GARCH类模型基本都走极大似然。给定样本,对数似然函数是各期条件密度之和,以正态假设为例,每一项是 -0.5 * (ln(2π) + ln(h_t) + e_t²/h_t)。因为 h_t 递推依赖前面的参数,目标函数没有解析解,靠数值优化,参数初值和分布假设就变得很敏感。
| 分布假设 | 适用场景 | 代价 |
|---|---|---|
| 正态 | 教学演示、波动幅度小的低频数据 | 严重低估尾部,参数可能被极端值带偏 |
| Student-t | 尖峰厚尾明显的股票收益率 | 多一个自由度参数,样本少时估计不稳 |
| GED | 尾部厚度介于正态与t之间 | 需要额外选择形状参数 |
| 偏t | 收益率分布本身不对称 | 参数最多,优化容易卡在局部极值 |
判断分布选得对不对,最直接的办法是把标准化残差 z_t 拿出来看峰度、做Jarque-Bera检验,再用 QQ 图看尾部。z_t 理论上应该是同方差的白噪声,如果它还有明显的厚尾,说明分布假设太薄,换t分布重估通常会让参数的对数似然明显改善。
4. 用Python复现上证指数GARCH(1,1):从对数收益率到条件方差
4.1 数据准备与收益率缩放
把课件里的上证指数案例搬到代码里,第一步是收益率的口径。价格序列是非平稳的,必须转成对数收益率;更关键的是缩放——原始对数收益率的数量级在1e-3到1e-2之间,直接丢进优化器会触发数值警告甚至不收敛。实务里统一乘以100,把单位换算成百分比。
import pandas as pd import numpy as np from arch import arch_model df = pd.read_csv("sh_index.csv", parse_dates=["date"]).sort_values("date") df["ret"] = 100 * np.log(df["close"]).diff() # 对数收益率,百分比口径 df = df.dropna(subset=["ret"]).reset_index(drop=True) print(df["ret"].describe()) print("峰度:", df["ret"].kurt()) # 远大于3说明厚尾np.log(close).diff()得到连续复利收益率,乘100只是为了数值条件更好,不影响参数显著性,事后解释波动率时记得除回去。峰度这一步是在为后面的分布假设做铺垫:如果算出来是6以上,基本可以放弃正态假设。
4.2 均值方程设定与模型拟合
均值方程不要一上来就堆滞后。先用AR(1)起步,把残差取出来做 ARCH-LM,确认有效应之后再上GARCH。arch包可以直接把均值项和方差项写在一个调用里,mean='AR'配合lags=1表示AR(1)均值方程。
# 第一步:只估均值方程,取残差做ARCH效应检验 from statsmodels.tsa.arima.model import ARIMA ar1 = ARIMA(df["ret"], order=(1, 0, 0)).fit() resid = ar1.resid # 第二步:联合估计AR(1)-GARCH(1,1),残差服从t分布 am = arch_model(df["ret"], mean="AR", lags=1, vol="GARCH", p=1, q=1, dist="t") res = am.fit(disp="off") print(res.summary())dist="t"让新息服从Student-t,disp="off"关掉每轮迭代的输出。res.summary()里要重点看四块:均值方程系数的显著性、omega/alpha[1]/beta[1]、t分布的自由度参数nu、以及对数似然值。alpha[1] 显著说明冲击的即时反应真实存在;beta[1] 显著说明波动记忆长;两个相加接近1说明波动冲击衰减得很慢。
4.3 参数解读与标准化残差诊断
拟合完不能直接拿去用,必须回头验证标准化残差。z_t = e_t / sqrt(h_t) 如果还有结构,说明模型没吃干净。
# 标准化残差 z = res.resid / res.conditional_volatility from statsmodels.stats.diagnostic import het_arch, acorr_ljungbox print("标准化残差ARCH-LM p值:", het_arch(z.dropna(), nlags=10)[1]) print("标准化残差平方Ljung-Box p值:", acorr_ljungbox(z.dropna() ** 2, lags=[10])["lb_pvalue"].values) print("标准化残差峰度:", z.kurt())两个p值都应该大于0.05,峰度应该比原始收益率明显下降、接近t分布的理论水平。如果ARCH-LM仍然显著,说明阶数不够,把 p 或 q 加到2再试;如果峰度还是很高,说明t分布的自由度估计被极端值拉住了,可以考虑GED或者把样本里的极端点单独检查。
4.4 条件波动率提取与常见报错
条件波动率直接用res.conditional_volatility取,注意这是标准差不是方差,量纲是百分比,换算成年化要乘 sqrt(252)。这一步做错是新手最常见的量纲错误,用它去和日收益率画在同一张图上,动辄差两个数量级。
几个高频报错和处理方式:
| 报错/警告 | 原因 | 处理 |
|---|---|---|
| DataScaleWarning | 收益率量纲太小 | 乘100后重估 |
| ConvergenceWarning | 初值差或模型设定过复杂 | 降阶、换分布、多给几组初值 |
| omega为负 | 样本内极端值主导 | 检查缺失值和停牌日,考虑稳健设定 |
| alpha+beta>1 | 波动记忆过强或样本太短 | 检查数据频率,必要时用IGARCH |
停牌、涨跌停和复权处理不干净,是上证指数这类数据最容易出问题的地方。收益率序列里出现一根异常大的跳空,omega 和 alpha 都会跟着走样,动手前先把数据清洗日志留一份。
5. EGARCH、TGARCH与GARCH-M:杠杆效应与风险溢价的建模
5.1 对称结构在什么地方失效
GARCH(1,1) 的条件方差只依赖 e_{t-1} 的平方,正负冲击对波动的影响完全一样。但股票市场里,同等幅度的下跌带来的波动上升通常比上涨更猛,这就是课件里提到的杠杆效应。用 EGARCH 或 TGARCH 的核心动机,就是把“方向”这个信息塞进方差方程。
5.2 EGARCH:对数方差加符号项
EGARCH 把方差方程写到对数尺度上,天然保证方差为正,不需要再对参数施加非负约束:
ln(h_t) = w + b * ln(h_{t-1}) + g * (e_{t-1}/sqrt(h_{t-1})) + a * (|e_{t-1}|/sqrt(h_{t-1}) - E|z|)g 是符号项系数。g 显著为负,说明负冲击推高波动更多,杠杆效应成立;g 不显著则说明数据里没这个特征,用GARCH(1,1)就够了。对数形式还带来一个额外好处:外部冲击对波动的影响是可加的,不会因为当前波动水平高低而被放大或压缩。
5.3 TGARCH的阈值项与GARCH-M的均值方程
TGARCH 走的是另一条路,直接在方差方程里加一个哑变量交乘项:
h_t = w + a * e_{t-1}^2 + g * e_{t-1}^2 * d_{t-1} + b * h_{t-1} d_{t-1} = 1 若 e_{t-1} < 0,否则为 0当 e_{t-1} 为负时,冲击项的系数是 a+g,为正时是 a。g>0 就对应杠杆效应。相比EGARCH,TGARCH的参数更容易解释,但也更难保证方差恒为正。
GARCH-M 则换了个方向,把条件方差搬回均值方程:
y_t = mu + delta * h_t + e_tdelta 是风险溢价系数,delta>0 表示波动越大、要求收益越高,常用来描述风险与收益的跨期关系。三种扩展的适用场景可以对照下面这张表:
| 模型 | 加入的结构 | 主要检验目标 | Python设置 |
|---|---|---|---|
| GARCH(1,1) | 仅残差平方与滞后方差 | 波动丛聚是否显著 | vol="GARCH", p=1, q=1 |
| EGARCH | 对数方差 + 符号项 | 杠杆效应方向 | vol="EGARCH", o=1 |
| TGARCH | 负冲击阈值交乘 | 杠杆效应幅度 | vol="GARCH", o=1, power=1 |
| GARCH-M | 条件方差进均值方程 | 风险溢价是否存在 | mean="AR", 并在均值中指定vol |
5.4 用信息准则做模型选择
同一样本上估多个模型,别只看参数显著性,AIC和BIC更靠谱,因为它们惩罚了参数个数。实操里通常固定均值方程不变,只换方差方程设定,比较对数似然和AIC。
cands = { "GARCH": arch_model(df["ret"], mean="AR", lags=1, vol="GARCH", p=1, q=1, dist="t"), "EGARCH": arch_model(df["ret"], mean="AR", lags=1, vol="EGARCH", p=1, o=1, q=1, dist="t"), "TGARCH": arch_model(df["ret"], mean="AR", lags=1, vol="GARCH", p=1, o=1, q=1, power=1.0, dist="t"), } for name, m in cands.items(): r = m.fit(disp="off") print(f"{name}: LLF={r.loglikelihood:.2f}, AIC={r.aic:.2f}, BIC={r.bic:.2f}")o=1控制非对称项阶数,power=1.0让GARCH族按标准差而非方差建模,这是TGARCH在 arch 包里的常见写法。三个模型的AIC差在2以内时,优先选参数少、解释更直接的那个;差出10以上,说明杠杆效应确实存在,别硬用对称模型。
6. 波动率预测落地:预测步长、滚动回测与几个容易踩的坑
模型估完,真正拉开差距的是预测环节。调用res.forecast(horizon=5, method="analytic")拿到的res.forecast.variance是按期排列的条件方差,注意列名是 h.1 到 h.5,对应未来第1到第5期。多步预测有个容易被忽略的性质:GARCH(1,1) 的预测值会按 (a1+b1)^k 的速度收敛到长期方差 w/(1-a1-b1)。这意味着设 horizon=1 和 horizon=20,早期几期还有差别,越往后越是同一条水平线。所以拿GARCH做中期波动率预测意义有限,它的价值集中在一到五个交易日这个窗口。
评估预测质量别只看均方误差。用滚动窗口做样本外回测更接近真实使用场景:每次用固定长度的历史窗口估参,预测下一期方差,再滚动前移。
window = 1000 preds, actuals = [], [] for i in range(window, len(df) - 1): train = df["ret"].iloc[i - window:i] m = arch_model(train, mean="AR", lags=1, vol="GARCH", p=1, q=1, dist="t").fit(disp="off") # 取未来一期方差预测 preds.append(np.sqrt(m.forecast(horizon=1).variance.values[-1, 0])) actuals.append(df["ret"].iloc[i]) # 用当期收益平方作为代理 preds, actuals = np.array(preds), np.array(actuals) qlike = np.mean(np.log(preds ** 2) + (actuals ** 2) / preds ** 2) print("QLIKE损失:", round(qlike, 4))这段代码里有三个坑。第一,每次都重新拟合,计算量大,可以改成每20期重估一次、中间只做预测,速度能快一个数量级。第二,用当期收益率平方作为事后波动的代理噪声极大,样本少于500期时结论不稳,更稳的做法是用日内高频数据算已实现波动率。第三,QLIKE损失对低估波动率惩罚更重,评估结果要和MSE、Mincer-Zarnowitz回归的R²一起看。
最后是量纲和年化。conditional_volatility是百分比口径的标准差,年化乘 sqrt(252);若要拿去算VaR,记得先转回小数再乘头寸。风控场景里还有一个常见误用:把 GARCH 预测方差直接代入正态VaR公式,而新息分布选的是t,两边口径不一致会导致尾部风险被系统性低估,正确做法是用估计出的自由度参数查t分布分位数。
本文还有配套的精品资源,点击获取