Double Machine Learning: Estimando um Parâmetro Causal em Vez de Prever Retornos
Todos os artigos de modelagem neste blog até agora colocam a mesma forma de pergunta: dadas features, preveja um número, depois valide que a predição sobrevive fora da amostra. Modelos de spread preveem spread. Modelos de preenchimento preveem probabilidade de preenchimento. Todo o aparato de validação — walk-forward purgado, Sharpe deflacionado, taxonomia de look-ahead — existe para verificar se uma predição é real.
Este artigo coloca uma forma diferente de pergunta, e é a única peça de maquinário que o blog nunca teve: estimar um único parâmetro escalar que tenha uma interpretação causal, e anexar um erro padrão a ele que sobreviva ao fato de que um modelo ML flexível foi usado para chegar lá.
Isso não é uma distinção retórica. "Posição na fila prediz probabilidade de preenchimento" é trivialmente verdadeira e operacionalmente inútil — é claro que ela o faz, ambos são impulsionados por profundidade e volatilidade. "Mover uma posição para frente na fila causa uma mudança de na probabilidade de preenchimento, mantendo o estado do mercado fixo" é um número que você pode colocar em uma política de colocação de ordens. O primeiro é um ajuste de regressão. O segundo requer um estimador que não existe na caixa de ferramentas ML padrão, porque a regularização e o overfitting em um primeiro estágio flexível enviesam exatamente o coeficiente que você se importa.
Double Machine Learning (Chernozhukov, Chetverikov, Demirer, Duflo, Hansen, Newey & Robins, 2018) é o estimador que corrige isso. Todo trader quantitativo ouviu isso: correlação não é causalidade. DML é a parte que vem depois dessa frase.
Por Que a Regressão Ingênua Falha

Coloque a pergunta no próprio território do blog. Queremos o efeito causal da posição na fila na probabilidade de preenchimento:
- : se a ordem limitada em repouso na observação foi preenchida dentro do horizonte.
- : posição na fila na colocação (normalizada pelo tamanho do nível).
- : os confundidores — volatilidade realizada, spread cotado, desbalanceamento de profundidade, tamanho do nível, hora do dia, etiqueta de regime. Estas são as variáveis de estado do mercado que o blog já calcula em modelagem de spread com machine learning.
O parâmetro causal é em
onde captura a relação (potencialmente complexa, não linear) entre estado do mercado e resultado de preenchimento.
O tratamento não é aleatoriamente atribuído. Você está perto da frente da fila porque o nível era fino, ou porque você postou durante um período calmo, ou porque o livro estava desbalanceado a seu favor. As mesmas condições impulsionam independentemente se você é preenchido. Isso é a confusão.
Abordagem 1: Ignorar confundidores. Regredir em apenas. A estimativa absorve o efeito de cada confundidor correlacionado com ambos. Viés de variável omitida clássico: níveis finos lhe dão tanto uma boa vaga na fila quanto uma alta taxa de preenchimento, então você exagera o valor da vaga em si.
Abordagem 2: Regressão linear com controles. Regredir em e . Isso só funciona se for verdadeiramente linear. A dinâmica do livro não é — a relação preenchimento/volatilidade tem limiares, o efeito de desbalanceamento de profundidade muda de sinal por regime. Especificar mal reintroduz o viés.
Abordagem 3: Predição ML. Ajustar um modelo com gradient boosting em . Você obtém boa discriminação fora da amostra, e nenhuma interpretação causal whatsoever. O modelo captura cada padrão preditivo, causal ou não; a regularização encolhe a contribuição do tratamento de formas que enviesam ; e não há um erro padrão em que você possa confiar.
Esta é a tensão central. ML é bom em predição, mas a aplicação ingênua a um parâmetro causal produz estimativas enviesadas, não normais, não confiáveis.
O Modelo Parcialmente Linear

