Double Machine Learning:估计因果参数而非预测收益
本博客至今所有建模文章都提出同样形态的问题:给定特征,预测一个数字,然后验证该预测在样本外成立。价差模型预测价差。成交模型预测成交概率。整个验证机制——清理的 walk-forward、缩水的 Sharpe、前瞻分类——的存在是为了检查预测是否真实。
本文提出不同形态的问题,这是博客从未拥有的唯一机械部分:估计具有因果解释的单一纯量参数,并为其附上一个标准误,该误差在到达该点时使用了灵活 ML 模型的情况下仍然有效。
这不仅仅是修辞上的区别。「队列位置预测成交概率」显然正确但操作上无用——当然如此,两者都由深度和波动性驱动。「在队列中前进一个位置导致成交概率变化 ,保持市场状态不变」这是一个可以放入订单放置政策的数字。前者是回归拟合。后者需要一个不存在于标准 ML 工具箱中的估计器,因为灵活第一阶段的正则化和过拟合会使您关心的系数产生偏误。
Double Machine Learning (Chernozhukov, Chetverikov, Demirer, Duflo, Hansen, Newey & Robins, 2018) 是修正此问题的估计器。每个量化交易员都听说过:相关性不意味因果性。DML 是这句话之后的部分。
为何朴素回归失败

在博客自己的领域中建立问题。我们想要队列位置对成交概率的因果效应:
- :观测 处的休市限价单是否在时间范围内成交。
- :放置时的队列位置(由层级大小标准化)。
- :干扰因素——实现波动性、报价价差、深度不平衡、层级大小、一天中的时间、制度标签。这些是博客已经在 spread modeling with machine learning 中计算的市场状态变量。
因果参数是 ,在
其中 捕捉市场状态与成交结果之间的(可能复杂、非线性)关系。
处理并非随机分配。您位于队列前列是因为层级薄,或因为您在平静时期发布,或因为订单簿对您有利。相同条件独立驱动您是否成交。这就是干扰。
方法 1:忽略干扰因素。 将 对 单独回归。估计吸收与两者都相关的每个干扰因素的效应。教科书式的遗漏变量偏误:薄层级既给您好的队列位置又给您高成交率,因此您夸大了位置本身的价值。
方法 2:带控制的线性回归。 将 对 和 回归。这仅在 真正线性时才有效。订单簿动态并非如此——成交/波动性关系有阈值,深度不平衡效应按制度翻转符号。错误指定 会重新引入偏误。
方法 3:ML 预测。 在 上拟合梯度提升模型。您获得良好的样本外判别,但完全没有因果解释。模型捕捉每个预测模式,无论因果与否;正则化以偏误 的方式缩小处理的贡献;且没有可信赖的标准误。
这是核心张力。ML 擅长预测,但对因果参数的朴素应用会产生偏误、非正态、不可靠的估计。
部分线性模型

