MATLAB实现基于VT-GRU 投票集成(VT)结合门控循环单元(GRU)进行股票价格预测的详细项目实例

请注意此篇内容只是一个项目介绍 更多详细内容可直接联系博主本人 

 或者访问对应标题的完整博客或者文档下载页面(含完整的程序,GUI设计和代码详解)

金融时间序列往往表现出强烈的非线性特征、噪声干扰与结构性突变,使得传统的线性统计方法在股票价格预测上的表现受到明显限制。传统方法如自回归模型、移动平均模型以及各种线性回归手段,在面对高频波动、突发事件以及多因素交互时,往往难以刻画价格序列中的复杂动态结构。与此同时,随着电子交易系统和高频交易的发展,市场数据的维度和更新频率都大幅提高,如何在大量历史数据中挖掘潜在的时序模式,成为量化分析与智能交易领域的重要研究方向。

在深度学习技术迅速发展的背景下,基于循环神经网络的时间序列建模方法逐渐成为研究热点。门控循环单元(GRU)作为一种典型的门控循环网络结构,凭借相对轻量的参数规模和较好的长短期依赖建模能力,在序列预测领域表现出良好性能。与传统简单循环网络相比,GRU通过更新门和重置门机制,有效缓解了梯度消失与梯度爆炸问题,同时在参数数量上较长短期记忆网络更为精炼,能够在有限数据和有限算力环境中提供较高的建模效率。这一特点,使其非常适合处理股票收盘价、成交量以及多维技术指标构成的中等长度时间序列。

然而,单一深度模型往往存在泛化能力不足、对训练随机性敏感以及对特定窗口设置过拟合等问题。当数据中包含多种周期成分、不同交易阶段的波动模式以及异质性较强的个股特征时,单一网络结构很容易偏向某一类模式,忽视其他潜在结构。在金融市场中,还存在“模型不确定性”问题,即使用不同的模型或不同的训练子集往往得到差异明显的预测结果。如果只依赖单一模型输出,容易在特定时期触发偏差放大效应,对实际交易决策带来风险。

集成学习为解决上述问题提供了重要思路。通过构建多模型集成体系,可以在一定程度上平衡个体模型的偏差与方差,使整体输出更加稳健。投票集成思想通过多个预测子模型的输出进行综合,采用平均、加权投票或排序投票等方式实现决策融合,增强结果的鲁棒性。将这种集成思想与GRU时间序列建模结合,使得不同GRU子模型可以在不同的时间窗口、特征组合或随机初始化条件下学习不同的模式,集成后的结果能够更全面地刻画价格动态。

基于VT-GRU的股票价格预测项目正是在这一背景下提出。其核心思路是构建多个结构相似但配置不同的GRU子模型,利用多视角(窗口长度、特征集、随机种子、网络深度等)的训练策略获得一组候选预测,然后通过投票集成(Voting-based Ensemble)机制整合这些候选预测,形成更稳定、泛化能力更强的最终预测结果。与传统单模型方法相比,这种结构在建模过程中引入了“模型多样性”,同时通过投票机制减弱单个模型偶然误差对最终结果的影响。

在具体实现层面,MATLAB平台为构建VT-GRU提供了较为完备的工具支持。基于R2025b版本,可以通过深度学习工具箱快速构建GRU网络结构,利用深度学习训练程序执行时间序列回归任务,再结合MATLAB在金融时间序列处理方面的成熟函数,构建从数据读取、预处理、特征工程到模型训练、验证与可视化的完整流程。通过合理配置训练选项、早停策略与评估指标,可以有效控制模型过拟合,提升预测稳定性。

股票市场本身具有较强的噪声与不确定性,不存在任何一种模型能够在所有市场条件下长期保持绝对优势。因此,更合理的方向是构建具有自适应能力与稳健性的预测框架,使其在不同市场阶段中尽量保持较为平衡的表现。VT-GRU方案在结构上强调“多模型、多视角”和“投票融合”,在实践中既可以作为独立的预测模块,也可以作为更大决策系统中的一环,与风险控制模块、资产配置模块和交易执行模块结合,为量化策略提供相对平滑的价格预估信号。

从应用层面来看,基于VT-GRU的股票价格预测既可以用于单只股票的短期收盘价预测,也可以扩展到多资产组合的联合预测,进一步为组合优化和风险控制提供数据支撑。通过对价格走势的相对精确估计,可以辅助制定买入卖出阈值、止损止盈规则以及仓位调整策略,在长期运作中提高收益波动比率。此外,在教学与研究上,该项目能够展示深度学习与集成学习在金融工程中的结合方式,为深入学习时间序列建模、网络结构设计与模型评估提供一个可操作的综合实例。

总体来看,VT-GRU股票价格预测项目既立足于金融时间序列建模的现实需求,又结合门控循环网络与投票集成的技术优势,形成了一个具有理论价值与实践意义的研究与实现框架。在MATLAB R2025b环境中进行完整实现,可以帮助开发者系统理解从数据到模型再到预测解析的全流程,同时为进一步扩展和创新打下坚实基础。

项目目标与意义

提升股票价格预测精度与稳定性

