这个现象在量化里特别典型:模型会优先学“最容易降低 loss 的信号”,而这些信号往往是:
- 不可交易(跌停 / 停牌 / 流动性太差、成交冲击巨大)
- 不允许暴露(行业 / 风格 / beta 太强,后面优化器会剪掉)
- 看起来很准但其实是泄露 / 同步信息(时间戳没对齐、用到了收盘后才能知道的东西)
想让训练“无偏”(更准确说:对齐你最终能落地的 alpha key driver),常用办法可以按“从简单到高级”分四类:
1) 先把“不可实现的部分”从数据层面关掉
这是性价比最高的一步(很多时候比改 loss 更有效):
- 严格可交易过滤:跌停 / 停牌 / 一字板 / 极端流动性日,直接把这些样本从训练或 label 里 mask 掉(不参与 loss)。
- 时间戳对齐:特征只用你下单前能拿到的版本;label 也按你真实成交价/成交时点定义。
- 训练集的股票池 = 实盘股票池:别让模型在训练时学到“小票、低流动性”带来的虚假 alpha。
这一步的目的:别让模型把“你根本做不到的收益”当成最省力的捷径。
2) 让 label 变成“你真正想赚的东西”
如果 label 本身就是“毛收益”,模型天然会偏向那些 毛收益很大但成本也很大 / 不可交易 的点。
常见更贴近落地的 label 设计:
- 净收益 label:用
未来收益 - 预估交易成本(冲击 + 手续费)
做 label(哪怕是粗糙成本模型也比没有强)。 - 排序型 label(Rank / LTR):你最终是选股+组合,很多时候“排序正确”比“点值预测准”重要。
- 残差 / 去暴露后的 label:比如先把未来收益对行业 / 风格 / beta 回归,拿 residual 当 label(对应“特质 alpha”)。
3) 在 loss 里直接“惩罚捷径”
重点:怎么让模型别学到不该学的 driver。
A. 暴露惩罚(你们很适用:行业也约束)
在 loss 里加一项:让模型输出分数与行业/风格暴露“不要太相关”:
- 惩罚
corr(score, style_expo)、corr(score, industry_dummy) - 或惩罚组合层面的暴露(用一个简单可微的“从 score 到权重”的映射做代理)
直觉:模型想靠行业赚钱 → loss 会痛 → 它就会去找更“特质”的解释。
B. 成本 / 换手惩罚
如果你们最终受换手/冲击成本约束,训练里就把“频繁变动”变贵:
- 惩罚
|score_t - score_{t-1}|(时间平滑) - 或更接近持仓层:惩罚
|w_t - w_{t-1}|的代理项
C. 分组损失(防止模型只做行业轮动)
比如在行业内做 pairwise 排序 loss:
让模型学“同一行业里谁更好”,而不是“行业 A > 行业 B”。
D. 对尾部样本的稳健损失
Huber / Quantile 之类,让极端点不会主导梯度(避免模型为了少数极端样本扭曲常态)。
4) 更高级但更强:把“优化器目标”拉进训练(近似端到端)
“label 考虑风险约束”等,这条路能走,但通常不直接把“优化器输出收益”当 label,而是:
- 用一个 可微的近似组合构建层(比如 softmax 选股、或简单约束投影)
- 在训练目标里直接优化一个 组合层指标(例如:风险调整后的收益代理、或 IC 但带暴露惩罚)
优点:目标对齐
缺点:工程复杂、容易不稳定,需要强验证
一句话总结
要让模型不走捷径,最稳的顺序是:
先 mask 不可交易 → 再把 label 变成“净的 / 残差的” → 再加暴露与换手惩罚 → 最后再考虑端到端。
