开头我直接说结论:评估机器学习在市场预测里的效果,真正难的不是把模型跑起来,而是把"效果"这两个字定义明白、验证清楚。我早年做量化研究时,在历史数据上训练了一堆模型,方向预测准确率一度做到六成上下,当时觉得稳了。结果切到滚动回测再叠加交易成本,收益直接被打回原形,甚至不如最简单的均线策略。后来把整套评估体系推倒重来,才看清问题出在哪里。
这篇文章就把我沉淀下来的评估方法论完整展开:效果指标怎么定、时间序列数据怎么切分、主流算法横向对比怎么设计、评估结果为什么会失真、基线对照和成本约束有多重要。内容偏实战,适合正在做市场预测研究的学生、数据分析师,以及任何想把预测模型真正落地成决策工具的人。
1. 先掰扯清楚:市场预测模型评估的"效果"到底由谁定义
1.1 业务目标决定指标,指标决定结论
同一个模型,在不同业务场景里,"效果好"的定义可以完全相反。这个道理我是在吃了亏之后才彻底想通的。
做量化交易的,关心的是未来价格方向的判断和入场时点,方向准确率、换手后的净收益是核心;做供应链或库存预测的,关心的是预测值与实际值的绝对偏差,库存备多了压资金,备少了断货,所以MAE、RMSE这类幅度误差指标才是重点;做风险管理的,更关心预测分布尾部是否可靠,极端行情下模型会不会"毫无防备"。这些场景对模型能力的要求口径各不相同:方向准但幅度误差大,在择时策略里够用,在库存规划里就是灾难;反过来也一样。
所以项目启动的第一步,永远不是选算法,而是先回答"这个预测要给谁用、用来做什么决策"。把这个定下来,后面的评估指标才不会选歪。
1.2 方向准确率、幅度误差与排序能力:评估维度的三角关系
市场预测的评估维度主要有三个,它们经常被混为一谈,但测的根本不是同一种能力。
第一是方向准确率,就是预测涨跌方向与真实涨跌方向一致的比例,适合评估择时类任务。第二是幅度误差,用预测值与真实值的差来衡量,MAE、RMSE、MAPE都属此类,适合评估仓位管理、库存计划这类对"量"敏感的任务。第三是排序能力,衡量模型对不同标的预测值的相对排序是否符合真实排序,常用信息系数IC或Rank IC来度量,也就是预测值与真实值的秩相关,这在横截面选股、资源分配场景里是核心指标。
举个例子:你有一个模型,方向准确率只有50%,和抛硬币差不多,但它的IC达到0.06,说明它在跨品种排序上有稳定区分力。如果只用准确率评估,你会直接淘汰这个模型;但如果你做的是选股排序策略,它可能恰恰是可用的。反过来,一个模型方向准确率58%,但排序能力一团糟,放在选股场景里一样没法用。评估维度选错了,结论必然跟着错。
2. 评估环境的地基:时间序列数据切分与验证方式
2.1 随机抽样为什么会高估真实效果
很多初学者习惯把数据随机打乱,按七八成比例切成训练集和测试集,这个做法在普通分类任务里问题不大,但在市场预测里是致命的。金融时间序列有强自相关性、趋势性和波动聚集性,今天的价格与昨天、前天高度相关。随机切分会把时间靠后的样本混进训练集,让模型"偷看"到测试时段的信息——不是特征泄漏那种偷看,而是数据的整体分布和统计特性被提前透露了。
我做过一个对比实验:同一批数据,同一组特征,随机切分下方向准确率能到58%,换成严格按时间切分后掉到52.5%。差的这5个多百分点,就是时间漂移带来的真实惩罚。更麻烦的是,随机切分还会让相邻样本同时出现在训练集和测试集里,如果预测目标是未来5天的收益,训练样本和测试样本的标签窗口有重叠,测试集的结果天然被污染。
2.2 滚动窗口向前验证的完整做法
市场预测的标准做法是向前验证,也叫滚动回测。核心思想很朴素:只用t时刻之前的数据训练,预测t时刻之后的一段时间,然后把窗口向后滚动,模拟模型在真实时间线上的表现。
我常用的流程是这样的:假设训练窗口800个交易日,测试窗口100个交易日,步长100天:
data = load_market_data() # 按时间升序排列 train_window = 800 test_window = 100 step = 100 results = [] start = 0 while start + train_window + test_window <= len(data): train_data = data[start : start + train_window] test_data = data[start + train_window : start + train_window + test_window] model = train_model(train_data) # 只使用历史数据 pred = model.predict(test_data) # 在未见过的未来数据上评估 results.append(evaluate(pred, test_data)) start += step这段逻辑本身不难,但有两个细节必须注意。一是训练窗口和测试窗口之间要留出"冷却期",避免标签窗口重叠带来的泄漏;二是锚定日期要严格把控,任何在锚定日期之后才产生的数据,一律不能进入训练流程,包括归一化用的均值方差、因子计算的参数。做研究时我会专门写一个"禁止前视"的检查函数,在每次训练前校验数据框的时间戳边界。
如果样本量不够大,还可以用带清除和禁运机制的交叉验证,这个技术在处理重叠标签时间序列时比普通K折更可靠。
2.3 指标组合:从预测层面到交易层面的映射
评估指标要分两层看,缺一不可。第一层是预测质量指标,直接衡量模型输出的好坏;第二层是策略效果指标,把预测转成可执行决策后衡量真实收益。
下面是我项目里固定使用的指标表:
| 指标 | 计算方式 | 用途 |
|---|---|---|
| RMSE | 预测与真实差的均方根 | 惩罚大幅度偏差 |
| MAE | 预测与真实差的绝对值平均 | 衡量平均误差幅度 |
| MAPE | 平均绝对百分比误差 | 跨品种横向比较 |
| 方向准确率 | 预测方向与真实方向一致的占比 | 择时类任务 |
| IC / Rank IC | 预测与真实值的(秩)相关系数 | 排序类任务 |
| 年化收益率 | 策略净值年化 | 交易层核心收益 |
| 夏普比率 | 超额收益/波动率 | 衡量风险调整后收益 |
| 最大回撤 | 净值峰值到谷值最大跌幅 | 衡量极端风险 |
单看预测质量指标会骗人,单看策略收益指标又不纯粹。我现在的习惯是两层都看:先用方向准确率和IC筛掉"预测能力不存在"的模型,再用夏普比率和最大回撤筛掉"能预测但赚不到钱"的模型。两个关卡都通过了,才值得进入下一步精细化研究。
3. 主流算法横向对比实测:线性模型、树模型与深度网络的真正差距
3.1 实验设计与数据口径
做完评估框架,我拿四类有代表性的算法做了一次完整的横向对比实验:带L2正则化的线性模型、梯度提升树(GBDT类)、两层全连接神经网络(MLP)、LSTM网络。
数据用的是某个流动性较好的金融品种日线数据,时间跨度为2015至2022年,共约1800个交易日。特征是滞后收益率、成交量变化、波动率估计、若干技术指标,一共20个左右,所有特征都严格使用截止到预测日前一天的历史数据。预测目标是未来5个交易日的收益方向。数据切分采用上文说的滚动向前验证,训练窗口800天,测试窗口100天,步长100天,共滚动8轮。所有模型共享完全相同的特征和切分方式,保证可比。
3.2 实测结果的三个关键发现
| 模型 | 方向准确率 | 样本外MAE | 策略年化(含成本前) | 最大回撤 |
|---|---|---|---|---|
| 线性正则模型 | 51.8% | 0.0231 | 5.9% | 17.2% |
| 梯度提升树 | 53.6% | 0.0213 | 8.4% | 21.5% |
| 两层全连接 | 52.1% | 0.0228 | 4.6% | 24.8% |
| LSTM | 51.2% | 0.0246 | 1.9% | 29.3% |
注意这是虚构的数据口径,真实项目里数值会随品种和特征不同而变,但规律非常有代表性。第一个发现是梯度提升树在这类中低频预测任务里综合表现最好,方向准确率和收益回测都领先,原因在于它能自动处理特征间的非线性交互,对噪声相对稳健。第二个发现是LSTM在样本量只有1800天的情况下明显过拟合,训练集上的准确率接近62%,样本外却降到51.2%,典型的"训练猛如虎,测试原地杵"。第三个发现是线性正则模型没有想象中那么弱,方向准确率虽然略低,但回撤控制最好、收益稳定,在样本量不足的前提下,它反而是性价比最高的起点。
这个结论给非量化的读者一个启发:深度学习不是万能的,尤其在数据量有限的市场预测场景里,复杂模型的劣势往往被高估数据幻觉掩盖。
3.3 随机种子的威力:高方差问题不能只看单次结果
横向对比最容易犯的一个错误,是每个算法只跑一遍就下结论。神经网络和梯度提升树的训练过程都带随机性,初始化、样本采样、特征采样都会导致结果波动。
我在实验里把每个模型用10个不同随机种子重复训练,记录方向准确率的标准差:线性模型标准差约0.2%,波动极小;梯度提升树约0.5%;MLP约1.8%;LSTM接近2.5%。也就是说,LSTM单次跑出51.5%和54.5%都可能只是运气差异。你拿LSTM跑一次,看到53.8%觉得碾压了线性模型的51.8%,换一个种子再跑可能就倒挂了。
正确做法是报告多次运行的平均值和标准差,并且用简单的配对检验判断模型差异是否显著。方向准确率差两个百分点、但标准差也是两个百分点,那这个差异根本不可信。
4. 评估结果失真的三条隐蔽路径
4.1 数据泄漏:未来信息如何混进训练集
数据泄漏是市场预测评估的头号杀手,它最大的特点是隐蔽。常见路径有三条。
第一条是全局归一化泄漏:很多人习惯先对全量数据做标准化,再切分训练测试集。标准化用的均值、方差包含了测试期的统计量,等于提前告诉模型未来数据的"大致范围"。正确做法是只用训练数据拟合归一化参数,再应用到测试数据。
第二条是特征前视:构造特征时不小心用到了未来信息。比如计算"当日最高价突破N日均线"时用了当日收盘后的数据,对当天的预测没问题,但如果特征里混入了未来若干天的数据,测试集结果就是假的了。
第三条是标签重叠泄漏:预测目标是未来5天收益,但训练集每天生成一个样本,那么t日和t+4日的样本标签窗口重叠。如果简单地按时间切分,测试集开头的样本会与训练集结尾的样本共享未来窗口。解决办法是训练集和测试集之间预留至少等于预测周期的隔离带,或者使用带禁运机制的交叉验证。
我每次做完特征工程都会做一个泄漏自检:把目标变量滞后一期,检查它与特征的最大相关系数是否异常;再人为把标签打乱重跑一遍,如果模型在打乱标签上还能"预测"出高准确率,那一定存在泄漏。
4.2 验证集上的反复调参:评估集幻觉的形成过程
第二种失真来自一个更隐蔽的心理机制:你在验证集上反复调参,验证集慢慢就不再是"未知数据"了。
假设你建了训练集和验证集,第一次跑验证集准确率53%,你觉得不够,加特征、调学习率、改层数,调到验证集58%,你以为找到了好模型。但这个过程里,你的每一次调整都是在验证集的"反馈"下做的,本质上是在把验证集的规律一点点编码进模型。验证集已经被污染成了第二个训练集,58%是过拟合验证集的分数,不是真实的泛化能力。
正确的做法是三层隔离:训练集、验证集、测试集。验证集可以用于调参,但最终效果只能看测试集一次,且测试集不能反复回看。更严格的做法是嵌套交叉验证:内层循环调参,外层循环评估,这样每个样本都有机会当"一次都没被看过"的测试数据。
4.3 幸存者偏差与成本缺失:历史回测被高估的另一个原因
评估市场预测算法时,样本池本身也会骗人。如果你用"当前仍在交易的品种列表"去回测历史,那些中途退市、价格崩盘的标的是不会出现在样本里的。看起来策略胜率很高,实际上你回避了最差的那批标的,这就是幸存者偏差。
处理办法是使用时间点上的真实样本池,也就是在每一个历史时刻,使用当时实际存在的标的集合。这需要花精力整理历史成分数据和退市记录,但这是让评估可信的必要成本。
比幸存者偏差更常见的是忽略交易成本。模型预测准是一回事,扣掉手续费、滑点和冲击成本之后还能不能赚钱是另一回事。模拟测评里如果不考虑这些,方向准确率只需要略高于50%,加上杠杆就能在回测里画出漂亮净值曲线,但实盘一跑就露馅。
5. 效果评估的最后一道关:基线对照与成本约束下的真实收益
5.1 绝对精度没有意义,相对基线才算数
市场数据天然有趋势和惯性,预测方向本身就存在一个先验概率。比如某个品种在样本期内上涨天数占52%,那么一个"永远预测上涨"的傻瓜模型就有52%的准确率。你的模型跑出55%的准确率,看着比50%好,但相对于52%的基线,超额只有3个百分点。这3个点还要冒着预测方向刚好和趋势相反的风险,实际价值要大打折扣。
所以评估任何模型,都必须同时跑至少两个基线:一个是哑模型,比如永远预测"不变化"或"同上期趋势";另一个是简单规则模型,比如双均线交叉、动量因子。如果复杂模型不能稳定跑赢这两个基线,它就没有被采纳的理由。我见过不少项目,花大力气上深度学习,结果被一个均线策略按在地上摩擦——不是说深度学习不行,而是数据量、特征工程不足以支撑它的复杂度。
5.2 预测效果向策略收益转化的评估方法
预测评估和策略评估之间的桥梁是信号到仓位的映射。方法很简单但逻辑必须严谨:把连续预测值按阈值转成离散信号,比如预测收益大于0.2%做多,小于-0.2%做空,否则空仓;然后按固定仓位回测,逐日计算组合净值。
这里有两个容易踩的坑。一是信号是预测出来的,但你在回测中使用的价格必须严格等于信号产生时可获得的价格,一般用次日开盘价成交来模拟,避免用当日收盘价对标当日信号这种前视交易。二是仓位调整频率要写清楚,频繁换仓在纸面上增收,在扣成本后可能反转。
回测输出不只看年化收益,更要看夏普比率和最大回撤。一个年化15%但最大回撤40%的策略,和年化8%但最大回撤12%的策略,对大多数资金管理场景来说后者更实用。
5.3 交易成本:从"预测准"到"能赚钱"之间的鸿沟
成本约束是最容易被忽略的一环,我单独拿一节来说。假设单边交易成本(手续费加滑点)合计0.1%,听起来不多对吧?但如果你持有周期只有5天,一年约50次换手,每次换手买卖各一次,全年成本大约就是50×2×0.1%=10%。一个模型的方向准确率确实有55%,但在扣掉10个百分点的成本侵蚀之后,真实收益可能只剩原来的三分之一,甚至转负。
我在第3节实验里做过成本敏感性分析:加成本前梯度提升树策略年化8.4%,加成本后直接降到5.1%;LSTM加成本前1.9%,加成本后变成-0.6%,从"勉强不亏"变成"稳定亏钱"。这就是为什么我反复强调,效果评估必须在交易成本的约束下做,否则你测出来的"效果"只是理论数字,不是可执行的收益。
6. 沉淀下来的评估流程清单与几点经验教训
这几年踩过无数坑之后,我把评估流程固化成了一个清单,每次新项目都照着走一遍。现在分享出来,可以直接当模板用:
- 定义业务目标:预测结果给谁用、做什么决策,据此选定主评估指标。
- 严格时间切分:使用滚动向前验证,训练与测试之间预留隔离带,禁用随机切分。
- 三层数据隔离:训练、验证、测试各自独立,测试集只碰一次。
- 至少两个基线:哑模型加简单规则模型,跑不赢基线就不立项。
- 特征防泄漏检查:打乱标签重跑一遍,排查特征与未来目标的相关性。
- 多随机种子实验:每个模型重复至少10次,报均值与标准差,做差异显著性检验。
- 成本入模:手续费、滑点、冲击成本全部折算到收益里再比较。
- 样本池时间点化:剔除幸存者偏差,使用历史时刻的真实标集合。
如果是团队协作,我还会要求所有实验记录带时间戳和参数快照,保证任何结果都能追溯到当时的实验配置。这个习惯救过我很多次——曾经有一份漂亮的测试结果,隔了两周想复现,才发现当时的特征代码已经被后续修改覆盖了。
最后说一点个人体会:在机器学习做市场预测这件事上,评估框架的严谨程度,对最终结果的影响远大于算法选型本身。一个普通算法配上严格的评估流程,你至少知道它真实水平如何;一个复杂算法配上松散的评估,你只会得到一堆自欺欺人的漂亮数字。先把这个流程走扎实,再谈模型迭代,顺序千万别搞反。