本项目第一层面的目标在于通过VT-GRU结构有效提升股票价格预测的精度与稳定性。在传统单模型方案中,模型预测通常对训练数据、初始参数和超参数配置高度敏感,不同的训练过程可能产生显著差异的结果。通过在MATLAB环境中构建多个GRU子模型,并利用不同的时间窗口长度、特征组合和初始化种子,可以从多角度对同一股票价格序列进行建模。随后采用投票集成机制,对各个GRU子模型的预测结果进行综合,例如使用简单平均、加权平均或基于误差倒数的投票权重,从而有效平滑单一模型的偶然波动。在金融市场这种高噪声环境下,预测结果的稳定性与平滑性往往比单点精度更重要,因为实际交易策略需要在多日尺度上根据连续信号判断买卖时机。通过VT-GRU方案,预测曲线能够更好地贴合价格长期趋势的同时对短期噪声不过度反应,为构建稳健交易信号提供更可靠的基础。

构建可扩展的深度学习金融建模框架

第二个重要目标在于构建一个具有可扩展性的深度学习金融建模框架。项目并不仅仅局限在某一只股票或某一时间段的预测,而是通过合理的代码架构和模块划分,使得整体系统易于扩展到不同股票、指数以及其他金融资产。在MATLAB R2025b环境中,通过将数据读取、预处理、特征工程、模型定义、训练配置、集成投票和可视化结果等环节进行模块化设计,可以为后续扩展提供清晰接口。例如,通过参数化窗口长度、预测步长和输入特征类型,轻松切换到新的数据集,或引入额外技术指标与基本面因子。更进一步,可以在现有GRU基础上嵌入自注意力层、卷积层或其他结构,形成更加复杂的时序模型集成,而不需要彻底重构项目框架。这种可扩展性使得项目不仅具有当前的研究与应用价值,也能成为后续深度学习金融研究的基础工程。

验证集成学习在金融时间序列中的实际价值

项目还希望系统性地验证投票集成思想在金融时间序列预测中的实际价值。尽管集成学习在图像、语音等领域表现出色,但金融市场数据的噪声特性、非平稳性和外在冲击,使其应用效果有必要进行专门的验证。通过在MATLAB中构建多个GRU子模型,并设计不同的训练子集划分和超参数组合,可以观察集成前后模型在均方误差、平均绝对误差以及方向性准确率等指标上的变化。特别是针对趋势捕捉能力,可以采用预测方向与真实方向一致率来衡量买卖信号的可靠性。通过系统实验与可视化分析,可以直观对比单一GRU模型与VT-GRU集成模型在不同市场阶段、不同股票上的表现差异,从而定量说明多模型投票融合对抗噪声与减少过拟合的效果。这种验证不仅促进模型本身的优化,还为后续引入其他集成策略(如堆叠、袋装或提升)提供参考。

提供面向实战与教学的完整MATLAB工程样例

项目还有一个重要意义在于提供一个面向实战与教学的完整MATLAB工程样例,使理论与实践紧密结合。在金融工程与量化分析教学中,常常需要一个可运行、结构清晰且覆盖数据处理、模型构建和结果解释全流程的案例。VT-GRU股票预测项目在MATLAB R2025b中实现了从股票历史数据读入、缺失值处理、归一化、滑动窗口构造,到构建多GRU子模型、训练、集成预测、误差评估和可视化的完整链条。通过详细注释的代码示例,可以协助学习者理解GRU的门控机制、时间序列建模策略、集成学习思想以及MATLAB深度学习接口的使用方式。对于实际从业者而言,该项目的工程结构也便于直接迁移到真实业务数据,通过修改数据源和参数配置即可形成可用的预测模块。因而本项目在教学和实战两个层面都具有较强的示范意义,有助于促进深度学习方法在金融领域的规范化应用。

项目挑战及解决方案

金融时间序列的非平稳性与噪声问题

金融时间序列往往存在显著的非平稳性、周期突变和噪声干扰。价格趋势可能在短时间内由上涨转为下跌,宏观事件和政策变化会导致整个市场结构发生突变。传统时间序列建模手段多以平稳性为前提,一旦这一前提被长期破坏,模型预测偏差就会逐步积累。在VT-GRU项目中,非平稳性和噪声是首要挑战之一。价格序列中蕴含的有用信号相对较弱,而高频波动与交易噪声占据大量数据。将原始价格直接输入GRU,容易导致模型学习到噪声模式而非真正有用的趋势与周期。

针对这一问题,项目在多个层面提出解决方案。一方面在数据预处理阶段,采用对数收益率、标准化、滑动窗口差分等方式,对价格序列进行平滑和相对平稳化处理。例如将收盘价转换为对数收益率,并结合技术指标如移动平均线、相对强弱指数等,构建更加稳定的特征空间。另一方面,在GRU网络结构与训练策略上,通过合理的正则化、丢弃层设置以及早停机制,降低模型对训练样本噪声的过拟合程度。多GRU子模型结构本身也具有分散风险的意味,不同子模型在不同时间窗口或特征组合上训练,使得某个子模型即便对特定噪声模式敏感,整体投票结果仍可以保持相对稳定。此外,在模型评估时,不仅考察误差指标,还结合趋势方向匹配率和极端行情下的表现,确保模型在关键时刻不会因为噪声导致完全偏离真实走势,从而在实践中更具可用性。

多模型集成策略与投票权重设计

