halo 的技术博客

返回

监督学习做方向预测,第一步不是调模型,而是打标签。标签错了,模型再花哨也是在对噪声过拟合。

最朴素的标签是「明天涨了标 +1、跌了标 −1」。它的问题很致命:它只看期末一个点的符号,把中途涨 5% 又跌回来的路径,和一路阴跌的路径当成同一类;它还把「涨 0.1%」和「涨 10%」都叫 +1,信息损失巨大。更隐蔽的是,这种标签天然和近期收益高度相关,模型很容易学到「昨天涨今天就涨」这种伪规律。

本文用两段真实计算(8 年日度合成序列、MA 金叉主信号)讲清两件事:Triple Barrier 怎么把路径信息编码进标签,以及 Meta-Labeling 怎么让机器学习「这次该不该真的下注」。所有数字和配图都由文末代码真实生成。

一、Triple Barrier:用三条边界定义一次交易的结果#

对每一个入场点 tt,我们同时画三条边界:

  • 上边界(止盈):价格触及 Pt(1+u)P_t(1+u)
  • 下边界(止损):价格触及 Pt(1d)P_t(1-d)
  • 时间边界:固定持有 hh 个交易日。

t+1t+1 开始往前看,第一个被触发的边界决定标签

  • 先触上边界 → 标签 +1+1(做多止盈);
  • 先触下边界 → 标签 1-1(做多止损);
  • 时间到了还没触 → 标签 00(到期平仓)。

关键点在于:标签不再只看「期末价格」,而是看「路径上哪个边界先到」。一段「先冲 +5% 再回落」的行情,会被标成 +1 而不是 0 或 −1——这正是朴素标签丢失的信息。

一条价格路径与三条 barrier:第一个触发的边界决定标签

下面这段是文章所有实验的核心:给定价格序列和三条边界,逐起点扫描 horizon 内第一个触发的边界。

二、标签分布:Triple Barrier 编码了「方向」#

我们用一段约 8 年(2017 个交易日)、年化漂移 8%、波动 18% 的合成 GBM,参数取 h=20h=20 日、u=d=5%u=d=5\%,把 Triple Barrier 标签和朴素「20 日后符号」标签放在一起比:

  • Triple Barrier:+1=498+1=4980(到期)=8790(\text{到期})=8791=620-1=620
  • 朴素标签:涨 =868=868、平 =0=0、跌 =1129=1129

Triple Barrier 标签分布 vs 朴素标签分布

差别很明显:朴素标签把一切塞进「涨/跌」二元,而 Triple Barrier 多出一个 00 类——它表示「这 20 天里价格既没冲到 +5% 也没跌破 −5%,在中间晃荡」。这一类在风险管理里极其重要:它对应的是「信号失效、该少动」的区间,朴素标签完全看不见它。

三、风险封顶:单笔收益被边界锁死#

把标签直接变成交易规则:标签 +1+1 就赚 +u+u,标签 1-1 就亏 d-d,标签 00 拿到期末收益。对比「无脑持有 20 日」:

指标Triple Barrier 策略朴素持有 20 日
单笔均值−0.417%−0.605%
单笔 Std4.07%5.10%
胜率44.8%43.5%
最差单笔−5.0%(被下边界封死)−14.0%

每笔交易收益分布:Triple Barrier 把单笔亏损/盈利锁在边界内

Triple Barrier 的均值略高、波动更低,最关键的差异在右尾被砍掉:朴素持有会出现 −14% 的灾难单笔,而 Triple Barrier 最惨也就 −5%(下边界)。换句话说,标签本身就是一道风控——它把每笔交易的最大亏损/盈利预先钉死,逼着策略讨论「该不该承担这笔风险」,而不是赌一个遥远的期末价格。

四、元标签 Meta-Labeling:让 ML 决定「下不下注」#

