跳到正文

Meta-Labeling:方向与仓位

两个模型胜过单个模型。主模型决定方向(多、空、不交易),次级模型决定仓位(满仓、半仓、零仓)。Meta-labeling 把方向和置信度分开。

第 12 篇 · 共 12 篇 约 11 分钟

Meta-Labeling:为什么两个模型胜过单个

单个模型同时预测“买”还是“卖”,相当于在同时做两件事:决定交易方向,又决定仓位大小。这两件事对信息的需求不同。一个 60% 正确率的模型,和一个“满仓时 60% 正确”的模型不是一回事。同一个模型,用半仓的话,预期 P&L 减半,波动率也减半。应该加仓还是减仓,取决于置信度,不是方向。

Meta-labeling 把问题拆成两块。主模型预测方向:做多、做空还是不做?次级模型预测 meta-label:主模型的预测是否正确?次级模型的输出变成仓位大小。

参考是 AFML 第 3 章,§3.6–3.7。这一节短而密。大部分价值在于框架,不在数学。

(López de Prado, M., Advances in Financial Machine Learning, 第 3 章,§3.6–3.7。ISBN 978-1119482086。)

架构

三个组件。

主模型:预测方向。输出是 −1-1、00 或 +1+1。在三重障碍标签上训练。主模型的职责是识别交易机会。不需要校准,只需要方向上比随机更对。

次级模型:预测主模型是否正确。输出是 [0,1][0, 1] 之间的概率。在 meta-labels 上训练:给定主模型做了预测,主模型是否预测对了?次级模型负责估计置信度。

仓位管理:把次级模型的输出映射到仓位大小。0.7 的概率可能映射到 70% 资金;0.55 的概率可能映射到 10%。映射关系是超参数。

伪代码架构:


side = primary_model.predict(X[t])             # -1, 0, or +1
if side != 0:
    confidence = secondary_model.predict_proba(X[t])
    size = confidence_to_size(confidence)
    execute_trade(side=side, size=size)

主模型是二分类(如果包含不交易,则是三分类)。次级模型是在条件集合“主模型预测非零”上的二分类。

为什么这样能起效

三个理由,每个都基于金融数据的实际行为。

理由 1:两个模型目标不同。

主模型追求方向准确率。它想尽量多地对。它不在乎置信度:51% 置信的预测和 99% 置信的预测都得到同一个 +1+1 标签。

次级模型追求预测“主模型是否对”,前提是主模型做了预测。它在乎置信度。51% 置信的主预测应该降权;99% 置信的主预测应该加仓。

这种分离让每个模型都更容易训练。主模型损失更简单(方向上的交叉熵)。次级模型损失不同(正确性上的交叉熵)。把它们合成一个多目标模型,比训练两个专家更难。

理由 2:两个模型可以用不同特征。

主模型用预测方向的特征:动量、价值、情绪、宏观。次级模型用预测置信度的特征:状态指标、波动率、交易时段、微观结构。两套特征往往是不相交的。

举个例子,主模型可能用 20 天动量信号。次级模型可能用过去 5 天的实现波动率,因为近期高波动率说明主模型的信号更不可靠。特征不同,是因为目标不同。

理由 3:仓位管理处理了风险管理。

单模型策略的常见失败模式:每笔交易仓位一样。无论赚亏,策略都投入同样多的资金。只有在每个预测的置信度都相同时,这才能算最优,但实际几乎从来不成立。

Meta-labeling 修复了这一点。次级模型给出 0.55 置信度的主预测,是半仓交易;给出 0.95 置信度的主预测,是满仓交易。每单位风险的预期 P&L 在不同交易之间更均匀,策略整体夏普也更高。

(AFML, §3.6.1–3.6.2。)

Meta-Label

Meta-label 定义为:主模型的预测是否正确。

mi=1[primary prediction at time ti matches realized outcome at ti+h]m_i = \mathbb{1}[\text{primary prediction at time } t_i \text{ matches realized outcome at } t_i + h]

对多空策略:如果主模型说“多”,价格涨了(或说“空”,价格跌了),那么 mi=1m_i = 1,否则 mi=0m_i = 0。