DML opera dentro de uma estrutura estrutural. A cavalgade de trabalho é a regressão parcialmente linear (PLR):
- é o parâmetro causal de interesse.
- é uma função de incômodo — a parte do resultado explicada pelo estado do mercado.
- é outra função de incômodo — a expectativa condicional do tratamento dado o estado do mercado (a "propensity" em um cenário de tratamento contínuo).
- e são resíduos estruturais.
A visão chave: é de baixa dimensão, mas e podem ser arbitrariamente complexos. Queremos que ML lidere com as funções de incômodo enquanto ainda entrega inferência válida sobre o escalar.
Por Que "Double"?
Dois modelos ML, não um:
- Modelo de resultado: — prever o resultado a partir apenas do estado do mercado.
- Modelo de tratamento: — prever o tratamento a partir apenas do estado do mercado.
Formar resíduos
e estimar regredindo em :
Isto é Frisch-Waugh-Lovell em esteroides: partial out os confundidores com ML em vez de uma projeção linear, depois leia o efeito do tratamento da variação residual.
Ortogonalidade de Neyman: Por Que Funciona
A abordagem de partial-out ingênua (estimar , subtrair, regredir) falha porque erros de estimação ML em se propagam diretamente para . O escore DML é construído para ser Neyman ortogonal — insensível a pequenas perturbações nas funções de incômodo.
O escore ortogonal para PLR:
onde . A condição de ortogonalidade é
Intuitivamente, o escore usa apenas a variação em e que é independente de , e erros em uma função de incômodo são compensados pela outra. Se superestima levemente o tratamento, é levemente pequeno demais, mas o erro correspondente em de estimar mal empurra em uma direção compensatória. O viés torna-se segunda ordem — o produto de dois erros de primeiro estágio — em vez de primeira ordem.
Formalmente, se ambos os estimadores de incômodo convergem na taxa (suave; a maioria dos métodos ML razoáveis satisfazem isso), então
portanto converge na taxa paramétrica e é assintoticamente normal.
Cross-Fitting: Por Que É Obrigatório Aqui
Ortogonalidade por si só não é suficiente. Se os modelos de incômodo são ajustados nas mesmas linhas usadas para estimar , o overfitting de primeiro estágio contamina o segundo estágio — e o dano específico vale a pena ser precisamente declarado, porque não é o dano com que você está acostumado. Em outros lugares, o overfitting aparece como uma pontuação de validação inflada: você nota, você desconta, você prossegue. Aqui ele aparece como uma estimativa de ponto deslocada para , com um intervalo de confiança que ainda é estreito e ainda centrado no número errado. Não há pontuação da qual suspeitar. O estimador simplesmente mente quieto.
O cross-fitting quebra a dependência: as predições de incômodo de cada observação vêm de um modelo treinado sem ela, e é estimado a partir dos resíduos held-out pooled. A mecânica é maquinário K-fold ordinária, coberta em modelagem de spread com machine learning; o que importa abaixo é quais folds você lhe entrega.
O Algoritmo DML Passo a Passo
Entrada: dados , métodos ML e , folds .
Passo 1 — Partição: dividir em folds disjuntos.
Passo 2 — Cross-fit modelos de incômodo: para , treinar e no complemento do fold , depois calcular e para .
Passo 3 — Estimação:
Passo 4 — Inferência:
com intervalos .
O intervalo de confiança é válido para exatamente uma pergunta
Esta é a ressalva que decide se um resultado DML vale algo, e é onde a maioria dos usos aplicados do método silenciosamente se desmancha.
A normalidade assintótica acima é uma declaração sobre um tratamento pré-especificado, um conjunto pré-especificado de confundidores, um escore pré-especificado. Fixe esses com antecedência, execute o estimador uma vez, e o intervalo significa o que diz. Tente três tratamentos candidatos, ou quatro conjuntos de confundidores, ou troque learners até que o valor p pareça melhor, e você não está mais fazendo inferência — você está executando uma busca, e o valor p reportado é o valor p de um máximo, não de um sorteio.
O blog já mediu o que isso faz. Em o estudo de rácio de Sharpe deflacionado, buscas sobre ruído puro com zero vantagem real produzem uma taxa de descoberta falsa ingênua de 1.000 — o teste não ajustado dispara toda vez — enquanto que o valor p ingênuo mediano do vencedor senta perto de 0.0007. Nada sobre ortogonalidade de Neyman o protege disso. A ortogonalidade corrige o viés de estimação de incômodo; ela nada diz sobre o viés de busca de especificação. Um valor p DML de 1e-05 obtido depois de tentar seis especificações merece exatamente o mesmo tratamento Bonferroni/Holm/BHY que qualquer outro vencedor tirado de um grid, com definido para o número de especificações que você realmente executou.
Isso tem uma consequência prática direta para as funcionalidades de conveniência das ferramentas. DoubleMLData aceita uma lista em d_cols e alegremente retornará três efeitos de tratamento em uma tabela de resumo:
dml_data_multi = dml.DoubleMLData(
df, y_col='filled', d_cols=['queue_pos', 'toxicity', 'spread_at_post'],
x_cols=confounder_cols,
)
Três linhas, três valores p, e um problema de testes múltiplos que a tabela de resumo não menciona. Se você ler os três, ajuste os três. Se apenas um era a pergunta pré-registrada, diga-o, e trate os outros dois explicitamente como exploratórios.
Cross-Fitting em Séries Temporais: Purge, Embargo, Folds Personalizados