在VT-GRU框架中,多模型集成是核心环节之一,但集成策略和投票权重设计并非简单技术问题。若采用简单平均投票,虽然能够在一定程度上减少单模型偶然误差,但对于明显表现较差的子模型缺乏有效抑制,可能拖累整体预测性能。若采用复杂的自适应加权策略,又可能导致权重学习本身陷入过拟合,甚至形成新的不稳定因素。如何在MATLAB平台中合理设计集成机制,使其既充分利用多模型多视角带来的信息冗余,又不过度增加系统复杂度与过拟合风险,是本项目面临的重要挑战。

解决方案采用“性能驱动的加权投票”思路,并结合验证集评估。在训练阶段,为每个GRU子模型划分独立的验证子集,记录其在验证集上的均方误差或平均绝对误差,随后将误差的倒数或通过归一化的函数作为投票权重,构建权重向量。在生成预测时,各子模型输出按权重加权求和。这样,性能较好的子模型在集成中占比更高,而表现较差的子模型自动被弱化。同时,为避免权重极端集中,还可以对误差倒数进行平滑处理或截断,避免某个子模型因偶然高性能而垄断整体决策。MATLAB R2025b的矩阵运算能力可以方便地实现这一加权过程,只需在预测阶段对各模型输出构成矩阵,再与权重向量计算矩阵乘法即可获得最终预测结果。通过可视化对比加权集成与简单平均的表现,可以验证这一策略的有效性,并在实际项目中灵活调整权重计算方式。

MATLAB环境下的工程实现与兼容性问题

在MATLAB R2025b环境中实现VT-GRU项目时,还需要面对一系列工程层面的挑战。例如,R2025b版本中对部分界面控件、可视化对象和机器学习函数的行为进行调整,如不再推荐使用某些UI组件、限制某些参数组合使用、调整深度学习网络状态更新方式等。这些变化若未充分考虑,可能导致代码在执行时触发警告或错误,影响项目的可重复性与稳定性。同时,深度学习相关接口在不同版本之间也可能存在轻微差异,设计代码时需要兼顾可读性与兼容性。

解决这一类问题时,项目采用“面向当前版本的稳健实现”策略。界面部分尽量使用传统的figure和uicontrol组合,而不依赖易受版本影响的新UI布局组件,从而在R2025b中保持高兼容性。可视化上使用标准Axes和figure对象,并注意在调用colormap时以figure或axes对象为输入,避免对ConfusionMatrixChart等特殊对象误用。在机器学习层面,使用R2025b正式支持的参数组合,如在fitrlinear中严格限定Regularization为lasso或ridge,避免无效选项。同时,在深度学习模型构建上,优先使用深度学习工具箱已经稳定支持的序列网络和layerGraph接口,不调用尚处于实验阶段或已经弃用的接口。通过详细注释和模块化代码,项目在保证功能完整的前提下,尽量规避版本差异带来的风险,使工程在R2025b中可以顺畅运行,并为后续迁移到更高版本保留足够空间。

项目模型架构

数据预处理与特征工程模块

在VT-GRU项目中,数据预处理与特征工程是整个模型架构的起点,对后续预测性能具有决定性影响。股票价格原始数据通常包含日期、开盘价、最高价、最低价、收盘价、成交量等字段,其中收盘价是最常用的预测目标。预处理首先需要完成缺失值检测与修复,包括对停牌、数据缺口以及异常波动进行处理,可以采用前值填充、插值或直接剔除等方式。在MATLAB中,可利用isnan、fillmissing等函数快速实现缺失值处理,通过向量化操作提升效率。

特征工程部分则围绕构造更具预测性的输入特征展开。单纯使用收盘价序列往往不足以刻画市场状态,因此有必要引入对数收益率、移动平均线、价格波动率以及动量类指标作为网络输入。例如,将原始收盘价转换为log(Ct/Ct-1),构成收益率序列,并在此基础上计算5日、10日、20日移动平均线以及对应的乖离率,用以表现趋势强度和偏离程度。成交量可用于反映资金活跃程度,可以通过对数变换和标准化处理减少尺度差异。通过组合这些价格与量能指标,可以为GRU网络提供丰富的信息源,使其更好学习趋势、反转与盘整等模式。

在滑动窗口构造阶段,模型将连续的历史时间步构成一个输入序列片段对应未来若干步的预测目标。窗口长度的设定直接影响网络能够捕捉的时间依赖范围,较短窗口有利于捕捉近期波动,较长窗口则强调长期趋势。在VT-GRU架构中,不同GRU子模型可以使用不同的窗口长度与预测步长,形成多视角数据序列,从而为后续集成提供多样性。所有特征在进入网络前需执行归一化或标准化处理,例如采用z-score标准化或min-max归一化,将输入特征缩放到[-1,1]或[0,1]区间,有助于模型稳定训练。MATLAB中可以使用normalize函数或自定义标准化函数,并记录归一化参数,以便在预测阶段对新数据使用相同变换,确保训练与测试分布一致。

GRU子模型结构设计