到这里有个分工问题。主模型(比如均线金叉、动量)擅长回答方向,但它不擅长回答时机和规模。López de Prado 的元标签框架非常巧妙:

  1. 主模型给一个副作用信号(如 MA20 > MA50 → 看多);
  2. 用主信号方向的 Triple Barrier 是否先触上边界二元标签 y{0,1}y\in\{0,1\}(盈利=1,否则=0);
  3. 训练一个元模型,用波动率、RSI、成交量异常、动量、价格偏离度等辅助特征预测 yy
  4. 实战中:只在主信号看多、且元模型预测盈利概率高时,才真的下注

方向交给可解释的主模型,时机/规模交给 ML——既保留了主模型的经济含义,又用数据过滤掉「看多但不该动」的噪声交易。

我们在一个真实的弱主信号上验证。主信号是 MA20/MA50 金叉(长期看它在本样本里其实是亏损的),元模型用 5 个特征训练逻辑回归,按时间切分训练/测试。测试段 233 笔主信号交易里,盈利占比仅 22.3%,元模型测试 AUC=0.620——排名有真实技能,但校准偏弱(平均预测概率 0.28,全部低于 0.5)。因此我们用标准做法:按预测概率取前 50% 下注,而不是硬卡 0.5 阈值。

主信号全仓 vs 主信号 + 元标签过滤的权益曲线

结果(测试段,逐笔复利):

策略下注笔数终值最大回撤单笔均值Sharpe
主信号全仓2330.142−91.9%−0.750%−2.91
元标签过滤1170.917−67.1%+0.014%+0.05

元标签没把亏损变盈利,但它把一个灾难性的策略(−86% 终值、−92% 回撤)改造成了接近盈亏平衡(−8% 终值)、回撤收缩 25 个百分点、交易次数减半的版本。元标签的价值从来不是「点石成金」,而是「把仓位集中在更可能盈利的那一半信号上」——在弱信号上,这一点就值回票价。

五、完整实现(串起来)#

train_logistic / predict 用 numpy 梯度下降实现即可(标准化后用学习率 0.05、迭代 3000 次),不依赖任何外部库——这正是本专栏「纯 numpy 可复现」的一贯做法。

六、真实陷阱(踩坑清单)#

  1. 前视偏差:Triple Barrier 的「第一个触发点」必须只用到 tt 之后的价格,但特征里绝不能混进未来的量(如用期末波动率当特征)。特征与标签同源,等于把答案塞进题目。
  2. 标签不平衡:对称边界下,时间边界触发往往最多(本文 00 类占 44%),直接训练元模型会退化成「永远预测 0」。务必用时序切分 + 校准/排序阈值,而非朴素卡 0.5。
  3. 参数敏感u/d/hu/d/h 决定一切。边界太窄→几乎全触发,太宽→几乎全到期;horizon 太长→标签被噪声淹没。它们本质是止损/止盈/持有期的交易假设,要和经济意义一起调。
  4. 成本吞噬:本文标签是基于毛收益的。实盘里小盈(如 +0.3%)被手续费和冲击成本一刮就变亏,元标签应以净收益而非毛收益为标签。
  5. 过拟合主信号噪声:元模型若用 Purged K-fold 以外的普通交叉验证,会因为有重叠的滚动窗口而产生信息泄漏(这是另一个大主题)。本例用严格时序切分规避,但多标的、多参数扫描时务必上 purged CV。

七、结论#

标签工程是机器学习量化的「第一公里」。Triple Barrier 把「路径」还给了标签,让模型学到的是「这笔交易怎么结束」而非「期末一个点的符号」;Meta-Labeling 则把 ML 放在它最擅长的地方——给一个已有方向信号做「该不该下注」的二级判断。二者合起来,你的因子/信号负责「看哪里」,ML 负责「什么时候扣扳机」,各司其职,也比端到端黑箱更可解释、更抗过拟合。


所有图表与统计数字(标签分布、单笔收益、元标签 AUC 与权益曲线)均由 generate_triple_barrier_images.py 真实计算生成。

标签工程:Triple Barrier 与元标签(Meta-Labeling)在机器学习量化中的应用
https://blog.halo26812.eu.org/blog/triple-barrier-metalabeling
Author halo
Published at 2026年7月12日
版权声明 CC BY-NC-SA 4.0
Comment seems to stuck. Try to refresh?✨