DML padrão assume observações i.i.d. Dados de livro não são, e o modo de falha é aquele que o blog já documentou em detalhe: linhas adjacentes compartilham janelas forward sobrepostas, então um TimeSeriesSplit plano ainda vaza a resposta através da fronteira do fold. Veja modelagem de spread com machine learning para a implementação walk-forward purgada e embargada e a razão pela qual uma lacuna de pelo menos horizon linhas é requerida, e a taxonomia de viés de look-ahead para o catálogo completo de vazamentos e suas magnitudes medidas.
A parte verdadeiramente específica de DML é como você entrega folds purgados ao estimador, porque set_sample_splitting tem um contrato que tropeça as pessoas:
import numpy as np
import doubleml as dml
def purged_folds(n: int, n_splits: int, horizon: int):
"""Folds de janela em expansão com uma lacuna de purge/embargo de `horizon` linhas.
Mesma construção que o CV walk-forward purgado no artigo de
modelagem de spread: a lacuna remove a sobreposição entre a janela
forward de uma linha de treinamento e uma linha de validação.
"""
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()
Duas coisas a estar ciente, nenhuma óbvia dos docs da biblioteca:
- Folds walk-forward purgados não cobrem cada linha. As lacunas de purge e o bloco de treinamento inicial nunca são o fold de teste de ninguém, então é estimado de estritamente menos que resíduos. Isso é comportamento correto, não um bug, mas significa que o efetivo na fórmula de variância é o número de linhas de teste pooled — verifique-o em vez de assumir.
- Repetições
n_repnão são grátis aqui. Com K-fold aleatório, repetir cross-fitting e média é uma redução de variância barata. Com um split determinístico ordenado por tempo há apenas um split, entãon_repnão compra nada e não esconde nada; a estabilidade tem que vir de re-executar em diferentes janelas de dados.
Para estruturas de painel (muitos símbolos no mesmo período), DoubleML suporta erros padrão robustos a cluster — agrupe em símbolo, não em tempo, e veja validação multi-símbolo para a posição do blog sobre quando um resultado cross-instrumento é realmente estabelecido.
O Caso Medido: Posição na Fila e Probabilidade de Preenchimento

