Двойное машинное обучение: оценка причинного параметра вместо прогнозирования доходности
Все статьи о моделировании в этом блоге до сих пор ставили одну и ту же форму вопроса: даны признаки, спрогнозируй число, затем проверь, что прогноз выживает вне выборки. Модели спреда прогнозируют спред. Модели заполнения прогнозируют вероятность заполнения. Весь аппарат валидации — очищенный walk-forward, сдутый Шарп, таксономия look-ahead — существует для проверки того, является ли прогноз настоящим.
Эта статья ставит другую форму вопроса, и это единственный инструмент, которого никогда не было в блоге: оценить один скалярный параметр, который имеет причинное значение, и прикрепить к нему стандартную ошибку, которая переживает факт того, что гибкая ML модель была использована для достижения этого.
Это не риторическое различие. "Позиция в очереди предсказывает вероятность заполнения" тривиально верна и операционно бесполезна — конечно, она это делает, оба определяются глубиной и волатильностью. "Сдвинуться на одну позицию вперед в очереди вызывает изменение на в вероятности заполнения, при фиксированном состоянии рынка" — это число, которое можно вставить в политику размещения ордеров. Первое — это подгонка регрессии. Второе требует оценщика, которого не существует в стандартном ML инструментарии, потому что регуляризация и overfitting в гибкой первой стадии смещают именно тот коэффициент, который вам важен.
Двойное машинное обучение (Chernozhukov, Chetverikov, Demirer, Duflo, Hansen, Newey & Robins, 2018) — это оценщик, который это исправляет. Каждый количественный трейдер слышал это: корреляция не есть причинность. DML — это та часть, которая идет после этой фразы.
Почему наивная регрессия не работает

Поставим вопрос на собственной территории блога. Мы хотим причинный эффект позиции в очереди на вероятность заполнения:
- : заполнился ли лимитный ордер в покое на наблюдении в пределах горизонта.
- : позиция в очереди при размещении (нормализованная размером уровня).
- : конфаундеры — реализованная волатильность, котируемый спред, дисбаланс глубины, размер уровня, время дня, метка режима. Это переменные состояния рынка, которые блог уже вычисляет в моделировании спреда с машинным обучением.
Причинный параметр — это в
где захватывает (потенциально сложную, нелинейную) связь между состоянием рынка и исходом заполнения.
Лечение не назначено случайно. Вы находитесь в начале очереди потому что уровень был тонким, или потому что вы разместили в спокойный период, или потому что книга была несбалансирована в вашу пользу. Те же условия независимо определяете, заполнитесь ли вы. Это и есть конфаундинг.
Подход 1: Игнорировать конфаундеры. Регрессировать на только. Оценка поглощает эффект каждого конфаундера, коррелированного с обоими. Классическое смещение пропущенной переменной: тонкие уровни дают и хорошую позицию в очереди, и высокую частоту заполнения, поэтому вы преувеличиваете ценность самой позиции.
Подход 2: Линейная регрессия с контролем. Регрессировать на и . Это работает только если действительно линейна. Динамика книги не такова — связь заполнения/волатильности имеет пороги, эффект дисбаланса глубины меняет знак в зависимости от режима. Неправильная спецификация повторно вводит смещение.
Подход 3: ML прогноз. Подогнать модель с градиентным бустингом на . Вы получаете хорошую вне выборки дискриминацию, и никакого причинного толкования. Модель захватывает каждый прогностический паттерн, причинный или нет; регуляризация сжимает вклад лечения способами, которые смещают ; и нет стандартной ошибки, которой можно доверять.
Это главное напряжение. ML хорош в прогнозировании, но наивное применение к причинному параметру дает смещенные, ненормальные, ненадежные оценки.
Частично линейная модель

