Double Machine Learning: Estimando un Parametro Causal en Vez de Predecir Retornos
Todos los articulos de modelado en este blog hasta ahora plantean la misma forma de pregunta: dadas caracteristicas, predecir un numero, luego validar que la prediccion sobrevive fuera de la muestra. Los modelos de spread predicen spread. Los modelos de fill predicen probabilidad de fill. Todo el aparato de validacion — walk-forward purgado, Sharpe desinflado, taxonomia de look-ahead — existe para verificar si una prediccion es real.
Este articulo plantea una forma diferente de pregunta, y es la unica pieza de maquinaria que el blog nunca ha tenido: estimar un unico parametro escalar que tenga una interpretacion causal, y adjuntarle un error estandar que sobreviva al hecho de que se uso un modelo ML flexible para llegar ahi.
Eso no es una distincion retorica. "La posicion en cola predice la probabilidad de fill" es trivialmente verdadera y operacionalmente inutil — por supuesto que lo hace, ambos son impulsados por profundidad y volatilidad. "Moverse una posicion adelante en la cola causa un cambio de en la probabilidad de fill, manteniendo el estado del mercado fijo" es un numero que puedes poner en una politica de colocacion de ordenes. El primero es un ajuste de regresion. El segundo requiere un estimador que no existe en la caja de herramientas ML estandar, porque la regularizacion y el overfitting en una primera etapa flexible sesgan exactamente el coeficiente que te importa.
Double Machine Learning (Chernozhukov, Chetverikov, Demirer, Duflo, Hansen, Newey & Robins, 2018) es el estimador que arregla esto. Todo trader cuantitativo ha escuchado esto: correlacion no es causalidad. DML es la parte que viene despues de esa frase.
Por Que la Regresion Naiva Falla
¡Un confundidor de estado de mercado oculto impulsa tanto la colocacion en cola como los resultados de fill, creando una asociacion naiva enganosa](/images/blog/double-ml-causal-trading-naive-regression.webp)
Plantea la pregunta en el propio territorio del blog. Queremos el efecto causal de la posicion en cola sobre la probabilidad de fill:
- : si la orden limitante en reposo en la observacion se lleno dentro del horizonte.
- : posicion en cola al colocarse (normalizada por el tamano del nivel).
- : los confundidores — volatilidad realizada, spread cotizado, desbalance de profundidad, tamano del nivel, hora del dia, etiqueta de regimen. Estas son las variables de estado del mercado que el blog ya calcula en modelado de spread con machine learning.
El parametro causal es en
donde captura la relacion (potencialmente compleja, no lineal) entre el estado del mercado y el resultado de fill.
El tratamiento no esta asignado aleatoriamente. Estas cerca del frente de la cola porque el nivel estaba delgado, o porque publicaste durante un periodo tranquilo, o porque el libro estaba desbalanceado a tu favor. Las mismas condiciones impulsan independientemente si te llenas. Eso es la confusion.
Enfoque 1: Ignorar confundidores. Regresar sobre solo. La estimacion absorbe el efecto de cada confundidor correlacionado con ambos. Sesgo de variable omitida clasico: niveles delgados te dan tanto un buen lugar en cola como una alta tasa de fill, asi que exageras el valor del lugar mismo.
Enfoque 2: Regresion lineal con controles. Regresar sobre y . Esto solo funciona si es verdaderamente lineal. La dinamica del libro no lo es — la relacion fill/volatilidad tiene umbrales, el efecto de desbalance de profundidad cambia de signo por regimen. Especificar mal reintroduce el sesgo.
Enfoque 3: Prediccion ML. Ajustar un modelo potenciado por gradiente en . Obtienes buena discriminacion fuera de la muestra, y ninguna interpretacion causal en absoluto. El modelo captura cada patron predictivo, causal o no; la regularizacion encoge la contribucion del tratamiento de formas que sesgan ; y no hay un error estandar en el que puedas confiar.
Esta es la tension central. ML es bueno en prediccion, pero la aplicacion naiva a un parametro causal produce estimaciones sesgadas, no normales, no fiables.
El Modelo Parcialmente Lineal