Esta é a única pergunta causal no artigo onde o projeto já tem os dados, e deveria ser executada em vez de colocada. Análise de posição na fila já cobre estimação de posição, mecânica FIFO, taxas de drenagem e tempo-para-preenchimento em dados de livro reais; simulação de preenchimento cobre modelagem de probabilidade de preenchimento e o loop de calibração contra preenchimentos ao vivo. Ambos produzem um modelo preditivo de preenchimentos. DML converte as mesmas entradas em uma estimativa causal.
A especificação, pré-registrada antes de olhar a estimativa:
- Resultado : preenchido dentro de
HORIZONsnapshots (binário). - Tratamento : posição na fila normalizada na colocação.
- Confundidores : volatilidade realizada 1s, spread cotado em bps, desbalanceamento de profundidade, tamanho do nível no post, distância do mid em ticks, codificação de hora do dia, etiqueta de regime.
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)
O resultado a reportar é uma comparação de quatro colunas, não um único coeficiente: a estimativa OLS ingênua de em apenas, a estimativa de controle linear de em e , a estimativa DML com seu erro padrão, e o valor de robustez da análise de sensibilidade — quão forte um confundidor não observado teria que ser para anular o efeito. A lacuna entre as colunas ingênua e DML é a quantidade de interesse real: é quanto do valor aparente da posição na fila era estado do mercado usando uma fantasia.
Um nulo ou negativo aqui é um resultado publicável e se ajusta melhor a este blog do que um positivo limpo. Se o efeito causal da posição na fila colapsa uma vez que a volatilidade e o tamanho do nível são parcialmente removidos, esse é um achado direto sobre política de colocação de ordens: a vaga não é o que ganha o preenchimento, as condições sob as quais você obteve a vaga é que são.
Análise de Fator Causal
A abordagem padrão para investimento em fatores é associativa: ordene por uma característica, forme carteiras long-short, observe que os retornos diferem. DML permite um teste diferente — estimar o efeito causal direto de uma característica nos retornos, liquidando os efeitos de confusão das outras características. Se o efeito desaparece sob DML, o fator não é independentemente causal; é um proxy.
Esta é uma segunda, forma independente de ceticismo de fator, e vale a pena ser explícito sobre como se relaciona com a que o blog já publica. O rácio de Sharpe deflacionado ataca o zoológico de fatores do lado de seleção: com试验 suficientes, um fator pode parecer significativo puramente porque você olhou muitas vezes. DML ataca do lado de confusão: um fator pode parecer significativo em um único teste honesto e ainda ser um proxy de algo mais no conjunto de condicionamento. Um fator tem que sobreviver a ambos para ser interessante, e os dois modos de falha são independentes — passar um não lhe diz nada sobre o outro.
O Que DML Não Pode Fazer
-
Requer que os confundidores sejam observados. Se uma variável não observada impulsiona tanto o tratamento quanto o resultado, DML é enviesado, e nenhuma sofisticação ML corrige um problema de identificação. Análise de sensibilidade limita o risco; não o remove.
-
Estima um efeito médio. Se o efeito da posição na fila varia acentuadamente através de regimes, a estimativa de ponto é a média sobre a mistura de regimes da sua amostra. Para heterogeneidade use o Interactive Regression Model (
DoubleMLIRM) ou uma floresta causal. -
Assume um modelo estrutural. A especificação parcialmente linear requer que o tratamento entre na equação de resultado de uma maneira particular. Se o processo real é fundamentalmente diferente, DML está confiantemente errado.
-
Não descobre estrutura causal. DML estima o efeito de um tratamento pré-especificado. Não lhe diz quais variáveis são causas.
-
Não o isenta de testes múltiplos. Repetindo o ponto acima porque é o mais frequentemente pulado: a ortogonalidade de-viesa estimação de incômodo, não busca de especificação.
Notas Práticas
Tamanho da amostra. DML requer que os modelos de incômodo convirjam em , o que na prática significa linhas suficientes para os modelos ML aproximarem e de qualquer forma. Em vez de confiar em limiares de números redondos, estabeleça adequação empiricamente da forma que validação multi-símbolo faz — verifique se a estimativa se mantém através de instrumentos e sub-períodos, e trate instabilidade como o sinal que ela é.
Escolha de learner. O fato específico de DML é estreito mas útil: dada convergência , o learner afeta a eficiência de (largura do intervalo), não sua consistência. Quais learners valem a pena alcançar em dados de mercado tabulares, e por que gradient boosting é o padrão, já está coberto em modelagem de spread com machine learning. Se se move materialmente através de learners, isso não é um menu para escolher — é evidência de que as funções de incômodo estão mal estimadas, e por seção acima, escolher o mais amigável transforma o exercício em uma busca.
Conclusão
DML dá ao blog algo que não tinha: uma maneira de afirmar uma reivindicação de microestrutura de mercado como um parâmetro causal com um erro padrão defensável, em vez de como uma predição com uma boa pontuação de validação.
As três ideias que suportam carga são:
- Ortogonalize o escore para que erros de primeiro estágio se compensem a segunda ordem.
- Cross-fit, com folds purgados e embargados em dados de séries temporais, para que overfitting de primeiro estágio não possa deslocar .
- Pré-especifique, para que o intervalo que você reporta é o intervalo que você realmente ganhou.
O estimador é a parte fácil. As partes difíceis permanecem inalteradas: decidir quais confundidores importam, argumentar que as suposições de identificação se mantêm, e resistir ao impulso de executar a especificação mais uma vez.
Referências
A linhagem de DML é curta e vale uma linha: é o modelo parcialmente linear de Robinson (1988) com ML substituindo os estimadores de kernel, alcançando o limite de eficiência semiparamétrico, com uma condição de ortogonalidade que remonta ao teste C() de Neyman e um primo próximo na literatura de aprendizado direcionado (TMLE). A contribuição de Chernozhukov et al. foi mostrar que isso poderia ser operacionalizado com learners ML arbitrários enquanto retém inferência -consistente, assintoticamente normal.
- 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.