MATLAB实现基于UKF-GARCH 无迹卡尔曼滤波(UKF)结合广义自回归条件异方差(GARCH)进行股票价格预测的详细项目实例
请注意此篇内容只是一个项目介绍 更多详细内容可直接联系博主本人
或者访问对应标题的完整博客或者文档下载页面(含完整的程序,GUI设计和代码详解)
股票价格预测长期以来都是金融工程、量化投资、风险管理与资产配置中的核心任务。股票市场具有高噪声、高波动、强非线性、厚尾分布、结构突变频繁等典型特征,价格序列不仅受宏观经济、行业景气、政策预期、市场情绪、资金流动等多重因素影响,还会随着市场交易制度、流动性环境和投资者行为的变化而呈现显著的时变性。传统的线性时间序列模型,例如简单移动平均、ARIMA、指数平滑等,在平稳性较强、扰动较弱的场景中能够发挥一定作用,但面对真实股票市场时,往往难以同时刻画趋势演化与波动聚集现象,预测结果容易出现滞后、过度平滑或对极端波动反应不足的问题。
广义自回归条件异方差模型能够专门描述金融收益率序列中常见的波动聚集现象,即大波动往往伴随大波动,小波动往往伴随小波动。该类模型在金融时间序列分析中具有非常高的使用价值,尤其适用于收益率而非原始价格的波动刻画。GARCH 模型通过历史残差与历史条件方差共同递推当前波动水平,因而能够反映风险随时间变化的动态结构。对于股票市场而言,这种动态方差结构具有现实意义,因为投资决策通常不仅关心价格趋势,也非常关心未来波动水平、回撤风险与不确定性范围。
无迹卡尔曼滤波是一种适用于非线性状态空间系统的递推估计方法。它通过一组精心设计的确定性采样点传播均值和协方差,而非依赖泰勒展开,因此比扩展卡尔曼滤波更适合非线性强、可导性较差或非线性形式复杂的系统。股票价格预测本质上是一个动态状态估计问题,价格本身可以看作隐状态,观测值是带噪声的市场成交价格或复权收盘价。若将价格演化、收益率演化与波动方差变化统一纳入状态空间框架,UKF 能够在观测噪声存在、模型不完全精确的情况下,对未来状态进行递推估计,并实现对短期价格路径的平滑跟踪与预测修正。
将 UKF 与 GARCH 结合,能够形成一种兼具趋势估计能力与波动建模能力的复合预测框架。UKF 负责对价格状态进行非线性滤波与动态更新,GARCH 负责对收益波动进行条件方差估计,并将这种方差信息反馈到状态噪声协方差中,使滤波器能够根据市场波动水平自动调整“信任程度”。当市场剧烈波动时,模型会提高过程噪声或观测噪声的动态权重,避免过度依赖历史路径;当市场较平稳时,模型则会增强对趋势的跟踪能力,减少噪声干扰。这样一来,价格预测不再只是对点值的机械外推,而是兼顾了风险结构、动态不确定性和非线性状态演化。
从工程实现角度来看,这类项目具有很强的综合性。首先需要完成股票历史数据获取、缺失值处理、复权处理、收益率构造与标准化等数据准备工作;随后建立 GARCH 波动率估计模块,并将其输出嵌入 UKF 的过程噪声或状态扩展项;再进一步构建非线性状态空间模型,设计状态转移函数与观测函数;最后进行参数初始化、迭代估计、结果评估以及可视化展示。整个流程跨越金融建模、统计学习、状态估计与数值计算多个方向,既能体现理论深度,也能体现 MATLAB 在数值仿真与金融算法实现方面的强大能力。
在实际应用中,单纯追求“价格数值尽可能准确”并不是唯一目标。更重要的是在不同市场环境下保持稳健性,能够识别波动上升阶段、减少错误交易信号、改善风险调整后收益表现。因此,UKF-GARCH 框架特别适合用于短中期股票价格预测、波动预警、动态仓位控制、止损阈值自适应调整以及组合风险分配等任务。对于量化研究而言,它还具有良好的可扩展性,可以进一步引入成交量、技术指标、宏观变量或多资产联动信息,形成更复杂的多维状态空间系统。该项目不仅是一个股票预测实例,更是一个将波动建模、非线性滤波与金融工程实践紧密结合的综合性建模范例。
项目目标与意义
一、提升股票价格短期预测的动态适应能力
该项目的核心目标之一,是构建一个能够随市场状态变化而自适应调整的短期股票价格预测框架。股票价格在现实市场中并不满足稳定、平滑、单一机制驱动的理想条件,而是会受到突发消息、交易情绪、资金集中流入流出以及宏观环境变化的影响,导致趋势与波动同时改变。普通回归模型常常只能处理静态映射关系,面对时变噪声时容易失效。UKF-GARCH 的组合方法可以在每个时间步中利用最新观测更新状态,并依据 GARCH 输出的条件方差动态调整估计强度,使预测值更贴合真实市场环境。该目标的意义在于提升模型对短线波动、冲击事件与趋势切换的响应速度,减少滞后估计,让预测系统具备更好的时变适应性和工程可用性。
二、同时刻画价格走势与波动风险
第二个目标是让模型不仅预测价格方向,还能同步反映未来风险水平。金融时间序列分析中,单独预测价格往往不够,因为高收益往往伴随着高风险,低波动阶段与高波动阶段对应的建模策略应当不同。GARCH 模块能够专门估计条件方差,从而揭示收益率序列的波动聚集特征;UKF 则在状态估计过程中把这种波动信息纳入协方差传播过程,形成统一的动态估计机制。该设计的意义在于将“收益预测”与“风险识别”整合为一个框架,避免只看点预测而忽视不确定性,从而为交易决策、止损设置、仓位调整和风险预警提供更可靠的量化依据。
三、增强模型在非线性和噪声环境中的稳健性
股票市场中的观测噪声、非线性传导与误差累积会显著影响预测质量。若使用线性滤波或线性回归,容易产生系统性偏差。UKF 相比传统线性估计方法具有更强的非线性处理能力,它通过 sigma 点传播均值和协方差,不依赖复杂的导数展开,因此对复杂状态转移关系更稳定。结合 GARCH 后,模型还能针对波动异常自动增加状态不确定度,降低在极端行情下的过拟合风险。该目标的意义在于构建一个对噪声更敏感、对结构变化更稳健的预测系统,使模型在震荡市、单边市和高波动市中都能保持相对一致的表现,提升实盘部署价值。
四、为量化交易与风险管理提供可扩展基础
该项目并非停留在学术演示层面,而是面向实际量化应用构建基础框架。通过 UKF-GARCH 生成的预测结果,可以进一步用于信号生成、组合权重调整、波动率目标控制、动态对冲与尾部风险管理。项目的意义还体现在良好的扩展性上:可继续接入成交量、市场指数、行业因子、财务指标和情绪指标,形成多源融合状态空间模型;也可进一步改造成多资产协同预测系统,用于更复杂的资产配置与风险分散问题。该目标的价值在于把一个单一预测模型,扩展为可服务于交易、风控、研究和决策支持的综合性分析工具。
项目挑战及解决方案
一、股票序列非平稳、噪声强、波动聚集显著
股票价格序列通常不满足平稳性要求,直接在价格水平上建模容易受到趋势漂移和量纲累积的影响。与此同时,市场噪声具有随机性强、突发性高、厚尾明显等特征,导致短时间内预测误差可能迅速扩大。更复杂的是,波动聚集现象使得风险状态具有明显的时间相关性,高波动阶段往往连续出现,这使得固定参数模型很难在全周期中保持稳定表现。针对这一问题,解决方案是将原始价格转化为收益率或对数收益率进行波动建模,同时在状态空间中保留价格水平信息,再利用 GARCH 对条件方差进行递推估计。这样既能减少非平稳带来的干扰,又能保留趋势信息与风险信息,使模型对不同市场阶段都有更高的适应性。
二、非线性状态转移与参数耦合带来的估计难度
UKF-GARCH 框架中的状态转移函数并非简单线性关系,价格、收益率和波动方差之间存在复杂的耦合关系。若状态转移设计不合理,可能出现协方差发散、滤波不收敛或参数漂移的问题;若 GARCH 参数与滤波参数之间缺乏协同,也会造成波动估计失真。对此,解决方案是采用分层建模思路:先利用历史收益率估计 GARCH 参数,得到稳定的波动递推结构,再把条件方差作为状态噪声的动态来源或协方差信息输入 UKF;同时在状态初始化阶段设置合理的初始均值和协方差,并在递推中引入平滑约束与边界保护,避免数值不稳定。通过这种方式,可以降低参数耦合导致的不确定性,提高模型的可收敛性和可解释性。
三、实际实现中数值稳定性与版本兼容问题复杂
MATLAB 在不同版本中对函数接口、绘图属性、机器学习接口和状态空间计算方式存在差异,尤其在新版本中,一些属性已被移除或改名,某些函数参数的兼容性也有所变化。对于一个综合性项目而言,如果实现不充分考虑版本约束,就可能在运行时出现参数无效、图表对象冲突、优化器报错或矩阵维度异常等问题。对应的解决方案是采用兼容性更高的基础函数和标准数值流程,避免依赖过于激进的高级封装接口;在数据标准化、协方差更新、权重计算和图形显示方面使用明确、稳定的写法;在绘图时使用 figure 与 axes 的标准方式管理图像对象。这样可显著降低版本差异带来的故障概率,使项目代码更适合长期维护与复现。
项目模型架构
一、数据输入与预处理层
模型架构的第一层是数据输入与预处理层,负责将原始股票历史数据转换为可用于状态估计的标准化序列。原始数据通常包含日期、开盘价、最高价、最低价、收盘价、成交量等字段,其中收盘价最常用于短期价格建模。预处理环节需要先完成缺失值剔除、异常点检查、时间排序与复权处理,再计算对数收益率或简单收益率,以减轻价格非平稳性带来的影响。该层的基本原理是把原始行情映射为更适合时间序列分析的统计量,使后续模型聚焦于变化率而非绝对量级。若再进一步引入移动平均、波动率、交易量变化率等辅助特征,还可增强模型对局部市场状态的识别能力。该层的作用不仅在于清洗数据,更在于为 GARCH 和 UKF 提供结构清晰、尺度统一的输入。
二、GARCH 波动建模层
第二层是 GARCH 波动建模层,其作用是刻画收益率序列中的条件异方差结构。GARCH 模型认为当前波动并非固定不变,而是由历史残差平方和历史条件方差共同驱动。以常见的 GARCH(1,1) 为例,当前条件方差由常数项、上一期残差平方和上一期条件方差线性递推得到,这种结构能够很好描述金融市场中典型的波动聚集现象。该层的基本原理是通过时变方差估计,捕捉市场风险状态的延续性与放大效应,并将估计得到的条件方差传递给后续滤波模块。它的价值不仅体现在预测波动本身,也体现在动态调整状态估计过程中的协方差,帮助 UKF 在高波动环境下自动提高不确定度,降低过度自信带来的偏差。
三、UKF 状态估计层
第三层是 UKF 状态估计层,也是整个系统的核心。UKF 用于处理非线性状态空间模型中的递推估计问题,其核心思想是通过 sigma 点对状态分布进行近似采样,再将这些点传播到非线性函数中,最后重新计算预测均值与协方差。相比扩展卡尔曼滤波需要显式求导,UKF 更适合非线性函数复杂、模型形式不易线性化的场景。该层的基本原理是将价格状态、趋势状态或隐含收益状态纳入一个向量形式的状态变量,通过状态转移函数描述其演化,再依据观测函数把状态映射为实际可见价格。结合 GARCH 输出的条件方差后,UKF 能够动态调节过程噪声和估计置信区间,从而在噪声环境中保持较强的收敛能力和跟踪能力。
四、预测输出与性能评估层
第四层是预测输出与性能评估层,负责把状态估计结果转换为未来价格预测值,并用标准指标衡量模型表现。输出结果通常包括未来一步或多步的价格预测、对应收益率预测以及波动率预测。评价指标可以包括均方误差、平均绝对误差、方向准确率、拟合图形、残差分布以及波动跟踪效果。该层的基本原理是从数值误差、趋势一致性和风险识别三个角度检验模型质量。只看误差均值并不能全面说明模型有效性,因此还应观察在高波动区间内的表现是否稳定,预测曲线是否存在明显滞后,残差是否接近零均值等。该层将模型从“能运行”提升到“可评价、可比较、可优化”的工程阶段。
五、可视化与决策支持层
第五层是可视化与决策支持层,用于把复杂的模型输出转换为可理解的图形与表格信息。常见展示包括真实价格与预测价格对比曲线、收益率与条件波动率曲线、残差分析图以及不同模型之间的性能比较图。该层的基本原理不是单纯美化图像,而是帮助研究人员判断模型在哪些区间表现良好、在哪些区间存在偏差、波动拐点是否被及时捕捉。对于实务应用而言,该层还可以进一步转化为交易辅助信号,例如当预测收益率上升且条件波动率稳定时提示增强持仓,当波动率骤增时提示收缩风险暴露。通过这一层,整个 UKF-GARCH 系统从纯算法模型转化为能服务于策略研判和风控决策的分析工具。
项目模型描述及代码示例
一、读取股票数据并构造收益率序列 T = readtable('stock_data.csv'); % 读取股票历史数据表,便于后续按列提取收盘价与日期信息 T = rmmissing(T); % 删除含有缺失值的行,避免后续对数运算与滤波递推出现数值异常 closePrice = T.Close; % 提取收盘价序列,作为价格状态建模的核心输入 dateVec = T.Date; % 提取日期列,便于后续绘制时间轴与结果对齐 logRet = diff(log(closePrice)); % 计算对数收益率,减弱价格非平稳性并突出动态变化特征 logRet = logRet(:); % 将收益率整理为列向量,保证 GARCH 与状态空间运算的维度一致 priceObs = closePrice(2:end); % 与收益率对应的观测价格序列,长度比原始收盘价少 1 n = numel(logRet); % 统计样本长度,作为滤波循环与参数初始化的基础 二、估计 GARCH 波动并生成条件方差 garchMdl = garch(1,1); % 构造 GARCH(1,1) 模型,用于刻画金融收益率的波动聚集特征 EstMdl = estimate(garchMdl, logRet, 'Display', 'off'); % 根据历史收益率估计 GARCH 参数,关闭迭代显示以减少干扰 v = infer(EstMdl, logRet); % 推断每一期条件方差,作为动态波动水平的估计结果 v = max(v, 1e-8); % 对条件方差进行下界约束,避免后续开方与协方差传播出现零值问题 sigma2 = v; % 将条件方差保存为统一变量,便于 UKF 中调用并构建时变噪声 sigma = sqrt(sigma2); % 计算条件标准差,便于观察波动大小及构造更直观的风险刻画指标 三、建立 UKF 状态向量与初始参数 x0 = [priceObs(1); logRet(1)]; % 设置初始状态,第一维表示价格水平,第二维表示收益变化率 P0 = diag([1, 1]); % 设置初始协方差矩阵,表示对初值的不确定性分布 Qbase = diag([0.05, 0.02]); % 设置基础过程噪声,用于描述状态演化中的随机扰动 Rbase = 0.5; % 设置基础观测噪声强度,用于描述价格观测中的测量误差 alpha = 1e-3; % UKF 的缩放参数,用于控制 sigma 点分布范围 beta = 2; % UKF 的先验分布修正参数,常用于高斯分布场景 kappa = 0; % UKF 的附加缩放参数,用于协同调整 sigma 点权重 L = numel(x0); % 计算状态维度,用于生成 sigma 点与权重向量 lambda = alpha^2 * (L + kappa) - L; % 计算 UT 变换缩放系数,决定 sigma 点扩展尺度 Wm = [lambda/(L+lambda), repmat(1/(2*(L+lambda)), 1, 2*L)]; % 构造均值权重,用于恢复预测均值 Wc = Wm; % 初始化协方差权重,与均值权重保持一致 Wc(1) = Wc(1) + (1 - alpha^2 + beta); % 对第一个 sigma 点协方差权重进行修正,提高二阶精度 四、UKF 递推预测与更新 xPred = zeros(2, n); % 预分配状态预测矩阵,提升运行效率 yPred = zeros(n, 1); % 预分配观测预测向量,保存每一步的价格预测值 P = P0; % 将初始协方差赋给当前协方差变量,作为滤波递推起点 x = x0; % 将初始状态赋给当前状态变量,作为滤波循环起点 for k = 1:n % 逐期执行 UKF 递推,遍历全部收益率样本 Qk = Qbase * (1 + sigma2(k)); % 依据 GARCH 条件方差动态调整过程噪声,使高波动阶段具有更大不确定度 Rk = Rbase * (1 + 0.5 * sigma2(k)); % 依据条件方差动态调整观测噪声,反映市场噪声随波动变化的特征 S = chol((L + lambda) * (P + Qk), 'lower'); % 通过 Cholesky 分解生成 sigma 点扩展方向,确保数值稳定性 Xsigma = [x, x + S, x - S]; % 构造 sigma 点集合,作为非线性传播的输入样本 Xpred = zeros(size(Xsigma)); % 预分配预测 sigma 点矩阵,用于保存状态转移后的结果 for i = 1:size(Xsigma, 2) % 遍历每个 sigma 点,执行状态转移 curX = Xsigma(:, i); % 取出当前 sigma 点状态 nextPrice = curX(1) * exp(curX(2)); % 用价格与收益状态构造非线性价格演化关系 nextRet = 0.7 * curX(2) + 0.3 * logRet(max(k,1)); % 用平滑递推方式更新收益状态,增强时序连续性 Xpred(:, i) = [nextPrice; nextRet]; % 保存状态转移后的 sigma 点结果 end xPred_k = Xpred * Wm'; % 利用均值权重恢复预测状态均值 PPred = zeros(L, L); % 初始化预测协方差矩阵 for i = 1:size(Xpred, 2) % 累加每个 sigma 点对协方差的贡献 dx = Xpred(:, i) - xPred_k; % 计算 sigma 点偏差 PPred = PPred + Wc(i) * (dx * dx'); % 根据协方差权重更新预测协方差 end PPred = PPred + Qk; % 加入过程噪声,得到完整的先验协方差 Ysigma = Xpred(1, :); % 观测函数只取价格维度,构造预测观测 sigma 点 yPred_k = Ysigma * Wm'; % 恢复观测预测值 Py = 0; % 初始化观测协方差 Pxy = zeros(L, 1); % 初始化状态与观测之间的互协方差 for i = 1:size(Xpred, 2) % 遍历每个 sigma 点,构建观测相关统计量 dy = Ysigma(i) - yPred_k; % 计算观测偏差 dx = Xpred(:, i) - xPred_k; % 计算状态偏差 Py = Py + Wc(i) * (dy * dy'); % 更新观测协方差 Pxy = Pxy + Wc(i) * dx * dy; % 更新互协方差 end Py = Py + Rk; % 加入观测噪声,得到最终观测协方差 K = Pxy / Py; % 计算卡尔曼增益,决定状态修正幅度 innov = priceObs(k) - yPred_k; % 计算观测残差,衡量预测与实际的偏差 x = xPred_k + K * innov; % 利用创新项修正状态估计值 P = PPred - K * Py * K'; % 更新后验协方差,降低已观测信息的不确定性 xPred(:, k) = x; % 保存当前时刻更新后的状态估计 yPred(k) = x(1); % 保存当前时刻的价格预测值 end % UKF 递推结束,得到全部时刻的预测结果 五、计算误差指标并进行结果评估 rmse = sqrt(mean((priceObs - yPred).^2)); % 计算均方根误差,反映整体预测偏差幅度 mae = mean(abs(priceObs - yPred)); % 计算平均绝对误差,反映预测偏离的平均水平 mape = mean(abs((priceObs - yPred) ./ max(priceObs, eps))) * 100; % 计算平均绝对百分比误差,便于跨价格水平比较 directionAcc = mean(sign(diff([priceObs(1); priceObs])) == sign(diff([yPred(1); yPred]))); % 统计涨跌方向一致率,衡量趋势预测能力 residual = priceObs - yPred; % 计算残差序列,作为误差分布分析基础 fprintf('RMSE = %.6f\n', rmse); % 输出 RMSE,便于快速检查模型数值表现 fprintf('MAE = %.6f\n', mae); % 输出 MAE,便于观察平均偏差 fprintf('MAPE = %.4f%%\n', mape); % 输出 MAPE,便于检查相对误差大小 fprintf('Direction Accuracy = %.4f\n', directionAcc); % 输出方向准确率,便于评估趋势捕捉能力 六、绘制预测结果与波动曲线 fig1 = figure('Color', 'w'); % 创建白底图窗,便于展示价格预测曲线 plot(priceObs, 'k', 'LineWidth', 1.2); % 绘制真实价格序列,黑色线条用于对照 hold on; % 保持当前图像内容,叠加预测结果 plot(yPred, 'r--', 'LineWidth', 1.4); % 绘制 UKF 预测价格序列,红色虚线用于区分 legend('真实价格', 'UKF-GARCH预测价格'); % 添加图例,说明两条曲线的含义 title('股票价格预测结果'); % 设置图题,突出预测效果展示主题 xlabel('时间'); % 设置横轴标签,表示样本顺序或交易日序列 ylabel('价格'); % 设置纵轴标签,表示股票价格水平 grid on; % 打开网格,便于观察曲线变化细节 fig2 = figure('Color', 'w'); % 创建第二个图窗,用于展示波动率变化 plot(sigma, 'b', 'LineWidth', 1.2); % 绘制 GARCH 条件标准差序列 title('GARCH 条件波动率'); % 设置波动率图题,突出风险变化特征 xlabel('时间'); % 设置横轴标签 ylabel('标准差'); % 设置纵轴标签 grid on; % 打开网格,便于分析波动聚集现象