VT-GRU架构的核心由多个GRU子模型构成,每个子模型针对同一价格序列构建独立的时序预测网络。GRU单元通过更新门和重置门机制控制信息在时间上的流动。更新门决定当前隐状态在多大程度上保留前一时间步的信息,重置门则控制当前输入与历史信息的融合程度。每个时间步的候选隐状态由当前输入与上一隐状态通过非线性变换得到,再与上一隐状态按更新门加权融合,从而形成当前隐状态。这种结构在保持较短计算路径的同时,有效缓解了传统循环网络在长序列训练中面临的梯度衰减问题。

在MATLAB R2025b中,可以通过深度学习工具箱构建包含序列输入层、GRU层、全连接层与回归输出层的序列网络。对于股票价格预测任务,通常使用一到两层GRU作为主干网络,再接一个或多个全连接层输出最终的标量预测值。每个子模型可采用不同的隐层单元数、层数和丢弃率,以增加模型多样性。例如某些子模型使用单层较小隐单元以偏向于短期模式,另一些子模型使用较大隐单元或堆叠GRU,以强调较长时间依赖。通过合理设置初始学习率、L2正则化参数、mini-batch大小以及最大训练轮数,可以针对不同子模型进行精细化训练。训练过程可使用Adam或SGDM等优化算法,并结合验证集早停策略防止过拟合。子模型训练完成后,保存对应的网络结构和权重,用于后续集成预测。

投票集成(VT)预测模块

投票集成模块是VT-GRU框架的关键创新之一。该模块负责收集所有GRU子模型在同一输入序列上的预测结果,并根据预先设计的投票规则输出合成预测。投票集成可以采用多种形式,项目中采用以性能为导向的加权平均方案。为确定投票权重,需要在训练阶段为每个GRU子模型准备独立的验证集,通过在验证集上的误差指标估计模型可靠性。可以选用均方误差、平均绝对误差或加权误差作为度量,根据误差的倒数或其平滑函数构建权重,使误差较小的子模型获得更大权重。

在预测阶段,各子模型对输入特征序列分别执行前向传播,输出单步或多步预测的数值序列。将所有子模型的预测结果堆叠成矩阵,行维度表示样本,列维度表示子模型,然后与权重向量进行矩阵乘法,即可得到最终预测值。对于多步预测,可以对每一个预测步独立进行加权,或者在时间维度上进一步平滑。投票集成的优势在于能够自动弱化在某一阶段表现不佳的模型,通过整体决策提升稳定性。若后续扩展引入新的GRU子模型,只需在验证集上计算其误差并更新权重向量即可,不需要修改投票机制本身。这种结构使得VT-GRU具有良好的可扩展性与维护性。

训练与验证流程设计

训练与验证流程是VT-GRU项目的运行主线,负责协调数据划分、子模型训练、性能评估与参数调优。通常将完整的时间序列数据划分为训练集、验证集与测试集三部分。训练集用于优化模型参数,验证集用于选择超参数与投票权重,测试集用于评估最终模型在未见数据上的泛化性能。在具体实现中,可以采用时间顺序划分,保证未来数据不泄漏到过去,符合实际预测场景。在MATLAB中通过索引分割即可方便实现,避免随机划分导致的时间穿越问题。

训练过程中,每个GRU子模型依次进行训练,使用相同或不同的训练选项。通过训练选项设置最大训练轮数、mini-batch大小、梯度阈值、学习率衰减方案和验证频率。在每个训练周期或若干步后,通过验证集计算当前模型在验证数据上的误差指标。若验证误差在若干周期内不再下降,可以触发早停机制,避免过度训练。训练完成后,记录每个子模型在验证集上的误差,以便后续计算投票权重。在所有子模型训练完成后,将测试集输入VT-GRU集成框架,生成最终预测,并与真实价格比较,计算均方误差、平均绝对误差、方向正确率等指标。在整个流程中,通过绘图函数对损失曲线、预测与真实曲线进行可视化,辅助分析模型性能与问题。

MATLAB工程结构与模块化组织

在工程实现上,VT-GRU项目采用模块化组织结构,将数据处理、模型构建、训练、集成和可视化分离为若干逻辑模块。数据模块负责从文件或数据接口读取股票历史数据,执行清洗与特征构造后输出统一格式的训练数据。模型模块定义GRU子模型的结构,可以通过函数实现生成网络结构的通用接口,根据参数输入构建不同配置的子模型。训练模块控制多个子模型的训练流程,保存训练好的网络与性能指标。集成模块根据验证结果计算投票权重,并执行预测融合。可视化模块集中实现价格曲线、误差曲线和预测对比的绘制,便于调试和分析。

在MATLAB R2025b环境中,工程结构可采用主脚本加子函数的形式组织。主脚本负责调用各模块,协调执行顺序;子函数则实现各功能模块的细节逻辑。考虑到版本规范,界面组件尽量使用figure与uicontrol实现简单参数输入与结果浏览,而不依赖复杂的界面布局对象。可视化过程中,注意使用标准Axes和colormap(fig,turbo)等形式设置色图,避免使用已被限制的属性。通过充分注释和清晰命名,使每个模块职责明确,有助于后续维护与扩展。整体架构既满足当前VT-GRU实验需求,又为引入其他时间序列模型或扩展到多资产、多频率数据提供基础。

项目模型描述及代码示例