DML opera dentro de un marco estructural. El caballo de batalla es la regresion parcialmente lineal (PLR):
- es el parametro causal de interes.
- es una funcion de molestia — la parte del resultado explicada por el estado del mercado.
- es otra funcion de molestia — la expectativa condicional del tratamiento dado el estado del mercado (la "propensity" en un entorno de tratamiento continuo).
- y son residuos estructurales.
La vision clave: es de baja dimension, pero y pueden ser arbitrariamente complejos. Queremos que ML maneje las funciones de molestia mientras todavia entrega inferencia valida sobre el escalar.
Por Que "Doble"?
Dos modelos ML, no uno:
- Modelo de resultado: — predecir el resultado desde el estado del mercado solo.
- Modelo de tratamiento: — predecir el tratamiento desde el estado del mercado solo.
Formar residuos
y estimar regresando sobre :
Esto es Frisch-Waugh-Lovell con esteroides: partial out los confundidores con ML en lugar de una proyeccion lineal, luego leer el efecto del tratamiento de la variacion residual.
Ortogonalidad de Neyman: Por Que Funciona
El enfoque de partial-out naivo (estimar , restar, regresar) falla porque los errores de estimacion ML en se propagan directamente a . El score DML se construye para ser Neyman ortogonal — insensible a pequenas perturbaciones en las funciones de molestia.
El score ortogonal para PLR:
donde . La condicion de ortogonalidad es
Intuitivamente, el score usa solo la variacion en y que es independiente de , y los errores en una funcion de molestia se compensan con la otra. Si sobre-predice levemente el tratamiento, es ligeramente pequeno, pero el error correspondiente en de estimar mal empuja en una direccion compensatoria. El sesgo se vuelve de segundo orden — el producto de dos errores de primera etapa — en lugar de primer orden.
Formalmente, si ambos estimadores de molestia convergen a tasa (suave; la mayoria de metodos ML razonables la cumplen), entonces
asi que converge a tasa parametrica y es asintoticamente normal.
Cross-Fitting: Por Que Es Obligatorio Aqui
La ortogonalidad por si sola no es suficiente. Si los modelos de molestia se ajustan en las mismas filas usadas para estimar , el overfitting de primera etapa contamina la segunda etapa — y el dano especifico vale la pena stated con precision, porque no es el dano al que estas acostumbrado. En otro lugar, el overfitting se muestra como una puntuacion de validacion inflada: lo notas, lo descuentas, continuas. Aqui se muestra como una estimacion de punto desplazada para , con un intervalo de confianza que todavia es estrecho y todavia centrado en el numero incorrecto. No hay puntuacion de la que sospechar. El estimador simplemente miente en silencio.
El cross-fitting rompe la dependencia: las predicciones de molestia de cada observacion vienen de un modelo entrenado sin ella, y se estima desde los residuos agrupados held-out. La mecanica es maquinaria K-fold ordinaria, cubierta en modelado de spread con machine learning; lo que importa abajo es que folds le entregas.
El Algoritmo DML Paso a Paso
Entrada: datos , metodos ML y , folds .
Paso 1 — Particion: dividir en folds disjuntos.
Paso 2 — Cross-fit modelos de molestia: para , entrenar y en el complemento del fold , luego calcular y para .
Paso 3 — Estimacion:
Paso 4 — Inferencia:
con intervalos .
El intervalo de confianza es valido para exactamente una pregunta
Esta es la salvedad que decide si un resultado DML vale algo, y es donde la mayoria de los usos aplicados del metodo se deshacen silenciosamente.
La normalidad asintotica anterior es una declaracion sobre un tratamiento pre-especificado, un conjunto pre-especificado de confundidores, un score pre-especificado. Fija esos por adelantado, ejecuta el estimador una vez, y el intervalo significa lo que dice. Prueba tres tratamientos candidatos, o cuatro conjuntos de confundidores, o cambia learners hasta que el p-value se vea mejor, y ya no estas haciendo inferencia — estas ejecutando una busqueda, y el p-value reportado es el p-value de un maximo, no de un sorteo.
El blog ya ha medido lo que eso hace. En el estudio de Sharpe ratio desinflado, buscas sobre ruido puro con cero ventaja real producen una tasa de descubrimiento falso naiva de 1.000 — la prueba no ajustada dispara cada vez — mientras que el p-value naivo medio del ganador se sienta cerca de 0.0007. Nada sobre la ortogonalidad de Neyman te protege de esto. La ortogonalidad arregla el sesgo de estimacion de molestia; no dice nada sobre el sesgo de busqueda de especificacion. Un p-value DML de 1e-05 obtenido despues de probar seis especificaciones merece exactamente el mismo tratamiento Bonferroni/Holm/BHY que cualquier otro ganador sacado de un grid, con establecido al numero de especificaciones que realmente ejecutaste.
Esto tiene una consecuencia practica directa para las caracteristicas de conveniencia de las herramientas. DoubleMLData acepta una lista en d_cols y felizmente devolvera tres efectos de tratamiento en una tabla de resumen:
dml_data_multi = dml.DoubleMLData(
df, y_col='filled', d_cols=['queue_pos', 'toxicity', 'spread_at_post'],
x_cols=confounder_cols,
)
Tres filas, tres p-values, y un problema de pruebas multiples que la tabla de resumen no menciona. Si lees los tres, ajusta los tres. Si solo uno fue la pregunta pre-registrada, dilo, y trata los otros dos explicitamente como exploratorios.
Cross-Fitting en Series Temporales: Purge, Embargo, Folds Personalizados