DML 在结构框架内运作。主力是部分线性回归 (PLR):
- 是感兴趣的因果参数。
- 是烦函数——结果中由市场状态解释的部分。
- 是另一个烦函数——给定市场状态的处理条件期望(连续处理设置中的「propensity」)。
- 和 是结构残差。
关键见解: 是低维的,但 和 可以任意复杂。我们希望 ML 处理烦函数,同时在标量上提供有效推断。
为何「双重」?
两个 ML 模型,不是一个:
- 结果模型: —— 仅从市场状态预测结果。
- 处理模型: —— 仅从市场状态预测处理。
形成残差
并通过将 对 回归来估计 :
这是 Frisch-Waugh-Lovell 的加强版:用 ML 而非线性投影将干扰因素部分化,然后从残差变异中读取处理效应。
Neyman 正交性:为何有效
朴素部分外方法(估计 ,减去,回归)失败,因为 中的 ML 估计误差直接传播到 。DML 分数构建为 Neyman 正交——对烦函数中的小干扰不敏感。
PLR 的正交分数:
其中 。正交条件是
直观上,分数仅使用 和 中独立于 的变异,且一个烦函数中的误差被另一个补偿。如果 稍微过高预测处理, 稍微太小,但来自错误估计 的 中对应误差会向补偿方向推动。偏误变成二阶——两个第一阶误差的乘积——而非一阶。
正式地,如果两个烦扰估计器以 速度收敛(温和;大多数合理的 ML 方法通过),则
因此 以参数速度收敛且渐近正态。
交叉拟合:为何在此必须
仅正交性不够。如果烦扰模型在用于估计 的相同行上拟合,第一阶过拟合会污染第二阶段——具体伤害值得精确说明,因为它不是您习惯的伤害。在其他地方,过拟合作为膨胀的验证分数出现:您注意到它,您打折它,您继续。在这里它作为 的偏移点估计出现,伴随仍然狭窄且仍然以错误数字为中心的置信区间。没有可疑的分数。估计器只是安静地撒谎。
交叉拟合打破依赖:每个观察的烦扰预测来自未包含它的模型,且 从池化的 held-out 残差估计。机制是普通的 K-fold 机械,在 spread modeling with machine learning 中涵盖;下面重要的是您给它哪些折叠。
DML 算法逐步
输入:数据 ,ML 方法 和 ,折叠
步骤 1 —— 分割:将 分割为 个不相交折叠。
步骤 2 —— 交叉拟合烦扰模型:对于 ,在折叠 的补集上训练 和 ,然后对于 计算 和 。
步骤 3 —— 估计:
步骤 4 —— 推断:
带有区间 。
置信区间仅对一个问题有效
这是决定 DML 结果是否有价值的警告,也是大多数该方法应用默默崩溃的地方。
上述渐近正态性是关于一个预先指定的处理、一个预先指定的干扰因素集、一个预先指定的分数的陈述。预先固定这些,运行估计器一次,区间意味它所说的。尝试三个候选处理,或四个干扰因素集,或交换学习器直到 p 值看起来更好,您就不再在做推断——您在运行搜索,报告的 p 值是最大值的 p 值,不是单次抽样的。
博客已经测量了这样做的效果。在 the deflated Sharpe ratio study 中,在零真实边缘的纯噪声上的搜索产生 1.000 的朴素虚假发现率——未调整测试每次都触发——而赢家的中位数朴素 p 值接近 0.0007。关于 Neyman 正交性的没有任何保护您免受此害。正交性修正烦扰估计的偏误;它没说规格搜索的偏误。在尝试六个规格后获得的 1e-05 DML p 值,完全应该获得与任何其他从网格中提取的赢家相同的 Bonferroni/Holm/BHY 处理,其中 设置为您实际运行的规格数量。
这对工具的便利特性有直接的实际后果。DoubleMLData 接受 d_cols 中的列表,并会在一个摘要表中愉快地返回三个处理效应:
dml_data_multi = dml.DoubleMLData(
df, y_col='filled', d_cols=['queue_pos', 'toxicity', 'spread_at_post'],
x_cols=confounder_cols,
)
三行、三个 p 值,以及摘要表未提及的多重测试问题。如果您读取全部三个,请调整全部三个。如果只有一个是预先注册的问题,请这样说,并明确将其他两个视为探索性。
时间序列上的交叉拟合:清理、禁运、自定义折叠

