200字
我的量化模型 85% 精度,回测亏了 82%——问题出在标签上
2026-09-04
2026-09-04

一台 16G 内存的云服务器,一个想用机器学习炒股的人

先报成绩单:我做了一个 A 股选股模型,验证精度 85%,听起来很唬人吧?

然后我跑了回测,亏了 82%

这篇文章复盘这个打脸过程的完整技术链路:一个精度指标是怎么骗过我的,以及我后来怎么一步步把「预测得准」修成「真的能赚钱」。所有数字都是我真实回测的输出,代码思路在文末,不构成投资建议。

第一个坑:我的模型根本没在学选股

v1 版本我拍脑袋定的标签是:未来 5 天涨幅超过 6%,记为正样本。LightGBM 跑出来精度 85%,我激动了一晚上。

回测直接给我上了一课。

冷静下来拆解才发现:那段时间大盘本身在涨。「未来 5 天会不会涨」的答案,一大半由大盘决定——牛市里无脑预测 "涨" 就能拿到高精度。我的模型学到的不是「这只股票比别的股票强」,而是「明天大盘涨不涨」。牛市里精度虚高,一转熊全部现形:模型满仓杀进随大盘下跌的股票,回测曲线一路向南。

修复方案:把标签改成相对收益。

正样本 = 未来 20 天内,个股收益 − 沪深 300 收益 ≥ 2%

减掉大盘收益,等于把市场 beta 从标签里剥掉,逼着模型只学「选股 alpha」——它不再能靠「猜大盘」混精度了。

这是整个项目最重要的一次修改。后面所有的正确,都始于这个标签。

第二个坑:随机切分在时间序列上就是作弊

改完标签,精度还是莫名偏高。我又挖了几周,挖出一个更隐蔽的 bug:时间序列泄漏

我的标签是「未来 20 天」算出来的。而我在用最普通的随机 train_test_split——训练集和验证集在时间上互相穿插。这意味着:训练集最后 20 天的标签里,掺着验证集前 20 天的价格。模型在验证时偷看了未来的答案,精度虚高 5~10 个百分点。

修复方案:封禁切分(embargo)。

train / val / test 之间挖一条 20 天的隔离带(宽度 = 标签周期),隔离带内「标签跨边界」的样本直接丢弃。代价是损失一点数据,换来的是验证集终于干净——精度从「虚高 85%」掉到「诚实 80%」,但这个 80% 是真的能赚钱的

后来我知道这个思路在专业量化圈有名字(Purged CV 一类),当时是自己被坑出来的。

第三个坑:出场周期必须等于标签周期

标签是 20 天的,但我贪心:拿 20 天训练的信号,5 天就卖,想着「快速复利、多跑几轮」。

回测数据把这条路线证伪得干干净净(同一模型,只改持有期):

持有期 年化 回撤 胜率
20 天 +18.6% -31% 96%
10 天 +15.7% -93% 88%
7 天 +11.1% -95% 76%
5 天 +8.2% -97% 68%

年化随持有期单调递增,5 天方案回撤接近归零。原因很直白:alpha 写在 20 天的标签里,你 5 天就离场,等于把还没实现的 alpha 掐死在半路。而「多跑几轮」也是幻觉——实测交易次数几乎没变(1.68 年里 23 次变 25 次),因为真正的瓶颈是信号本身的稀缺,不是周转速度。

标签是多久,就持有多久。标签周期 = 出场周期,这是硬约束。

第四个坑(反直觉):去掉止损,业绩反而变好

风控直觉告诉我必须设止损,我设了 -3%。直到我做压力测试对比:

窗口 带止损 无止损(20天到期)
2022 熊市 超额 +64.9%,胜率 61% 超额 +80.0%,胜率 79%
2023-24 阴跌 超额 +34.6%,胜率 46% 超额 +47.2%,胜率 80%

止损在震荡市里频繁「底部震仓洗出去」——卖在坑里,模型选出的相对强势股随后修复,我已不在车上。

我最终的无止损方案长这样:+5% 止盈;涨 4% 激活移动止盈(高点回撤 4% 卖);20 天到期强制离场。用时间止损替代价格止损,和 20 天标签严格对齐。

当然要说明:这个结论只在我的标签体系下成立,别当成普适真理抄走。

顺便说下工程侧:全 A 股面板是怎么塞进 16G 内存的

这段没有前面精彩,但对想复现的人很实用。全 A 股 11 年日线,构建特征面板后 980 万行 × 180 列,parquet 5GB,pandas 读进来直接膨胀到 35GB——16G 服务器反复 OOM。

不换机器的解法三件套:

  1. 列过滤读取read_parquet 只读特征选择后的 117 列,parquet 是列式存储,不读的列根本不碰磁盘,35GB → 8GB
  2. 分块推理:200 万行测试集按 20 万一块逐块预测,峰值内存压到 4GB 以下
  3. 分层抽样训练:全量跑不动的模型(如 Logistic)按类别比例抽 50 万行训练

结果:980 万行面板从「跑不动」到训练 12~15 分钟、推理不到 1 分钟。单机能解决的事,别上分布式——我当时评估过 Spark,I/O 反而成为新瓶颈。

最终方案和诚实的成绩单

现在的架构一句话:LightGBM + XGBoost + Logistic 三模型独立训练、等渗校准,几何平均共识打分,soft@0.60 阈值出信号,次日开盘等权买入(mp=3 分仓),+5% 止盈 / 移动止盈 / 20 天到期。候选池剔除 ST、退市风险、科创板、北交所。

回测(滚动训练、含 T+1 规则):

回测期 时长 策略 NAV 沪深300 超额 年化
主回测(牛+震荡) 1.68 年 +31.1% +25.2% +5.9% +17.4%
熊市 2023-24 2.00 年 +48.4% +1.2% +47.2% +21.8%
熊市 2022 0.99 年 +59.0% -21.1% +80.1% +59.7%

两个必须泼的冷水:

  • 实盘要打五折。 回测假设 100% 成交、零滑点。滑点、不全成交、手续费、执行延迟全算上,我的实盘预期是年化 +8~15%,最大回撤 -30~50%。谁跟你吹回测数字不打折,谁就是在骗你——包括骗你自己。
  • 2022 那个 +59.7% 是极值,急跌后 V 型反弹吃到的,不可外推。

复盘:精度为什么会骗人

回头看,85% 精度和亏 82% 同时为真,不矛盾——「精度」只衡量预测对不对,不衡量预测对的时候你赚多少、错的时候你亏多少。而这两件事由标签设计、验证方法、出场规则决定,跟模型关系反而最小。

如果只让我留三句话:

  1. 标签定义了问题:绝对收益标签学的是大盘,相对收益标签才是在学选股
  2. 验证必须服从时间:时间序列上用随机切分,等于允许模型偷看答案
  3. 出场周期对齐标签周期:alpha 写在标签里,提前离场就是亲手掐灭它

机器学习那部分(三模型共识、等渗校准)反而是整个项目里最不用动脑子的环节。量化里最难的部分不是建模,是定义「对」


本文为个人研究复盘,所有数据来自历史回测,不构成任何投资建议。股市有风险,入市需谨慎。

评论