DML работает в рамках структурной модели. Рабочая лошадка — это частично линейная регрессия (PLR):
- — причинный параметр интереса.
- — это nuisance-функция — часть результата, объясненная состоянием рынка.
- — другая nuisance-функция — условное ожидание лечения при данном состоянии рынка ("propensity" в контексте непрерывного лечения).
- и — структурные остатки.
Ключевое понимание: низкоразмерный, но и могут быть произвольно сложными. Мы хотим, чтобы ML обрабатывал nuisance-функции, при этом все еще доставляя валидный вывод о скаляре.
Почему "двойной"?
Две ML модели, а не одна:
- Модель результата: — прогнозировать результат только из состояния рынка.
- Модель лечения: — прогнозировать лечение только из состояния рынка.
Сформировать остатки
и оценить , регрессируя на :
Это Frisch-Waugh-Lovell на стероидах: убрать конфаундеры с ML вместо линейной проекции, затем прочитать эффект лечения из остаточной вариации.
Ортогональность Неймана: почему это работает
Наивный подход частичного удаления (оценить , вычесть, регрессировать) не работает, потому что ошибки ML оценки в напрямую передаются в . Оценка DML сконструирована так, чтобы быть Нейман ортогональной — нечувствительной к малым возмущениям в nuisance-функциях.
Ортогональная оценка для PLR:
где . Условие ортогональности:
Интуитивно, оценка использует только вариацию в и , которая независима от , и ошибки в одной nuisance-функции компенсируются другой. Если немного переоценивает лечение, немного слишком маленькая, но соответствующая ошибка в от неправильной оценки толкает в компенсирующем направлении. Смещение становится второго порядка — произведение двух ошибок первой стадии — а не первого порядка.
Формально, если оба nuisance-оценщика сходятся со скоростью (мягко; большинство разумных ML методов это выполняют), тогда
поэтому сходится с параметрической скоростью и асимптотически нормален.
Cross-fitting: почему здесь обязательно
Одной ортогональности недостаточно. Если nuisance-моды подогнаны на тех же строках, которые используются для оценки , overfitting первой стадии загрязняет вторую стадию — и специфический вред стоит того, чтобы быть точно сформулированным, потому что это не тот вред, к которому вы привыкли. В другом месте overfitting появляется как раздутая оценка валидации: вы замечаете, делаете скидку, продолжаете. Здесь он появляется как смещенная точечная оценка для , с доверительным интервалом, который все еще узок и все еще центрирован на неправильном числе. Нет оценки, которой можно подозревать. Оценщик просто тихо лжет.
Cross-fitting разрывает зависимость: nuisance-прогнозы каждого наблюдения приходят из модели, обученной без него, и оценивается из pooled held-out остатков. Механика — это обычная K-fold машинерия, описанная в моделировании спреда с машинным обучением; что важно ниже — это какие folds вы ему даете.
Алгоритм DML шаг за шагом
Ввод: данные , ML методы и , folds .
Шаг 1 — Разбиение: разделить на непересекающихся folds.
Шаг 2 — Cross-fit nuisance-модели: для , обучить и на дополнении fold , затем вычислить и для .
Шаг 3 — Оценка:
Шаг 4 — Вывод:
с интервалами .
Доверительный интервал валиден ровно для одного вопроса
Это та оговорка, которая определяет, стоит ли DML результат что-то, и где большинство приложений метода тихо разваливаются.
Вышеописанная асимптотическая нормальность — это утверждение об одном заранее специфицированном лечении, одном заранее специфицированном наборе конфаундеров, одной заранее специфицированной оценке. Зафиксируйте это заранее, выполните оценщик один раз, и интервал означает то, что говорит. Попробуйте три кандидат-лечения, или четыре набора конфаундеров, или меняйте learners пока p-значение не будет выглядеть лучше, и вы больше не делаете вывод — вы выполняете поиск, и сообщенное p-значение — это p-значение максимума, а не выборки.
Блог уже измерял, что это делает. В исследовании сдутого Sharpe ratio поиски по чистому шуму с нулевым реальным преимуществом производят наивную частоту ложных открытий 1.000 — неадJUSTированный тест срабатывает каждый раз — в то время как медианное наивное p-значение победителя сидит около 0.0007. Ничто в ортогональности Неймана не защищает вас от этого. Ортогональность исправляет смещение от nuisance-оценки; она ничего не говорит о смещении от поиска спецификации. p-значение DML 1e-05, полученное после попытки шести спецификаций, заслуживает точно такое же отношение 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-значения, и проблема множественного тестирования, которую итоговая таблица не упоминает. Если вы читаете все три, корректируйте все три. Если только одна была предварительно зарегистрированным вопросом, скажите это, и обращайтесь с другими двумя явно как с исследовательскими.
Cross-fitting на временных рядах: purge, embargo, кастомные folds