标准 DML 假设 i.i.d. 观察。订单簿数据不是,失败模式是博客已经详细记录的模式:相邻行共享重叠的前瞻窗口,因此简单的 TimeSeriesSplit 仍然会跨越折叠边界泄漏答案。参见 spread modeling with machine learning 以了解清理的禁运 walk-forward 实现以及为何需要至少 horizon 行间隙的原因,以及 the look-ahead bias taxonomy 以了解完整的泄漏目录及其测量幅度。
真正的 DML 特定部分是如何将清理的折叠交给估计器,因为 set_sample_splitting 有一个让人绊倒的契约:
import numpy as np
import doubleml as dml
def purged_folds(n: int, n_splits: int, horizon: int):
"""带有 `horizon` 行清理/禁运间隙的扩展窗口折叠。
与 spread-modeling 文章中清理的 walk-forward CV 相同构造:
间隙移除训练行前瞻窗口与验证行之间的重叠。
"""
fold_size = n // (n_splits + 1)
for k in range(1, n_splits + 1):
train_end = fold_size * k
val_start = train_end + horizon
val_end = val_start + fold_size
if val_end > n:
break
yield np.arange(0, train_end - horizon), np.arange(val_start, val_end)
folds = list(purged_folds(len(df), n_splits=5, horizon=HORIZON))
dml_plr = dml.DoubleMLPLR(dml_data, ml_l=ml_l, ml_m=ml_m)
// 元组列表的列表。一次重复:
dml_plr.set_sample_splitting([folds])
dml_plr.fit()
需要注意两件事,没有一件从库文档中明显:
-
清理的 walk-forward 折叠不覆盖每一行。 清理间隙和初始训练块从不是任何人的测试折叠,因此 从严格少于 个残差估计。这是正确行为,不是错误,但这意味着方差公式中的有效 是池化测试行的数量——检查它而非假设。
-
n_rep重复在此不 free。 对随机 K-fold,重复交叉拟合和平均是廉价的方差减少。对确定性时间顺序分割只有一个分割,因此n_rep不购买任何东西也不隐藏任何东西;稳定性必须来自在不同数据窗口上重新运行。
对于面板结构(同期多个符号),DoubleML 支持聚类稳健标准误——按符号聚类,而非按时间,参见 multi-symbol validation 以了解博客关于何时真正确立跨工具结果的立场。
测量案例:队列位置与成交概率