有一个细节:meta-label 只在主模型做了预测的时刻计算。如果主模型在时点 tt 预测“不交易”,那么 tt 就没有 meta-label。这点很重要:次级模型是在条件分布 P(正确∣主模型预测)P(\text{正确} | \text{主模型预测}) 上训练,不是边缘分布 P(正确)P(\text{正确})。

实际中:

meta_labels = []
for t in times_when_primary_predicted:
    prediction = primary_model.predict(X[t])
    actual = realized_outcome(t)
    meta_labels.append(1 if sign(prediction) == sign(actual) else 0)

次级模型在这些 meta-labels 上训练。

(AFML, §3.6.3。)

训练次级模型

三个步骤。

步骤 1:在样本外数据上生成主预测。

主模型应该在一个训练集上拟合,meta-labels 应该在另一个集合上计算(通常是用于主模型超参数选择的验证集)。如果在主模型的训练集上算 meta-labels,次级模型会学到预测样本内准确率,但样本内准确率总是很高,没有信息量。

一种干净的做法:走 walk-forward 交叉验证。在数据 [0,T1][0, T_1] 上拟合主模型,在 [T1,T2][T_1, T_2] 上预测,记录主预测和实际结果。然后在 [0,T2][0, T_2] 上重新拟合主模型,在 [T2,T3][T_2, T_3] 上预测,以此类推。每个主预测都是真正样本外的。Meta-labels 由这些样本外预测算出。

步骤 2:在 meta-labels 上训练次级模型。

次级模型的特征通常和主模型一样,再加上一些和置信度相关的特征(波动率、状态指标)。目标是 meta-label。

常见做法:次级模型用简单、有正则化的模型(带 L2 正则的逻辑回归)。主模型可以用更复杂的(梯度提升、神经网络);次级模型应该保守。

步骤 3:校准次级模型。

次级模型的输出应该是校准后的概率:说 0.7 的时候,主模型在样本外应该有 70% 的概率正确。用 Platt 缩放或 isotonic 回归做校准。

校准为什么重要:仓位管理是次级模型输出的函数。如果输出没有校准,仓位就不对,策略的风险敞口也不是你设计的样子。

(AFML, §3.6.5。)

仓位管理函数

把次级模型输出映射到仓位大小的函数。三种常见形式。

线性:size = p,其中 pp 是次级模型输出。0.7 的概率变成 70% 仓位。简单,但 0.51 概率也会有 51% 仓位,可能过于激进。

截断:size = 0 当 p<pmin⁡p < p_{\min},size = 1 当 p>pmax⁡p > p_{\max},中间线性插值。阈值是超参数。这样可以避免在边缘交易上下注。

幂函数:size = p^k,k>1k > 1。0.7 概率变成 0.72=0.490.7^2 = 0.49 仓位。幂函数对低置信度预测降权更激进。当你想把资金集中在高确信度交易上时很有用。

实务中的常见选择:截断形式,pmin⁡=0.55p_{\min} = 0.55,pmax⁡=0.85p_{\max} = 0.85。低于 0.55,不交易(这会过滤掉边缘预测)。高于 0.85,满仓(你已经足够确信可以部署全部资金)。中间线性插值。

更精细的选择:在验证集上同时优化阈值和函数形式,用夏普或其他风险调整后收益指标作为目标。

一个重要性质:仓位不影响方向

Meta-labeling 架构有一个重要性质:仓位不影响方向。被设为 10% 仓位的交易仍然是多头(或空头)。主模型的预测没变。

这很重要,因为它意味着主模型的准确率不会因为仓位管理而改变。如果主模型 55% 的时候是对的,那么无论怎么调整赚亏的仓位,它都是 55% 的时候是对的。Meta-labeling 带来的夏普提升完全来自仓位:高置信度赚的交易满仓,低置信度赚的交易小仓位,低置信度亏的交易变成不交易(仓位为零)。

对比单模型架构,模型输出 [−1,+1][-1, +1] 之间的连续预测,仓位就是预测的绝对值。在这种架构下,方向和仓位是耦合的:预测 −0.3-0.3 是小空头,预测 −0.9-0.9 是大空头。如果模型校准良好,这也能工作。但大多数模型校准得不好,耦合会带来问题。

Meta-labeling 把两者解耦,每个模型都更容易讲清楚。

(AFML, §3.6.4。)