DML estandar asume observaciones i.i.d. Los datos del libro no lo son, y el modo de fallo es el que el blog ya ha documentado en detalle: filas adyacentes comparten ventanas forward superpuestas, asi que un TimeSeriesSplit plano todavia filtra la respuesta a traves del limite del fold. Ve modelado de spread con machine learning para la implementacion walk-forward purgada y embargada y la razon por la que se requiere un hueco de al menos horizon filas, y la taxonomia de sesgo de look-ahead para el catalogo completo de fugas y sus magnitudes medidas.
La parte realmente especifica de DML es como entregas folds purgados al estimador, porque set_sample_splitting tiene un contrato que tropeza a la gente:
import numpy as np
import doubleml as dml
def purged_folds(n: int, n_splits: int, horizon: int):
"""Folds de ventana expansiva con un hueco de purge/embargo de `horizon` filas.
Misma construccion que el CV walk-forward purgado en el articulo de
modelado de spread: el hueco elimina la superposicion entre la ventana
forward de una fila de entrenamiento y una fila de validacion.
"""
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()
Dos cosas de las que estar al tanto, ninguna obvia de los docs de la biblioteca:
- Los folds walk-forward purgados no cubren cada fila. Los huecos de purge y el bloque de entrenamiento inicial nunca son el fold de prueba de nadie, asi que se estima de estrictamente menos de residuos. Eso es comportamiento correcto, no un bug, pero significa que la efectiva en la formula de varianza es el numero de filas de prueba agrupadas — verificalo en lugar de asumir.
- Las repeticiones
n_repno son gratis aqui. Con K-fold aleatorio, repetir cross-fitting y promediar es una reduccion de varianza barata. Con un split determinista ordenado por tiempo hay un solo split, asi quen_repno compra nada y no esconde nada; la estabilidad tiene que venir de re-ejecutar en diferentes ventanas de datos en su lugar.
Para estructuras de panel (muchos simbolos en el mismo periodo), DoubleML soporta errores estandar robustos a cluster — agrupa en simbolo, no en tiempo, y ve validacion multi-simbolo para la posicion del blog sobre cuando se establece realmente un resultado cross-instrument.
El Caso Medido: Posicion en Cola y Probabilidad de Fill