这是文章中项目已经有数据的唯一因果问题,它应该被运行而非提出。队列位置分析 已经涵盖真实订单簿数据上的位置估计、FIFO 机制、排水率和成交时间;成交模拟 涵盖成交概率建模和对实际成交的校准循环。两者都产生成交的预测模型。DML 将相同输入转换为因果估计。
预先注册的规格(在查看估计之前):
- 结果 :在
HORIZON快照内成交(二元)。 - 处理 :放置时的标准化队列位置。
- 干扰因素 :1s 实现波动性、以 bps 为单位的报价价差、深度不平衡、发布时的层级大小、以 tick 为单位的距离中点距离、一天中的时间编码、制度标签。
from sklearn.ensemble import GradientBoostingRegressor
import doubleml as dml
confounder_cols = [
'rv_1s', 'spread_bps', 'depth_imbalance', 'level_size',
'dist_from_mid_ticks', 'tod_sin', 'tod_cos', 'regime',
]
dml_data = dml.DoubleMLData(
df, y_col='filled', d_cols='queue_pos_norm', x_cols=confounder_cols,
)
ml_l = GradientBoostingRegressor(n_estimators=300, max_depth=5)
ml_m = GradientBoostingRegressor(n_estimators=300, max_depth=5)
dml_plr = dml.DoubleMLPLR(dml_data, ml_l=ml_l, ml_m=ml_m, score='partialling out')
dml_plr.set_sample_splitting([folds])
dml_plr.fit()
print(dml_plr.summary)
dml_plr.sensitivity_analysis()
print(dml_plr.sensitivity_summary)
要报告的结果是四列比较,不是单一系数:仅 上 的朴素 OLS 估计、 和 上 的线性控制估计、带有其标准误的 DML 估计,以及灵敏度分析的稳健值——未观察干扰因素需要多强才能使效应无效。朴素和 DML 列之间的差距是真正感兴趣的数量:它是队列位置的表面价值中有多少是市场状态的伪装。
此处的零或负 是可发布的结果,且比干净的正结果更适合本博客。如果一旦波动性和层级大小被部分化,队列位置的因果效应就崩溃,那是关于订单放置政策的直接发现:位置不是赚取成交的东西,获得位置的条件才是。
因子因果分析
因子投资的标准方法是关联的:按特征排序、形成多空投资组合、观察报酬不同。DML 启用不同的测试——估计特征对报酬的直接因果效应,抵消其他特征的干扰效应。如果效应在 DML 下消失,因子不是独立因果;它是代理。
这是因子怀疑论的第二种独立形式,值得明确说明它与博客已经发布的内容的关系。The deflated Sharpe ratio 从选择侧攻击因子动物园:有足够的试验,因子可能看起来显著只是因为您看了很多次。DML 从干扰侧攻击它:因子可能在单次诚实测试上显著,仍然是条件集中其他东西的代理。因子必须通过两者才有意思,且两种失败模式是独立的——通过一个并不告诉您关于另一个的任何事。
DML 不能做什么
-
它要求干扰因素被观察。 如果未观察变量同时驱动处理和结果,DML 有偏,且没有 ML 精致性修正识别问题。灵敏度分析有界风险;它不消除风险。
-
它估计平均效应。 如果队列位置的效应在制度间急剧变化,点估计是您样本制度混合的平均值。对于异质性使用 Interactive Regression Model (
DoubleMLIRM) 或因果森林。 -
它假设结构模型。 部分线性规格要求处理以特定方式进入结果方程。如果真实过程根本不同,DML 自信地错误。
-
它不发现因果结构。 DML 估计预先指定的处理的效应。它不告诉您哪些变量是原因。
-
它不免除您多重测试。 重复上述点因为它是最常跳过的点:正交性去偏烦扰估计,而非规格搜索。
实用注记
样本大小。 DML 需要烦扰模型以 收敛,实践中这意味着足够的行让 ML 模型以任何方式近似 和 。与其信任取整数的阈值,不如像 multi-symbol validation 那样实证建立充分性——检查估计是否在工具和子周期上成立,并将不稳定性视为其信号。
学习器选择。 DML 特定事实狭窄但有用:给定 收敛,学习器影响 的效率(区间宽度),而非其一致性。哪些学习器值得在表格市场数据上触及,以及为何梯度提升是默认值,已经在 spread modeling with machine learning 中涵盖。如果 在学习器间实质移动,那不是选择菜单——这是烦函数估计不良的证据,根据上述部分,选择最友好的会将练习变成搜索。
结论
DML 给博客带来了它没有的东西:一种将市场微结构主张声明为带有可辩护标准误的因果参数,而非带有良好验证分数的预测的方法。
三个承重想法是:
- 正交化分数,使第一阶误差补偿到二阶。
- 交叉拟合,在时间序列数据上使用清理和禁运折叠,使第一阶过拟合无法移动 。
- 预先指定,使您报告的区间是您实际获得的区间。
估计器是容易的部分。困难部分不变:决定哪些干扰因素重要,论证识别假设成立,以及抵抗再次运行规格的冲动。
参考文献
DML 血统短且 worth 一行:它是 Robinson (1988) 的部分线性模型,ML 替换核估计器,达到半参数效率界限,具有追溯 Neyman C() 测试的正交条件,以及在定向学习 (TMLE) 文献中的近亲。Chernozhukov 等人的贡献是展示这可以用任意 ML 学习器运作,同时保持 一致、渐近正态推断。
- Chernozhukov, V., Chetverikov, D., Demirer, M., Duflo, E., Hansen, C., Newey, W., & Robins, J. (2018). Double/Debiased Machine Learning for Treatment and Structural Parameters. The Econometrics Journal, 21(1), C1-C68.
- Robinson, P. M. (1988). Root-N-Consistent Semiparametric Regression. Econometrica, 56(4), 931-954.
- Bach, P., Chernozhukov, V., Kurz, M. S., & Spindler, M. (2022). DoubleML — An Object-Oriented Implementation of Double Machine Learning in Python. Journal of Machine Learning Research, 23(53), 1-6.
- Facure, M. (2022). Causal Inference for the Brave and True. Chapter 22: Debiased/Orthogonal Machine Learning.
- Cahan, E., Bai, J., & Ng, S. (2024). Causal Factor Investing. Quantitative Finance.
Authors
Trading-systems engineer
Trading-systems engineer building bots since 2017: cross-exchange arbitrage (connected up to 30 venues), cointegration-based pairs arbitrage across spot and futures, scalping, news and sentiment-driven strategies, trend algorithms, and portfolio management and balancing algorithms. Also builds sub-millisecond order execution, big-data warehouses, backtesting engines, AI agents, and trading interfaces (incl. open-source profitmaker.cc). Stack: JS/TS, Python, Rust/Zig/Go, DevOps, backend, frontend, architecture.