完整例子

设定:美国大盘股多空策略,日频再平衡,持仓期 5 天。主模型是用三重障碍标签训练的梯度提升分类器。特征包括 20 天动量、60 天均值回归、价值、质量和几个行业哑变量。

主模型输出:−1-1(空)、00(不交易)或 +1+1(多)。在带 k=1k = 1 障碍的三重障碍标签上训练。

次级模型:带 L2 正则的逻辑回归,在 meta-labels 上拟合。特征和主模型一样,加上实现波动率和一个状态指标(基于 200 天均线的牛市/熊市)。

仓位管理:size = 0 当 p<0.55p < 0.55;size = (p - 0.55) / 0.30 当 0.55≤p≤0.850.55 \leq p \leq 0.85;size = 1 当 p>0.85p > 0.85。

在 2010–2024 上走 walk-forward 验证,主模型每个季度重拟合,次级模型每年重拟合。

结果(示意,不是真实回测):

  • 单用主模型:53% 准确率,夏普 1.2。
  • 主模型 + 等权:和上面一样。
  • 主模型 + meta-labeling:53% 准确率(不变),但因为加了仓位管理,夏普 1.7。

准确率不变是因为主模型的预测没变。夏普提升是因为资金集中在高置信度交易上。次级模型不确定的交易变成不交易;次级模型确信的交易得到满仓。

夏普提升 0.5 比较典型。在某些策略上,可能提升 1.0 甚至更多。

常见陷阱

反复出现的五种陷阱。

陷阱 1:在样本内主预测上训练次级模型。

如果主模型在 [0,T][0, T] 上拟合,次级模型也在主模型在 [0,T][0, T] 上的预测上拟合,那么次级模型学到的是预测样本内准确率,但样本内准确率高且无信息。要用 walk-forward:主模型在 [0,T1][0, T_1] 上拟合,主预测在 [T1,T2][T_1, T_2] 上做,次级模型在这些样本外预测上拟合。

陷阱 2:两个模型用相同的特征。

主模型用预测方向的特征。次级模型应该用预测置信度的特征,两者可能有重叠但不应完全相同。至少加 2–3 个专门预测置信度的特征:波动率、状态、交易时段、微观结构。

陷阱 3:把 meta-label 和方向预测混淆。

Meta-label 是“主模型是否对”,不是“市场是否涨”。如果主模型说“多”,市场涨了,meta-label 是 1(正确)。如果主模型说“多”,市场跌了,meta-label 是 0(错)。如果主模型说“不交易”,就没有 meta-label。

陷阱 4:忘了对“不交易”不施加仓位。

如果主模型说“不交易”,次级模型不跑。仓位为零。这是对的。

陷阱 5:在低准确率主模型上使用 meta-labeling。

Meta-labeling 能改进 53% 准确率的主模型。但它不能把 51% 准确率的主模型变成赚钱的策略。在 meta-labeling 起作用之前,主模型的基础正确率需要高于 50%,理想情况是高于 53%。低于 50%,次级模型基本就是噪声。

什么时候不用 Meta-Labeling

三种情况。

情况 1:主模型准确率很高(>70%)。 如果主模型 70% 以上的时候是对的,仓位管理就不太重要。你可以等权下注,仍然能拿到不错的夏普。

情况 2:需要连续仓位管理。 如果策略做的是连续仓位管理(例如风险平价或波动率目标),meta-labeling 的二元仓位可能不合适。改用连续仓位管理模型。

情况 3:交易成本占主导。 如果策略换手率高到交易成本超过 meta-labeling 带来的收益,就跳过次级模型。主模型的高换手会吃掉收益。

其他大多数情况下(特别是日频再平衡的多空股票、外汇或期货策略),meta-labeling 都值得引入这种额外的复杂性。

一个微妙的实现细节

训练次级模型时,要小心一件事:次级模型应该用样本外的主预测训练,不能用样本内预测。

标准工作流:

  1. 用净化后的 walk-forward CV 把数据分成训练集和测试集(参见交叉验证一文)。
  2. 在训练集上拟合主模型。
  3. 在测试集上生成主预测。
  4. 从测试集的实际结果计算 meta-labels。
  5. 在(测试集特征,meta-labels)上拟合次级模型。