Стандартный DML предполагает i.i.d. наблюдения. Данные книги не таковы, и режим сбоя тот, который блог уже подробно документировал: соседние строки делят перекрывающиеся forward окна, поэтому простой TimeSeriesSplit все еще протекает ответ через границу fold. Смотрите моделирование спреда с машинным обучением для реализации очищенного и embargoed walk-forward и причины, по которой требуется разрыв минимум horizon строк, и таксономию look-ahead bias для полного каталога утечек и их измеренных величин.
Действительно специфичная для DML часть — это как вы передаете очищенные folds оценщику, потому что set_sample_splitting имеет контракт, на котором спотыкаются люди:
import numpy as np
import doubleml as dml
def purged_folds(n: int, n_splits: int, horizon: int):
"""Folds с расширяющимся окном и разрывом purge/embargo `horizon` строк.
Та же конструкция, что и очищенный walk-forward CV в статье о
моделировании спреда: разрыв удаляет перекрытие между forward окном
тренировочной строки и валидационной строки.
"""
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 folds не покрывают каждую строку. Разрывы purge и начальный тренировочный блок никогда не являются test fold никого, поэтому оценивается строго менее чем из остатков. Это правильное поведение, не баг, но это означает, что эффективное в формуле дисперсии — это количество pooled test строк — проверьте это вместо предположения.
- Повторения
n_repздесь не бесплатны. Со случайным K-fold повторение cross-fitting и усреднение — это дешевое снижение дисперсии. С детерминированным упорядоченным по времени разделением есть только одно разделение, поэтомуn_repничего не покупает и не скрывает; стабильность должна приходить от повторного запуска на разных окнах данных.
Для панельных структур (много символов за тот же период) DoubleML поддерживает кластер-робастные стандартные ошибки — кластеризуйте по символу, а не по времени, и смотрите множественную валидацию на позицию блога о том, когда действительно устанавливается cross-instrument результат.
Измеренный кейс: позиция в очереди и вероятность заполнения