数据读取与预处理代码示例
clear; % 清空工作区变量,避免旧变量干扰当前实验
clc; % 清空命令行窗口,便于观察后续输出结果
close all; % 关闭所有图形窗口,防止旧图遮挡新图
dataFile = 'stock_data.csv'; % 指定包含股票历史数据的CSV文件名,可根据实际路径调整
rawTable = readtable(dataFile,'PreserveVariableNames',true); % 读取CSV文件为表格格式并保留原始列名,便于按列名访问
dateVec = rawTable.Date; % 从表格中提取日期列,用于后续按时间排序和可视化
closePrice = rawTable.Close; % 提取收盘价列,作为主要预测目标序列
volume = rawTable.Volume; % 提取成交量列,作为辅助特征之一
validIdx = ~isnan(closePrice) & ~isnan(volume); % 构造有效索引,过滤收盘价或成交量为缺失值的记录
closePrice = closePrice(validIdx); % 过滤收盘价,去除缺失记录
volume = volume(validIdx); % 过滤成交量,去除缺失记录
 [dateVec, sortIdx] = sort(dateVec); % 按日期从早到晚排序,返回排序后的日期和对应索引
closePrice = closePrice(sortIdx); % 使用同一索引重排收盘价,使其按时间顺序排列
volume = volume(sortIdx); % 使用同一索引重排成交量,保持与日期、价格对齐
logReturn = diff(log(closePrice)); % 计算对数收益率序列,反映相邻交易日的相对变化
logVolume = log(volume(2:end)); % 对成交量从第二个元素起取对数,使其与收益率长度匹配并压缩数值范围
ma5 = movmean(closePrice,[winMA-1 0]); % 计算5日移动平均,使用过去winMA-1天及当前日的均值
ma5 = ma5(2:end); % 去掉首个元素以与对数收益率长度对齐
retNorm = (logReturn - mean(logReturn)) / std(logReturn); % 对对数收益率进行标准化,使其均值为零方差为一
volNorm = (logVolume - mean(logVolume)) / std(logVolume); % 对对数成交量进行标准化,减小量纲差异
ma5Norm = (ma5 - mean(ma5)) / std(ma5); % 对5日移动平均进行标准化,统一尺度
滑动窗口构造与数据集划分代码示例
numSeq = numSamples - inputWindow - predictHorizon + 1; % 计算可构造的序列样本数量,确保窗口和预测目标均在范围内
Xcell = cell(numSeq,1); % 预分配输入序列单元数组,每个元素为一个时间序列特征矩阵
Ycell = cell(numSeq,1); % 预分配目标序列单元数组,每个元素为对应的标量目标
for i = 1:numSeq % 遍历每一个起始位置构造窗口
    Ycell{i} = targetVec(targetIdx); % 取出该时间步的目标值,作为当前序列的预测标签
end
trainRatio = 0.7; % 设置训练集比例为70%,用于模型参数学习
valRatio = 0.15; % 设置验证集比例为15%,用于超参数调整与早停判定
testRatio = 0.15; % 设置测试集比例为15%,用于评估最终泛化性能
numTrain = floor(numSeq * trainRatio); % 计算训练集样本数量,向下取整保证为整数
numVal = floor(numSeq * valRatio); % 计算验证集样本数量,向下取整
numTest = numSeq - numTrain - numVal; % 剩余部分作为测试集样本数量,保证总和为numSeq
XTrain = Xcell(1:numTrain); % 将前numTrain个序列作为训练输入集合
XVal = Xcell(numTrain+1:numTrain+numVal); % 中间numVal个序列作为验证输入集合
XTest = Xcell(numTrain+numVal+1:end); % 剩余序列作为测试输入集合,对应未来时段
GRU子模型1结构与训练代码示例
numResponses = 1; % 设置输出响应维度为1,对应单步标量价格预测
layers1 = [ ... % 定义第一个GRU子模型的网络层结构序列
    sequenceInputLayer(inputSize) % 序列输入层,接受inputSize维特征的时间序列
    fullyConnectedLayer(numResponses) % 全连接层,将GRU输出映射为单个预测值
    regressionLayer]; % 回归层,用于连续数值回归损失计算