第 5 步用了测试集,对主模型来说是样本外,但对次级模型来说是样本内。为了避免泄露,要用嵌套交叉验证:

  1. 外层 CV:分成训练/测试。
  2. 内层 CV 在训练集上:拟合主模型,在内层验证折上生成预测,计算 meta-labels,拟合次级模型。
  3. 把两个模型都应用到外层测试集。

这在计算上很贵,但能产生一个诚实的 meta-labeling 系统。简单的单层做法在实务中也能用,但会引入一些乐观偏差。

一个折中:使用单次 walk-forward 切分。在 [0,T1][0, T_1] 上拟合主模型,在 [T1,T2][T_1, T_2] 上生成主预测,在这些预测上拟合次级模型。这样能用一层 CV 产生一个诚实的次级模型。偏差很小。

(AFML, §3.6.5。)

多分类 Meta-Labeling

标准 meta-labeling 有两类(正确、错误)。对多分类主模型(例如多、空、不交易),meta-labeling 可以扩展到多类:

  • 如果主模型选中了赢的类,meta-label = 1。
  • 如果主模型选中了亏的类,meta-label = 0。

对三类(多、空、不交易),meta-label 是二值的:主模型的类是否是赢家。次级模型是(特征,主类)上的二分类。

仓位管理依赖 meta-label 和主类。高置信度的“多”预测(meta-label 概率 0.7)满仓。高置信度的“空”预测(meta-label 概率 0.7)满仓。高置信度的“不交易”预测(meta-label 概率 0.7)……不仓位,因为主模型已经说了不交易。

多分类扩展很直接,应用的就是同一个原则:把方向和仓位分开。

SNO 框架

AFML 中还有一种相关框架:Sequential No-Trade(SNO)。思路是:让主模型只输出两类(多、空),用 meta-model 决定是否交易。

SNO 框架:

  1. 主模型:预测多 vs 空(二分类)。
  2. 次级模型:预测是否交易(二分类:交易或不交易)。
  3. 仓位管理:结合两个预测。

优势是:主模型更简单(二分类而不是三类)。次级模型可以用主模型没有的特征。

典型实现:主模型在三重障碍标签上训练,多 = +1,空 = -1,丢掉不交易。次级模型训练主模型的预测是否盈利。仓位管理基于次级模型的置信度。

这和 meta-labeling 类似,只是把“要不要交易?”和“哪个方向?”分开。一些从业者觉得这种做法比标准 meta-labeling 更清晰。

(AFML, §3.6.6。)

Meta-Labeling 不解决什么

三件事 meta-labeling 处理不了。

它不创造 alpha。 Meta-labeling 改进的是仓位大小,不是方向。如果主模型不比随机好,meta-labeling 也帮不了。你需要的是一个预期正确率为正的主模型。

它不降低交易成本。 如果主模型换手率高,meta-labeling 不会降低。事实上,如果次级模型波动大,meta-labeling 反而可能提高换手。要额外加换手约束或持仓期约束。

它处理不了容量限制。 如果策略大到足以影响价格,meta-labeling 不会处理市场冲击。要用执行算法或仓位大小约束。

这些是 meta-labeling 的局限,不是批评。Meta-labeling 是工具箱中的一件工具,它在自己的用途上,也就是改进仓位管理,表现很好。

更大的视角

Meta-labeling 是一个更广泛原则的应用:把你预测的事和应该下多少注分开。这个原则适用于量化机器学习的许多领域:

  • 方向 vs 仓位(本文):方向 vs 置信度。
  • 入场 vs 出场:何时进场 vs 何时离场。
  • 选股 vs 权重:选哪些资产 vs 如何加权。
  • Alpha vs 风险:预期收益 vs 预期风险。

每次分离都让你可以在更聚焦的问题上训练一个专家模型,这通常胜过试图把一切都装进一个模型。

Meta-labeling 架构也是经典机器学习中 stacking 的基础:训练几个基模型,再在它们的预测上训练一个 meta-model。Meta-model 学会组合基模型。在金融机器学习里,基模型预测方向,meta-model 预测仓位。想法一样,标签不同。

(López de Prado, M., Advances in Financial Machine Learning, 第 3 章,§3.6–3.7。ISBN 978-1119482086。)