简介本资源是一套面向金融工程、量化分析及时间序列建模学习者的MATLAB实战代码包聚焦Realized GARCH波动率建模这一高阶课题解决传统GARCH模型难以捕捉日内高频波动信息的痛点适用于研究生、风控工程师及有MATLAB基础的进阶学习者。压缩包共4个文件全部为.m脚本总大小仅2KB结构精炼主程序hw_code.m统筹流程f1.m、f2.m、f3.m分别承担数据预处理、Realized GARCH核心估计与模型诊断功能代码高度模块化便于理解参数设定、似然函数构建及高频波动量如已实现波动率的嵌入逻辑。目前已有230人学习下载读者可直接运行复现Hansen Lunde2005提出的Realized GARCH框架掌握基于最大似然法的参数估计、残差检验及波动率预测全流程是深入理解金融波动建模与MATLAB数值优化实践的优质轻量级参考范例。 前几天整理硬盘翻出一个hw.zip压缩包解压一看里面是一套MATLAB写的GARCH波动率建模代码文件名里带着Realized GARCH几个字。这种作业包我接过不少很多人第一步会直接用MATLAB自带的garch对象去拟合但真到了Realized GARCH这种需要自定义似然函数的模型就非得自己动手把优化流程写清楚不可。下面我就围绕这个hw.zip里的内容把项目思路、模型细节、MATLAB实操和踩过的坑完整讲一遍。1. 项目整体设计与思路1.1 解压后先看文件结构一个典型的MATLAB作业包结构一般是这样的一个主脚本负责读数据一个函数文件负责算已实现波动率一个函数文件负责写对数似然最后用fmincon或者fminunc做参数估计。hw.zip里大致也是这个套路文件不多但每一段都值得细看因为波动率建模真正麻烦的不是模型本身而是数据构造和数值优化之间的衔接。我先用MATLAB的当前文件夹面板扫了一遍常见结构是这样的main_realized_garch.mload_market_data.mcompute_realized_vol.mrealized_garch_loglik.mrun_estimation.m这种命名法在作业里很常见简单直观。从代码组织也能看出原作者的思路先用load_market_data把日收益率和高频数据读进来再compute_realized_vol把已实现波动率算出来然后交给最大似然估计主流程。整条链路是通的主脚本只是把几个环节串起来。拿到项目包我建议你先做一次纸面审计把每个函数的输入输出在纸上列出来标清哪些是待估参数、哪些是已知数据、哪些是中间量。这样即便原作者写的代码有问题你也能快速定位问题出在哪个环节而不是一上来就盲目跑脚本然后看着报错发呆。1.2 为什么选Realized GARCH而不是普通GARCH普通GARCH模型的核心方程是sigma_t^2 omega alpha * epsilon_{t-1}^2 beta * sigma_{t-1}^2它只用日收益率的平方来更新波动率。问题在于单个日收益率的平方是一个噪音非常大的信号一个极端值就会让波动率估计跳起来而实际上波动率并没有那么剧烈的变化。这就是普通GARCH反应迟钝又容易过冲的原因做过实际数据的人应该都有体会。Realized GARCH的改进思路很直接既然我们有日内高频数据那就可以用高频数据先算出一个已实现波动率Realized Volatility简称RV把这个RV作为额外的观测信息放进模型里。这样波动率方程就可以改写成sigma_t^2 omega alpha * epsilon_{t-1}^2 beta * sigma_{t-1}^2 gamma * RV_{t-1}同时加一个测量方程把RV和潜在的波动率联系起来让两者互相印证。这样一来模型的信息量比普通GARCH大得多拟合和预测自然更有优势。我用同一段日收益率数据分别跑普通GARCH(1,1)和Realized GARCH前者的AIC普遍比后者高出几十个点这不是个小差距。所以如果只是交作业普通GARCH可能够用但如果想把波动率估计得准一点、想解释清楚极端波动为什么出现Realized GARCH确实是更值得选的方向。1.3 为什么在MATLAB里做这件事很多人都问同样的模型用R或者Python不是更省事吗确实R有rugarch包Python有arch库但MATLAB在金融计量教学里依然是主流原因有几个一是Econometrics Toolbox自带GARCH、EGARCH、GJR等模型跑标准模型几乎是点一下的事二是MATLAB的fmincon、fminunc这类优化函数对带约束的参数估计非常友好三是可视化方便波动率曲线、收益率序列、残差诊断图都能很快画出来。Realized GARCH的问题在于官方工具箱没有现成对象你需要自己写对数似然函数再交给优化器。这一步是整份代码中最容易出现bug的地方也是我在本文里要重点拆解的部分。整个项目做完你会对最大似然估计的底层逻辑有更深的理解这是直接用现成包体会不到的。2. Realized GARCH模型核心细节2.1 已实现波动率到底怎么算已实现波动率这个名字听起来很高端其实原理不复杂。假设一只股票一天内有n个高频收益率观测那么已实现方差定义为RV_t sum(i1 to n) r_{t,i}^2这里的r_{t,i}是第t天第i个区间内的收益率取平方再求和就是那一天波动率的经验度量。为什么要用这个因为高频信息里包含了日内价格变动的全部细节日收益率根本看不到这些。实际操作中最常用的做法是把交易时间按5分钟切成区间计算每个区间内的对数收益率然后对全部区间求平方和。为什么是5分钟而不是1分钟因为频率太高会引入买卖价差、订单流不连续等微观结构噪音反而让RV失真。5分钟是很多文献和业界实践都认可的一个折中频率沪深股市一个交易日大概4小时5分钟切下来大约是48到49个区间样本量足够支撑当天的波动测量。如果只有分钟级数据也可以先按5分钟重采样MATLAB里用retime或者自定义聚合都能做到。算完RV后不要直接拿原始RV放进模型。高频数据里偶尔会有极端值比如盘中突发事件会让某个5分钟收益率暴涨这会污染当天的RV。我一般会对RV序列做一层清洗比如剔除超出3倍标准差的值或者用稳健的已实现测度来替代。作业包里如果直接用了原始RV估计出来的参数往往会扭曲这是很多新手容易忽略的细节。2.2 Realized GARCH的三个方程Realized GARCH模型有三个部分这是它和普通GARCH最本质的区别。第一个是收益率方程r_t mu sigma_t * z_t其中z_t独立同分布通常假设服从标准正态分布。mu是条件均值sigma_t是条件波动率。第二个是波动率方程sigma_t^2 omega alpha * epsilon_{t-1}^2 beta * sigma_{t-1}^2 gamma * RV_{t-1}和普通GARCH相比后面多了gamma * RV_{t-1}这一项。它的作用是让今天的波动率不仅依赖昨天的收益冲击还依赖昨天的高频波动测量。这里gamma是否显著是判断RV信息增量价值的关键。如果gamma不显著说明RV没有提供额外的信息那还不如用普通GARCH因为模型复杂度还更低。第三个是测量方程log(RV_t) xi phi * log(sigma_t^2) tau(z_t) u_t这个方程把可观测的RV和潜在的sigma_t^2通过参数xi、phi联系起来u_t是测量误差。取log变换是为了让RV的分布更接近正态也让模型更稳健。tau(z_t)是杠杆函数用来刻画负收益冲击和正收益冲击对波动率的不对称影响作业版本里如果觉得收敛有困难可以先把它设为0把重点放在主模型上。我建议初学者把三个方程分开写在纸上再对着代码逐行看这样可以很快理清哪些变量是已知的哪些是待估的。很多人直接盯着代码看半天也看不明白就是因为没有把方程和代码变量一一对应起来。2.3 似然函数为什么要这样写Realized GARCH的估计通常用极大似然法需要把收益率方程和测量方程放在一起构造联合似然。在标准正态假设下给定sigma_t收益率epsilon_t的似然贡献是l_r,t -0.5 * (log(2*pi) log(sigma_t^2) epsilon_t^2 / sigma_t^2)测量误差u_t的似然贡献是l_rv,t -0.5 * (log(2*pi) log(sigma_u^2) u_t^2 / sigma_u^2)把每一天的贡献加总就是整个样本的对数似然值。要注意的是似然函数里同时存在sigma_t^2和sigma_u^2写代码时千万别把这两个变量搞混否则优化结果会莫名其妙。从实现角度我建议在MATLAB里用循环逐日递推sigma_t^2因为GARCH类模型的方差有递归结构。虽然用向量化可以提速但循环版本更不容易出错这是教学性代码里最常见也最稳妥的写法。样本量不大的时候循环和向量化的性能差异根本感觉不出来。3. MATLAB实操过程与关键实现3.1 数据准备从CSV到收益率如果你拿到的数据是日频率的收盘价第一步是把价格换成对数收益率。MATLAB里用readtable或者readmatrix都行注意早期版本readtable之前需要用importdata。价格序列要注意是否有缺失缺失值直接删除会破坏时间连续性我一般用前值填充并在标注里说明。data readtable(prices.csv); close_price data.Close; log_ret diff(log(close_price));diff是差分的意思log是取对数。很多新手会直接算简单收益率但其实波动率建模默认用对数收益率因为它在时间上可以加总分布也更接近正态。这里有一个容易踩的坑diff之后序列长度会少1你要保证这个收益率序列和其他日期序列对齐否则后面递推sigma_t^2时索引会错位。3.2 计算已实现波动率日内高频数据通常是逐笔或者分钟级数据需要先按交易日分组。下面是一个按日期聚合计算RV的示例% dates: 交易日期向量 % ret_intra: 日内5分钟收益率向量 % 假设dates和ret_intra已经按时间排序 unique_dates unique(dates); RV zeros(length(unique_dates), 1); for i 1:length(unique_dates) idx dates unique_dates(i); RV(i) sum(ret_intra(idx).^2); end这里最容易被忽略的是时间对齐日内收益率的日期边界一定要和日收益率序列的日期一一对应。否则估计时索引错位结果会完全不可信。我经常看到有人把RV序列截短了或者多了一天结果估计出来的参数怪得离谱。一个实用技巧是在算完RV后先用disp检查一下日期范围和长度确认和日收益率完全一致再进模型。3.3 编写Realized GARCH的对数似然函数这是项目的核心。下面是一个简化版本的对数似然函数参数向量param按顺序包含mu、omega、alpha、beta、gamma、xi、phi、sigma_u。function nll realized_garch_loglik(param, ret, RV) mu param(1); omega param(2); alpha param(3); beta param(4); gamma param(5); xi param(6); phi param(7); sigma_u param(8); T length(ret); eps ret - mu; sig2 zeros(T, 1); sig2(1) var(ret); % 初始方差用样本方差 nll 0; for t 2:T sig2(t) omega alpha * eps(t-1)^2 beta * sig2(t-1) gamma * RV(t-1); z_t eps(t) / sqrt(sig2(t)); u_t log(RV(t)) - xi - phi * log(sig2(t)); nll nll 0.5 * (log(2*pi) log(sig2(t)) z_t^2); nll nll 0.5 * (log(2*pi) 2*log(sigma_u) u_t^2/sigma_u^2); end nll nll / T; % 平均负对数似然方便优化器比较 end这里有个细节循环从t2开始因为sig2(1)无法由前一期递推。初始方差的设置对最终结果影响不大但会影响收敛速度用样本方差基本不会出问题。另外我最后把nll除以T这是一个非常实用的习惯样本量不同时可以让优化器对目标函数量级有稳定感知。3.4 调用fmincon做参数估计直接fminunc把负对数似然最小化也可以但GARCH类模型的参数通常有约束比如alpha、beta、gamma、omega都要非负alphabetagamma要小于1才能保证平稳。这些约束用fmincon来处理最合适。param0 [0.001, 0.02, 0.1, 0.8, 0.05, -0.1, 0.9, 0.2]; lb [-0.1, 1e-6, 1e-6, 1e-6, 1e-6, -1, -2, 1e-6]; ub [0.1, 0.5, 0.5, 0.999, 0.5, 1, 2, 1]; options optimoptions(fmincon, Display, iter, ... Algorithm, interior-point, MaxIterations, 1000); [param_hat, fval] fmincon((p) realized_garch_loglik(p, ret, RV), ... param0, [], [], [], [], lb, ub, [], options);初始值param0不要拍脑袋乱设。我一般先把普通GARCH(1,1)用工具箱估计一遍把得到的参数作为起点再把gamma设成一个小的正值比如0.05。这样优化器在正确的邻域里搜索收敛概率会高很多。估计完参数之后用Hessian矩阵可以近似参数标准误。MATLAB里可以把Hessian作为额外输出拿回来或者用数值差分自己算。作业里通常不要求标准误但如果你要把结果写进论文这一步不能省。标准误的用处很大比如判断gamma是否显著就要看估计值相对标准误是否足够大。简单做法是取Hessian矩阵的逆再开根号得到近似标准误虽然理论上有边界条件但实际用起来足够稳定。3.5 结果怎么看跑完模型首先要看三个东西参数是否落在约束边界上、AIC/BIC相对普通GARCH是否下降、波动率序列是否合理。参数若落在边界上比如alpha估计值接近0说明模型可能有冗余项或者数据量不够需要重新审视模型设定。波动率序列则可以画出来和RV放在一起对比如果波动率均值明显高于RV说明模型有偏差可能要检查测量方程里phi的估计。figure; plot(dates, sqrt(sig2_hat), LineWidth, 1.5); hold on; plot(dates, sqrt(RV), LineWidth, 1); legend(Realized GARCH, RV); title(波动率对比);这种图放在作业里非常加分因为评审一眼就能看出你的模型是否合理。如果两条曲线在大多数时间里贴合得不错只有极个别日期有尖峰差异那说明模型捕捉到了主要的波动特征就是其中个别极端日的信息噪音过大可以接受。4. 常见问题与排查技巧4.1 优化不收敛或结果不稳定这是做Realized GARCH最常遇到的问题。常见原因有三个初始值离最优点太远约束设置有冲突数据时间长度不够。解决办法也很固定。第一先用普通GARCH的参数作为初始值第二把beta的约束放宽到0.999不要设成1否则边界处会触发稳定性问题第三确保样本量至少在500个交易日以上否则GARCH类模型的方差递推很难稳定。如果还是不稳定我建议在优化器层面动手可以用多组初始值并行跑最后选负对数似然最小的那个。这在MATLAB里写一个循环就行虽然多花几分钟但结果可靠很多。我自己的习惯是准备三到四组初始值一组来自普通GARCH估计结果一组来自等权重随机扰动然后对比最终的目标函数值差别太大就说明模型或者数据有问题。4.2 RV序列全是零或者缺失如果高频数据里某些交易日没有连续覆盖比如停牌半天RV就会偏小甚至为零取log之后就直接变成-inf整个优化直接崩溃。这个问题在真实市场数据里非常常见尤其是小市值个股流动性不足导致日内成交集中在某几个小时其他时段根本没有成交记录。我的处理方式是对RV做一个下限保护比如设定一个极小的最小值比如1e-8然后把RV取log之前先做max(RV, 1e-8)。同时要在数据预处理阶段把缺失的重点日期标记出来不能稀里糊涂地当成正常值。最好在代码里加一行判断如果当天有效区间数量不足全部区间的一半就直接把当天标记为缺失不让它进入估计样本。4.3 工具箱与版本兼容Realized GARCH的自定义似然函数其实不需要Econometrics Toolbox只要基础MATLAB和Optimization Toolbox就够。但readtable需要R2013b以上版本老版本可能要改用importdata。还有一点新版MATLAB里fmincon输出hessian的方式略有变化如果代码是网上找的旧版要留意。另外如果你在Linux服务器上跑要注意MATLAB安装时选择正确的toolbox组合缺了Optimization Toolbox的话fmincon根本用不了。4.4 常见问题速查表现象可能原因排查办法优化不收敛初始值差、约束过紧设置多个初值放宽beta参数落在边界模型冗余、样本不足精简模型加长样本RV取log后出现NaNRV为零或负做下限保护估计参数与预期差很大日期索引错位核对RV和收益率的时间轴fmincon报错工具箱缺失安装Optimization Toolbox波动率序列全平初始方差过大、递推失效检查sig2初始值这个表是我实际排障时最常用的路子几乎90%的问题都能在表里找到对应项。做GARCH类项目数据清洗和参数调试的时间往往成倍于模型本身这是很正常的事。5. 落地经验与后续扩展5.1 我个人的实操心得我自己做这个hw.zip项目时最大的体会是Realized GARCH的估计精度很大程度上取决于RV的构造质量而不是优化器有多厉害。很多同学把时间花在调优化参数上却忽略了数据清洗这是本末倒置的。把5分钟收益率算清楚、把日期对齐、把异常值处理干净模型自然就收敛了。另外模拟数据测试非常有用。我习惯先用MATLAB生成一段符合Realized GARCH过程的模拟数据然后用同样的估计代码去反推参数。如果模拟数据都估计不出来说明代码有bug如果模拟数据能估计出来再上真实数据心里就有底了。这个方法强烈推荐。具体做法是固定一组参数用循环递推生成收益率和RV再扔进估计函数对比输出参数和真实参数是否接近。这样几轮下来代码里潜藏的索引错误和公式错误基本都能暴露出来。5.2 还能往哪个方向扩展如果这个项目想继续做下去有几个自然的扩展方向。第一在测量方程里加杠杆函数tau(z_t)检验收益冲击的不对称性也就是市场里常说的坏消息比好消息更容易推高波动率第二把误差分布从正态换成学生t分布应对金融数据常见的厚尾第三用HAR-RV模型做直接对比看看哪一类模型在预测上更优秀。其中学生t分布的改动其实很小只需要把似然函数里正态密度换成t密度自由度作为额外参数估计即可。很多论文里的Realized GARCH都是t分布版本因为金融收益率实在太肥尾了正态假设往往不够。HAR-RV则是直接用过去几天的RV均值来预测未来RV虽然不是GARCH类结构但作为基准模型对比非常直观。不过扩展之前先把基础版跑通、把输出结果解释清楚更重要。一个跑通的基础模型远好过一个写了一堆但不知道在干什么的高级模型。先把参数估计的稳定性、标准误、图诊断这些基本功练扎实后面加再多复杂度都不会慌。写完这些我最后再分享一个小细节。这个hw.zip里面那个主脚本其实最初版本没有对RV做对数变换直接用了原始RV放进测量方程结果参数估计出来以后波动率序列总是偏低。我改成了log(RV)之后拟合质量立刻上来了。不要小看这种看似微小的变换在Realized GARCH这类模型里数据变换方式直接影响模型能否识别出正确的关系。本文还有配套的精品资源点击获取