miniBatchSize1 = 64; % 设置mini-batch大小为64,在序列训练中平衡内存与收敛速度
learnRate1 = 0.005; % 设置初始学习率为0.005,略高以加快初期收敛
options1 = trainingOptions('adam', ... % 使用Adam优化算法,适合处理非平稳时间序列
    'MaxEpochs',maxEpochs1, ... % 设置最大训练轮数
    'MiniBatchSize',miniBatchSize1, ... % 设置每个mini-batch包含的序列样本数
    'InitialLearnRate',learnRate1, ... % 设置初始学习率
    'L2Regularization',l2Reg1, ... % 设置L2正则化参数以控制模型复杂度
    'Shuffle','never', ... % 不在各轮之间打乱序列顺序,保持时间结构
    'ValidationFrequency',10, ... % 每训练10个mini-batch计算一次验证损失
    'Verbose',false, ... % 关闭逐mini-batch详细输出,保持命令行简洁
netGRU1 = trainNetwork(XTrain,YTrain,layers1,options1); % 使用指定网络结构和训练选项在训练集上训练第一个GRU子模型
YPredVal1 = predict(netGRU1,XVal,'MiniBatchSize',miniBatchSize1); % 利用训练好的第一子模型对验证集进行预测
valError1 = sqrt(mean((cell2mat(YPredVal1) - cell2mat(YVal)).^2)); % 计算验证集上的均方根误差,评估模型在验证数据的拟合能力
GRU子模型2结构与训练代码示例
numHiddenUnits2 = 80; % 设置第二个GRU子模型的隐层单元数为80,较大容量以捕捉更复杂模式
layers2 = [ ... % 定义第二个GRU子模型的网络层结构
    sequenceInputLayer(inputSize) % 序列输入层,与第一个子模型相同
    gruLayer(numHiddenUnits2,'OutputMode','last') % GRU层,隐单元数为80输出最后隐状态
    fullyConnectedLayer(numResponses) % 全连接层,将GRU输出映射为单个预测值
    regressionLayer]; % 回归层,用于计算回归损失
learnRate2 = 0.003; % 设置较低初始学习率0.003,减小大模型训练震荡
options2 = trainingOptions('adam', ... % 使用Adam优化算法训练第二个子模型
    'MaxEpochs',maxEpochs2, ... % 最大训练轮数设置为100
    'MiniBatchSize',miniBatchSize2, ... % mini-batch大小为64
    'InitialLearnRate',learnRate2, ... % 初始学习率为0.003
    'L2Regularization',l2Reg2, ... % L2正则系数为0.0002
    'GradientThreshold',1, ... % 设置梯度截断阈值为1
    'Shuffle','never', ... % 不打乱序列顺序
    'ValidationFrequency',10, ... % 每10个mini-batch执行一次验证
    'Verbose',false, ... % 关闭详细文本输出
    'Plots','training-progress'); % 显示训练过程曲线,方便观察收敛情况
netGRU2 = trainNetwork(XTrain,YTrain,layers2,options2); % 使用训练集训练第二个GRU子模型
epsVal = 1e-6; % 设置一个极小正数用于防止除零,提高数值稳定性
w1_raw = 1 / (valError1 + epsVal); % 根据第一个子模型验证误差的倒数计算未归一化权重
wSum = w1_raw + w2_raw; % 计算两个未归一化权重的总和,用于归一化
w1 = w1_raw / wSum; % 归一化第一个子模型权重,使总和为1
w2 = w2_raw / wSum; % 归一化第二个子模型权重,使总和为1
YPredTest2 = predict(netGRU2,XTest,'MiniBatchSize',miniBatchSize2); % 使用第二个子模型对测试集进行预测
YTestMat = cell2mat(YTest); % 将测试目标单元数组转换为数值向量,便于误差计算
YPredTest2Vec = cell2mat(YPredTest2); % 将第二个子模型预测转换为向量形式
YPredEnsemble = w1 * YPredTest1Vec + w2 * YPredTest2Vec; % 根据归一化权重对两个子模型预测进行加权求和,得到集成预测
rmse1 = sqrt(mean((YPredTest1Vec - YTestMat).^2)); % 计算第一个子模型在测试集上的均方根误差
rmse2 = sqrt(mean((YPredTest2Vec - YTestMat).^2)); % 计算第二个子模型在测试集上的均方根误差
rmseEnsemble = sqrt(mean((YPredEnsemble - YTestMat).^2)); % 计算集成预测在测试集上的均方根误差,用于对比单模型和集成效果
figure; % 创建新的图形窗口用于绘制预测对比图
plot(YTestMat,'k','LineWidth',1.2); hold on; % 绘制真实测试目标序列,黑色线表示真实标准化价格
plot(YPredTest2Vec,'r--','LineWidth',1); % 绘制第二个子模型预测结果,红色虚线表示单模型2预测
legend({'真实','GRU1','GRU2','集成'},'Location','best'); % 添加图例,说明各曲线含义并自动选择合适位置
ylabel('标准化价格'); % 设置纵轴标签为标准化价格值
预测结果逆标准化与价格层面解析代码示例
muPrice = mean(closePrice(2:end)); % 计算训练阶段使用的收盘价均值,用于逆标准化
priceTestEnsemble = YPredEnsemble * sigmaPrice + muPrice; % 将集成预测值逆标准化为真实价格
idxStartTest = numTrain + numVal + inputWindow + 1; % 计算测试集起始时间索引,对齐原始日期序列
plot(dateTest,priceTestTrue,'k','LineWidth',1.2); hold on; % 绘制真实收盘价曲线,黑色线表示真实价格轨迹
plot(dateTest,priceTestEnsemble,'g','LineWidth',1.3); % 绘制集成预测价格曲线,绿色线表示VT-GRU预测结果
datetick('x','yyyy-mm-dd','keepticks'); % 将横轴日期格式设置为年月日形式,保持现有刻度位置
xlabel('日期'); % 设置横轴标签为日期
ylabel('收盘价'); % 设置纵轴标签为收盘价
title('VT-GRU集成模型测试集价格预测对比'); % 添加标题,说明图形内容为VT-GRU集成模型在测试集上的预测表现
grid on; % 启用网格线,增强图形可读性

数据读取与预处理代码示例

clear; % 清空工作区变量,避免旧变量干扰当前实验
clc; % 清空命令行窗口,便于观察后续输出结果
close all; % 关闭所有图形窗口,防止旧图遮挡新图
dataFile = 'stock_data.csv'; % 指定包含股票历史数据的CSV文件名,可根据实际路径调整
rawTable = readtable(dataFile,'PreserveVariableNames',true); % 读取CSV文件为表格格式并保留原始列名,便于按列名访问
dateVec = rawTable.Date; % 从表格中提取日期列,用于后续按时间排序和可视化
closePrice = rawTable.Close; % 提取收盘价列,作为主要预测目标序列
volume = rawTable.Volume; % 提取成交量列,作为辅助特征之一
validIdx = ~isnan(closePrice) & ~isnan(volume); % 构造有效索引,过滤收盘价或成交量为缺失值的记录
closePrice = closePrice(validIdx); % 过滤收盘价,去除缺失记录
volume = volume(validIdx); % 过滤成交量,去除缺失记录
 [dateVec, sortIdx] = sort(dateVec); % 按日期从早到晚排序,返回排序后的日期和对应索引
closePrice = closePrice(sortIdx); % 使用同一索引重排收盘价,使其按时间顺序排列
volume = volume(sortIdx); % 使用同一索引重排成交量,保持与日期、价格对齐
logReturn = diff(log(closePrice)); % 计算对数收益率序列,反映相邻交易日的相对变化
logVolume = log(volume(2:end)); % 对成交量从第二个元素起取对数,使其与收益率长度匹配并压缩数值范围
ma5 = movmean(closePrice,[winMA-1 0]); % 计算5日移动平均,使用过去winMA-1天及当前日的均值
ma5 = ma5(2:end); % 去掉首个元素以与对数收益率长度对齐
retNorm = (logReturn - mean(logReturn)) / std(logReturn); % 对对数收益率进行标准化,使其均值为零方差为一
volNorm = (logVolume - mean(logVolume)) / std(logVolume); % 对对数成交量进行标准化,减小量纲差异
ma5Norm = (ma5 - mean(ma5)) / std(ma5); % 对5日移动平均进行标准化,统一尺度

滑动窗口构造与数据集划分代码示例

numSeq = numSamples - inputWindow - predictHorizon + 1; % 计算可构造的序列样本数量,确保窗口和预测目标均在范围内
Xcell = cell(numSeq,1); % 预分配输入序列单元数组,每个元素为一个时间序列特征矩阵
Ycell = cell(numSeq,1); % 预分配目标序列单元数组,每个元素为对应的标量目标
for i = 1:numSeq % 遍历每一个起始位置构造窗口
    Ycell{i} = targetVec(targetIdx); % 取出该时间步的目标值,作为当前序列的预测标签
end
trainRatio = 0.7; % 设置训练集比例为70%,用于模型参数学习
valRatio = 0.15; % 设置验证集比例为15%,用于超参数调整与早停判定
testRatio = 0.15; % 设置测试集比例为15%,用于评估最终泛化性能
numTrain = floor(numSeq * trainRatio); % 计算训练集样本数量,向下取整保证为整数
numVal = floor(numSeq * valRatio); % 计算验证集样本数量,向下取整
numTest = numSeq - numTrain - numVal; % 剩余部分作为测试集样本数量,保证总和为numSeq
XTrain = Xcell(1:numTrain); % 将前numTrain个序列作为训练输入集合
XVal = Xcell(numTrain+1:numTrain+numVal); % 中间numVal个序列作为验证输入集合
XTest = Xcell(numTrain+numVal+1:end); % 剩余序列作为测试输入集合,对应未来时段

GRU子模型1结构与训练代码示例

numResponses = 1; % 设置输出响应维度为1,对应单步标量价格预测
layers1 = [ ... % 定义第一个GRU子模型的网络层结构序列
    sequenceInputLayer(inputSize) % 序列输入层,接受inputSize维特征的时间序列
    fullyConnectedLayer(numResponses) % 全连接层,将GRU输出映射为单个预测值
    regressionLayer]; % 回归层,用于连续数值回归损失计算
miniBatchSize1 = 64; % 设置mini-batch大小为64,在序列训练中平衡内存与收敛速度
learnRate1 = 0.005; % 设置初始学习率为0.005,略高以加快初期收敛
options1 = trainingOptions('adam', ... % 使用Adam优化算法,适合处理非平稳时间序列
    'MaxEpochs',maxEpochs1, ... % 设置最大训练轮数
    'MiniBatchSize',miniBatchSize1, ... % 设置每个mini-batch包含的序列样本数
    'InitialLearnRate',learnRate1, ... % 设置初始学习率
    'L2Regularization',l2Reg1, ... % 设置L2正则化参数以控制模型复杂度
    'Shuffle','never', ... % 不在各轮之间打乱序列顺序,保持时间结构
    'ValidationFrequency',10, ... % 每训练10个mini-batch计算一次验证损失
    'Verbose',false, ... % 关闭逐mini-batch详细输出,保持命令行简洁
netGRU1 = trainNetwork(XTrain,YTrain,layers1,options1); % 使用指定网络结构和训练选项在训练集上训练第一个GRU子模型
YPredVal1 = predict(netGRU1,XVal,'MiniBatchSize',miniBatchSize1); % 利用训练好的第一子模型对验证集进行预测
valError1 = sqrt(mean((cell2mat(YPredVal1) - cell2mat(YVal)).^2)); % 计算验证集上的均方根误差,评估模型在验证数据的拟合能力

GRU子模型2结构与训练代码示例

numHiddenUnits2 = 80; % 设置第二个GRU子模型的隐层单元数为80,较大容量以捕捉更复杂模式
layers2 = [ ... % 定义第二个GRU子模型的网络层结构
    sequenceInputLayer(inputSize) % 序列输入层,与第一个子模型相同
    gruLayer(numHiddenUnits2,'OutputMode','last') % GRU层,隐单元数为80输出最后隐状态
    fullyConnectedLayer(numResponses) % 全连接层,将GRU输出映射为单个预测值
    regressionLayer]; % 回归层,用于计算回归损失
learnRate2 = 0.003; % 设置较低初始学习率0.003,减小大模型训练震荡
options2 = trainingOptions('adam', ... % 使用Adam优化算法训练第二个子模型
    'MaxEpochs',maxEpochs2, ... % 最大训练轮数设置为100
    'MiniBatchSize',miniBatchSize2, ... % mini-batch大小为64
    'InitialLearnRate',learnRate2, ... % 初始学习率为0.003
    'L2Regularization',l2Reg2, ... % L2正则系数为0.0002
    'GradientThreshold',1, ... % 设置梯度截断阈值为1
    'Shuffle','never', ... % 不打乱序列顺序
    'ValidationFrequency',10, ... % 每10个mini-batch执行一次验证
    'Verbose',false, ... % 关闭详细文本输出
    'Plots','training-progress'); % 显示训练过程曲线,方便观察收敛情况
netGRU2 = trainNetwork(XTrain,YTrain,layers2,options2); % 使用训练集训练第二个GRU子模型
epsVal = 1e-6; % 设置一个极小正数用于防止除零,提高数值稳定性
w1_raw = 1 / (valError1 + epsVal); % 根据第一个子模型验证误差的倒数计算未归一化权重
wSum = w1_raw + w2_raw; % 计算两个未归一化权重的总和,用于归一化
w1 = w1_raw / wSum; % 归一化第一个子模型权重,使总和为1
w2 = w2_raw / wSum; % 归一化第二个子模型权重,使总和为1
YPredTest2 = predict(netGRU2,XTest,'MiniBatchSize',miniBatchSize2); % 使用第二个子模型对测试集进行预测
YTestMat = cell2mat(YTest); % 将测试目标单元数组转换为数值向量,便于误差计算
YPredTest2Vec = cell2mat(YPredTest2); % 将第二个子模型预测转换为向量形式
YPredEnsemble = w1 * YPredTest1Vec + w2 * YPredTest2Vec; % 根据归一化权重对两个子模型预测进行加权求和,得到集成预测
rmse1 = sqrt(mean((YPredTest1Vec - YTestMat).^2)); % 计算第一个子模型在测试集上的均方根误差
rmse2 = sqrt(mean((YPredTest2Vec - YTestMat).^2)); % 计算第二个子模型在测试集上的均方根误差
rmseEnsemble = sqrt(mean((YPredEnsemble - YTestMat).^2)); % 计算集成预测在测试集上的均方根误差,用于对比单模型和集成效果
figure; % 创建新的图形窗口用于绘制预测对比图
plot(YTestMat,'k','LineWidth',1.2); hold on; % 绘制真实测试目标序列,黑色线表示真实标准化价格
plot(YPredTest2Vec,'r--','LineWidth',1); % 绘制第二个子模型预测结果,红色虚线表示单模型2预测
legend({'真实','GRU1','GRU2','集成'},'Location','best'); % 添加图例,说明各曲线含义并自动选择合适位置
ylabel('标准化价格'); % 设置纵轴标签为标准化价格值

预测结果逆标准化与价格层面解析代码示例

muPrice = mean(closePrice(2:end)); % 计算训练阶段使用的收盘价均值,用于逆标准化
priceTestEnsemble = YPredEnsemble * sigmaPrice + muPrice; % 将集成预测值逆标准化为真实价格
idxStartTest = numTrain + numVal + inputWindow + 1; % 计算测试集起始时间索引,对齐原始日期序列
plot(dateTest,priceTestTrue,'k','LineWidth',1.2); hold on; % 绘制真实收盘价曲线,黑色线表示真实价格轨迹
plot(dateTest,priceTestEnsemble,'g','LineWidth',1.3); % 绘制集成预测价格曲线,绿色线表示VT-GRU预测结果
datetick('x','yyyy-mm-dd','keepticks'); % 将横轴日期格式设置为年月日形式,保持现有刻度位置
xlabel('日期'); % 设置横轴标签为日期
ylabel('收盘价'); % 设置纵轴标签为收盘价
title('VT-GRU集成模型测试集价格预测对比'); % 添加标题,说明图形内容为VT-GRU集成模型在测试集上的预测表现
grid on; % 启用网格线,增强图形可读性

更多详细内容请访问

http://【金融时间序列预测】MATLAB实现基于VT-GRU投票集成(VT)结合门控循环单元(GRU)进行股票价格预测的详细项目实例(含完整的程序,GUI设计和代码详解)_CNN-BiLSTM Python实现资源-CSDN下载  https://download.csdn.net/download/xiaoxingkongyuxi/90259193

https://download.csdn.net/download/xiaoxingkongyuxi/90259193

https://download.csdn.net/download/xiaoxingkongyuxi/90259193

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