Это единственный причинный вопрос в статье, где проект уже имеет данные, и он должен быть выполнен, а не просто предложен. Анализ позиции в очереди уже покрывает оценку позиции, механику FIFO, скорости дренажа и время-до-заполнения на реальных данных книги; симуляция заполнения покрывает моделирование вероятности заполнения и цикл калибровки против live заполнений. Оба производят прогностическую модель заполнений. DML преобразует те же входы в причинную оценку.
Спецификация, предварительно зарегистрированная перед взглядом на оценку:
- Результат $Y
: заполнен в пределахHORIZON` снимков (бинарно). - Лечение : нормализованная позиция в очереди при размещении.
- Конфаундеры $X`: реализованная 1s волатильность, котируемый спред в bps, дисбаланс глубины, размер уровня при посте, расстояние от mid в тиках, кодирование времени дня, метка режима.
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 колонками — это действительно интересное количество: это сколько мнимой ценности позиции в очереди было состоянием рынка в маскараде.
Нулевой или отрицательный здесь — это публикуемый результат и лучше подходит этому блогу, чем чистый положительный. Если причинный эффект позиции в очереди коллапсирует, как только волатильность и размер уровня частично удалены, это прямое открытие о политике размещения ордеров: не позиция зарабатывает заполнение, условия, при которых вы получили позицию, — да.
Причинный факторный анализ
Стандартный подход к факторному инвестированию — ассоциативный: сортировать по характеристике, формировать long-short портфели, наблюдать, что доходности различаются. DML позволяет другой тест — оценить прямой причинный эффект характеристики на доходности, очистив эффекты конфаундинга других характеристик. Если эффект исчезает под DML, фактор не является независимо причинным; это прокси.
Это вторая, независимая форма факторного скептицизма, и стоит быть явным о том, как она relates к той, которую блог уже публикует. Сдутый Sharpe ratio атакует факторный зоопарк со стороны селекции: с достаточно испытаний фактор может выглядеть значимым чисто потому что вы много раз смотрели. DML атакует со стороны конфаундинга: фактор может выглядеть значимым на одном честном тесте и все еще быть прокси чего-то другого в conditioning set. Фактор должен выжить в обоих, чтобы быть интересным, и два режима сбоя независимы — прохождение одного не говорит вам о другом.
Что DML не может делать
-
Требует, чтобы конфаундеры были наблюдены. Если ненаблюдаемая переменная управляет и лечением, и результатом, DML смещен, и никакая ML изощренность не исправляет проблему идентификации. Анализ чувствительности ограничивает риск; не удаляет его.
-
Оценивает средний эффект. Если эффект позиции в очереди резко varies по режимам, точечная оценка — это среднее по смеси режимов вашей выборки. Для гетерогенности используйте Interactive Regression Model (
DoubleMLIRM) или causal forest. -
Предполагает структурную модель. Частично линейная спецификация требует, чтобы лечение входило в уравнение результата определенным способом. Если истинный процесс фундаментально другой, DML уверенно ошибается.
-
Не открывает причинную структуру. DML оценивает эффект заранее специфицированного лечения. Он не говорит вам, какие переменные — причины.
-
Не освобождает от множественного тестирования. Повторяю вышеуказанную точку, потому что она чаще всего пропускается: ортогональность de-biasит nuisance-оценку, а не поиск спецификации.
Практические заметки
Размер выборки. DML требует, чтобы nuisance-модели сходились в , что на практике означает достаточно строк для ML моделей, чтобы вообще аппроксимировать и . Вместо доверия круглым порогам установите адекватность эмпирически тем способом, как это делает множественная валидация — проверьте, держится ли оценка через инструменты и под-периоды, и обращайтесь с нестабильностью как с сигналом, который она есть.
Выбор learner. Специфический для DML факт узок но полезен: при сходимости , learner влияет на эффективность (ширину интервала), а не на согласованность. Какие learners стоят того, чтобы достигать на табличных рыночных данных, и почему градиентный бустинг — дефолт, уже описано в моделировании спреда с машинным обучением. Если существенно moves через learners, это не меню для выбора — это доказательство, что nuisance-функции плохо оценены, и согласно вышеуказанной секции, выбор самого дружелюбного превращает упражнение в поиск.
Заключение
DML дает блогу то, чего у него не было: способ сформулировать утверждение о микроструктуре рынка как причинный параметр с defendable стандартной ошибкой, а не как прогноз с хорошей оценкой валидации.
Три несущие идеи:
- Ортогонализируйте оценку так, чтобы ошибки первой стадии компенсировались до второго порядка.
- Cross-fit, с очищенными и embargoed folds на данных временных рядов, чтобы overfitting первой стадии не мог сместить .
- Предварительно специфицируйте, чтобы интервал, который вы report, — это интервал, который вы действительно заслужили.
Оценщик — это легкая часть. Трудные части остаются неизменными: решать, какие конфаундеры важны, аргументировать, что идентификационные предположения выполняются, и сопротивляться импульсу выполнить спецификацию еще раз.
Ссылки
Линия DML коротка и стоит одной строки: это частично линейная модель Robinson (1988) с ML заменяющим kernel estimators, достигающая semiparametric efficiency bound, с условием ортогональности, tracing back к тесту C() Неймана и близкому кузену в литературе targeted learning (TMLE). Вклад Chernozhukov et al. был демонстрацией того, что это можно операционализировать с произвольными ML learners, сохраняя -consistent, асимптотически нормальный вывод.
- 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.
Авторы
Инженер торговых систем
Разработка торговых ботов с 2017 года: межбиржевой арбитраж (подключал до 30 бирж), парный арбитраж на коинтеграции между спотом и фьючерсами, скальпинг, фронтраннинг, торговля по новостям, сентиментный анализ, трендовые алгоритмы, а также алгоритмы управления и балансировки портфелей. Делает выставление ордеров до 1 мс, warehouse для big data, бэктестинг-движки, AI-агентов и интерфейсы для ботов (в т.ч. open-source profitmaker.cc). Стек: JS/TS, Python, Rust/Zig/Go, DevOps, backend, frontend, архитектура.