Esta es la unica pregunta causal en el articulo donde el proyecto ya tiene los datos, y deberia ejecutarse en lugar de plantearse. Analisis de posicion en cola ya cubre estimacion de posicion, mecanica FIFO, tasas de drenaje y tiempo-a-fill en datos reales de libro; simulacion de fill cubre modelado de probabilidad de fill y el bucle de calibracion contra fills en vivo. Ambos producen un modelo predictivo de fills. DML convierte las mismas entradas en una estimacion causal.
La especificacion, pre-registrada antes de mirar la estimacion:
- Resultado : lleno dentro de
HORIZONsnapshots (binario). - Tratamiento : posicion en cola normalizada al colocarse.
- Confundidores : volatilidad realizada 1s, spread cotizado en bps, desbalance de profundidad, tamano de nivel al post, distancia desde mid en ticks, codificacion de hora del dia, etiqueta de regimen.
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)
El resultado a reportar es una comparacion de cuatro columnas, no un solo coeficiente: la estimacion naiva OLS de sobre solo, la estimacion de control lineal de sobre y , la estimacion DML con su error estandar, y el valor de robustez del analisis de sensibilidad — que tan fuerte tendria que ser un confundidor no observado para anular el efecto. La brecha entre las columnas naiva y DML es la cantidad de interes real: es cuanto del valor aparente de la posicion en cola era estado del mercado usando un disfraz.
Un nulo o negativo aqui es un resultado publicable y se ajusta mejor a este blog que uno positivo limpio. Si el efecto causal de la posicion en cola colapsa una vez que la volatilidad y el tamano de nivel se parcialan fuera, ese es un hallazgo directo sobre la politica de colocacion de ordenes: el lugar no es lo que gana el fill, las condiciones bajo las que obtuviste el lugar lo son.
Analisis de Factor Causal
El enfoque estandar para la inversion en factores es asociativo: ordena por una caracteristica, forma carteras long-short, observa que los retornos difieren. DML permite una prueba diferente — estimar el efecto causal directo de una caracteristica sobre los retornos, limpiando los efectos de confusión de las otras caracteristicas. Si el efecto desaparece bajo DML, el factor no es causalmente independiente; es un proxy.
Esta es una segunda, forma independiente de escepticismo de factores, y vale la pena ser explicito sobre como se relaciona con la que el blog ya publica. El Sharpe ratio desinflado ataca el zoo de factores desde el lado de seleccion: con suficientes pruebas, un factor puede parecer significativo puramente porque miraste muchas veces. DML lo ataca desde el lado de confusion: un factor puede parecer significativo en una sola prueba honesta y aun ser un proxy de algo mas en el conjunto de condicionamiento. Un factor tiene que sobrevivir a ambos para ser interesante, y los dos modos de fallo son independientes — pasar uno no te dice nada sobre el otro.
Lo Que DML No Puede Hacer
-
Requiere que los confundidores sean observados. Si una variable no observada impulsa tanto el tratamiento como el resultado, DML esta sesgado, y ninguna sofisticacion ML arregla un problema de identificacion. El analisis de sensibilidad acota el riesgo; no lo elimina.
-
Estima un efecto promedio. Si el efecto de la posicion en cola varia fuertemente a traves de regimenes, la estimacion de punto es el promedio sobre la mezcla de regimenes de tu muestra. Para heterogeneidad usa el Interactive Regression Model (
DoubleMLIRM) o un bosque causal. -
Asume un modelo estructural. La especificacion parcialmente lineal requiere que el tratamiento entre en la ecuacion de resultado de una manera particular. Si el proceso verdadero es fundamentalmente diferente, DML esta confiadamente equivocado.
-
No descubre estructura causal. DML estima el efecto de un tratamiento pre-especificado. No te dice que variables son causas.
-
No te exime de pruebas multiples. Repetir el punto anterior porque es el mas comunmente saltado: la ortogonalidad de-biasa la estimacion de molestia, no la busqueda de especificacion.
Notas Practicas
Tamano de muestra. DML necesita que los modelos de molestia converjan a , lo que en la practica significa suficientes filas para que los modelos ML aproximen y en absoluto. En lugar de confiar en umbrales de numeros redondos, establece adecuacion empiricamente de la manera en que validacion multi-simbolo lo hace — verifica si la estimacion se mantiene a traves de instrumentos y sub-periodos, y trata la inestabilidad como la senal que es.
Eleccion de learner. El hecho especifico de DML es estrecho pero util: dada la convergencia , el learner afecta la eficiencia de (ancho del intervalo), no su consistencia. Que learners vale la pena alcanzar en datos de mercado tabulares, y por que el gradient boosting es el predeterminado, ya esta cubierto en modelado de spread con machine learning. Si se mueve materialmente a traves de learners, eso no es un menu para elegir — es evidencia de que las funciones de molestia estan mal estimadas, y por la seccion anterior, elegir el mas amistoso convierte el ejercicio en una busqueda.
Conclusion
DML le da al blog algo que no tenia: una manera de establecer una reclamacion de microestructura de mercado como un parametro causal con un error estandar defendible, en lugar de como una prediccion con una buena puntuacion de validacion.
Las tres ideas que soportan carga son:
- Ortogonaliza el score para que los errores de primera etapa se compensen a segundo orden.
- Cross-fit, con folds purgados y embargados en datos de series temporales, para que el overfitting de primera etapa no pueda desplazar .
- Pre-especifica, para que el intervalo que reportas es el intervalo que realmente ganaste.
El estimador es la parte facil. Las partes duras siguen sin cambios: decidir que confundidores importan, argumentar que los supuestos de identificacion se mantienen, y resistir el impulso de ejecutar la especificacion una vez mas.
Referencias
El linaje de DML es corto y vale una linea: es el modelo parcialmente lineal de Robinson (1988) con ML reemplazando los estimadores de nucleo, alcanzando el limite de eficiencia semiparametrica, con una condicion de ortogonalidad que se remonta al test C() de Neyman y un primo cercano en la literatura de aprendizaje dirigido (TMLE). La contribucion de Chernozhukov et al. fue mostrar que esto podia operacionalizarse con learners ML arbitrarios mientras se retiene inferencia -consistente, asintoticamente 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.