← Retour aux articles
August 2, 2026
5 min de lecture

Double Machine Learning : Estimer un Paramètre Causal au lieu de Prédire les Rendements

Double Machine Learning : Estimer un Paramètre Causal au lieu de Prédire les Rendements
#causal-inference
#double-ML
#treatment-effect
#econometrics
#quant

Chaque article de modélisation de ce blog jusqu'à présent pose la même forme de question : étant donné des caractéristiques, prédire un nombre, puis valider que la prédiction survit hors échantillon. Les modèles de spread prédisent le spread. Les modèles de remplissage prédisent la probabilité de remplissage. Tout l'appareil de validation — walk-forward purgé, Sharpe déflaté, taxonomie du look-ahead — existe pour vérifier si une prédiction est réelle.

Cet article pose une forme différente de question, et c'est la seule pièce de machinerie que le blog n'a jamais eue : estimer un seul paramètre scalaire qui a une interprétation causale, et attacher une erreur standard qui survit au fait qu'un modèle ML flexible a été utilisé pour y arriver.

Ce n'est pas une distinction rhétorique. "La position dans la file prédit la probabilité de remplissage" est trivialement vraie et opérationnellement inutile — bien sûr qu'elle le fait, les deux sont pilotés par la profondeur et la volatilité. "Avancer d'une position dans la file cause un changement de θ\theta dans la probabilité de remplissage, l'état du marché étant fixé" est un nombre que vous pouvez mettre dans une politique de placement d'ordres. La première est un ajustement de régression. La seconde nécessite un estimateur qui n'existe pas dans la boîte à outils ML standard, car la régularisation et le surajustement dans une première étape flexible faussent exactement le coefficient qui vous intéresse.

Double Machine Learning (Chernozhukov, Chetverikov, Demirer, Duflo, Hansen, Newey & Robins, 2018) est l'estimateur qui résout ce problème. Tout trader quantitatif a entendu ceci : corrélation n'est pas causalité. DML est la partie qui vient après cette phrase.

Pourquoi la Régression Naïve Échoue

Un confondu d'état de marché caché pilote à la fois le placement dans la file et les résultats de remplissage, créant une association naïve trompeuse

Posons la question sur le territoire propre du blog. Nous voulons l'effet causal de la position dans la file sur la probabilité de remplissage :

  • YiY_i : si l'ordre limite au repos à l'observation ii a été rempli dans l'horizon.
  • DiD_i : position dans la file au placement (normalisée par la taille du niveau).
  • XiX_i : les confondus — volatilité réalisée, spread coté, déséquilibre de profondeur, taille du niveau, heure de la journée, étiquette de régime. Ce sont les variables d'état du marché que le blog calcule déjà dans modélisation du spread avec le machine learning.

Le paramètre causal est θ0\theta_0 dans

Yi=Diθ0+g0(Xi)+ϵiY_i = D_i \theta_0 + g_0(X_i) + \epsilon_i

g0(Xi)g_0(X_i) capture la relation (potentiellement complexe, non linéaire) entre l'état du marché et le résultat de remplissage.

Le traitement n'est pas assigné aléatoirement. Vous êtes près du front de la file parce que le niveau était fin, ou parce que vous avez posté pendant une période calme, ou parce que le carnet était déséquilibré en votre faveur. Les mêmes conditions pilotent indépendamment si vous êtes rempli. C'est la confusion.

Approche 1 : Ignorer les confondus. Régresser YY sur DD seul. L'estimation absorbe l'effet de chaque confondu corrélé avec les deux. Biais de variable omise教科书 : les niveaux fins vous donnent à la fois une bonne place dans la file et un taux de remplissage élevé, donc vous exagérez la valeur de la place elle-même.

Approche 2 : Régression linéaire avec contrôles. Régresser YY sur DD et XX. Cela ne fonctionne que si g0(X)g_0(X) est vraiment linéaire. La dynamique du carnet ne l'est pas — la relation remplissage/volatilité a des seuils, l'effet de déséquilibre de profondeur change de signe selon le régime. Spécifier mal g0g_0 réintroduit le biais.

Approche 3 : Prédiction ML. Ajuster un modèle gradient-boosted sur (D,X)(D, X). Vous obtenez une bonne discrimination hors échantillon, et aucune interprétation causale whatsoever. Le modèle capture chaque motif prédictif, causal ou non ; la régularisation rétrécit la contribution du traitement de manière à biaiser θ\theta ; et il n'y a pas d'erreur standard en laquelle vous pouvez avoir confiance.

C'est la tension centrale. ML est bon pour la prédiction, mais l'application naïve à un paramètre causal produit des estimations biaisées, non normales, non fiables.

Le Modèle Partiellement Linéaire

Deux canaux de résidualisation synchronisés suppriment l'état de marché nuisible avant que des flux résiduels propres ne se rencontrent à une estimation causale orthogonale

DML opère dans un cadre structurel. Le cheval de labour est la régression partiellement linéaire (PLR) :

Y=Dθ0+g0(X)+U,E[UX,D]=0Y = D\theta_0 + g_0(X) + U, \quad \mathbb{E}[U \mid X, D] = 0

D=m0(X)+V,E[VX]=0D = m_0(X) + V, \quad \mathbb{E}[V \mid X] = 0

  • θ0\theta_0 est le paramètre causal d'intérêt.
  • g0(X)g_0(X) est une fonction de nuisance — la partie du résultat expliquée par l'état du marché.
  • m0(X)m_0(X) est une autre fonction de nuisance — l'espérance conditionnelle du traitement étant donné l'état du marché (la "propensity" dans un cadre de traitement continu).
  • UU et VV sont des résidus structurels.

L'insight clé : θ0\theta_0 est de basse dimension, mais g0g_0 et m0m_0 peuvent être arbitrairement complexes. Nous voulons que ML gère les fonctions de nuisance tout en délivrant encore une inférence valide sur le scalaire.

Pourquoi "Double" ?

Deux modèles ML, pas un seul :

  1. Modèle de résultat : ^(X)E[YX]\hat{\ell}(X) \approx \mathbb{E}[Y \mid X] — prédire le résultat à partir de l'état du marché seul.
  2. Modèle de traitement : m^(X)E[DX]\hat{m}(X) \approx \mathbb{E}[D \mid X] — prédire le traitement à partir de l'état du marché seul.

Former les résidus

Y~i=Yi^(Xi),D~i=Dim^(Xi)\tilde{Y}_i = Y_i - \hat{\ell}(X_i), \quad \tilde{D}_i = D_i - \hat{m}(X_i)

et estimer θ0\theta_0 en régressant Y~\tilde{Y} sur D~\tilde{D} :

θ^0=iD~iY~iiD~i2\hat{\theta}_0 = \frac{\sum_i \tilde{D}_i \tilde{Y}_i}{\sum_i \tilde{D}_i^2}

C'est Frisch-Waugh-Lovell aux stéroïdes : partial out les confondus avec ML au lieu d'une projection linéaire, puis lire l'effet du traitement à partir de la variation résiduelle.

Orthogonalité de Neyman : Pourquoi Ça Marche

L'approche de partial-out naïve (estimer g0g_0, soustraire, régresser) échoue car les erreurs d'estimation ML dans g^0\hat{g}_0 se propagent directement dans θ^0\hat\theta_0. Le score DML est construit pour être Neyman orthogonal — insensible aux petites perturbations dans les fonctions de nuisance.

Le score orthogonal pour PLR :

ψ(W;θ,η)=[Y(X)θ(Dm(X))][Dm(X)]\psi(W; \theta, \eta) = \big[Y - \ell(X) - \theta(D - m(X))\big] \cdot \big[D - m(X)\big]

η=(,m)\eta = (\ell, m). La condition d'orthogonalité est

ηE[ψ(W;θ0,η)]η=η0=0\left. \frac{\partial}{\partial \eta} \mathbb{E}\big[\psi(W; \theta_0, \eta)\big] \right|_{\eta = \eta_0} = 0

Intuitivement, le score n'utilise que la variation dans DD et YY qui est indépendante de XX, et les erreurs dans une fonction de nuisance sont compensées par l'autre. Si m^\hat{m} sur-prédit légèrement le traitement, D~\tilde{D} est légèrement trop petit, mais l'erreur correspondante dans Y~\tilde{Y} d'avoir mal estimé \ell pousse dans une direction compensatoire. Le biais devient du second ordre — le produit de deux erreurs de première étape — plutôt que du premier ordre.

Formellement, si les deux estimateurs de nuisance convergent au taux n1/4n^{-1/4} (doux ; la plupart des méthodes ML raisonnables satisfont cela), alors

N(θ^0θ0)dN(0,σ2)\sqrt{N}(\hat{\theta}_0 - \theta_0) \xrightarrow{d} \mathcal{N}(0, \sigma^2)

donc θ^0\hat\theta_0 converge au taux paramétrique et est asymptotiquement normal.

Cross-Fitting : Pourquoi C'est Obligatoire Ici

L'orthogonalité seule ne suffit pas. Si les modèles de nuisance sont ajustés sur les mêmes lignes utilisées pour estimer θ0\theta_0, le surajustement de première étape contamine la deuxième étape — et le dommage spécifique vaut la peine d'être énoncé précisément, car ce n'est pas le dommage auquel vous êtes habitué. Ailleurs, le surajustement se manifeste comme un score de validation gonflé : vous le remarquez, vous le rabattez, vous continuez. Ici, il se manifeste comme une estimation de point décalée pour θ0\theta_0, avec un intervalle de confiance toujours étroit et toujours centré sur le mauvais nombre. Il n'y a pas de score dont être soupçonneux. L'estimateur ment simplement tranquillement.

Le cross-fitting brise la dépendance : les prédictions de nuisance de chaque observation viennent d'un modèle entraîné sans elle, et θ0\theta_0 est estimé à partir des résidus held-out regroupés. La mécanique est la machinerie K-fold ordinaire, couverte dans modélisation du spread avec le machine learning ; ce qui compte en bas est quels folds vous lui donnez.

L'Algorithme DML Étape par Étape

Entrée : données {(Yi,Di,Xi)}i=1N\{(Y_i, D_i, X_i)\}_{i=1}^N, méthodes ML M\mathcal{M}_\ell et Mm\mathcal{M}_m, folds KK.

Étape 1 — Partition : diviser {1,,N}\{1, \ldots, N\} en KK folds disjoints.

Étape 2 — Cross-fit les modèles de nuisance : pour k=1,,Kk = 1, \ldots, K, entraîner ^(k)\hat{\ell}^{(-k)} et m^(k)\hat{m}^{(-k)} sur le complément du fold kk, puis calculer Y~i=Yi^(k)(Xi)\tilde{Y}_i = Y_i - \hat{\ell}^{(-k)}(X_i) et D~i=Dim^(k)(Xi)\tilde{D}_i = D_i - \hat{m}^{(-k)}(X_i) pour iIki \in I_k.

Étape 3 — Estimation :

θ^0=(i=1ND~i2)1i=1ND~iY~i\hat{\theta}_0 = \left(\sum_{i=1}^N \tilde{D}_i^2\right)^{-1} \sum_{i=1}^N \tilde{D}_i \tilde{Y}_i

Étape 4 — Inférence :

σ^2=1Ni=1N(Y~iθ^0D~i)2D~i2/(1Ni=1ND~i2)2\hat{\sigma}^2 = \frac{1}{N} \sum_{i=1}^N \big(\tilde{Y}_i - \hat{\theta}_0 \tilde{D}_i\big)^2 \tilde{D}_i^2 \bigg/ \left(\frac{1}{N} \sum_{i=1}^N \tilde{D}_i^2\right)^2

avec intervalles θ^0±zα/2σ^/N\hat{\theta}_0 \pm z_{\alpha/2} \cdot \hat{\sigma} / \sqrt{N}.

L'intervalle de confiance est valide pour exactement une question

C'est la réserve qui décide si un résultat DML vaut quelque chose, et c'est là que la plupart des usages appliqués de la méthode s'effondrent silencieusement.

La normalité asymptotique ci-dessus est une déclaration sur un traitement prédéfini, un ensemble de confondus prédéfini, un score prédéfini. Fixez ceux à l'avance, exécutez l'estimateur une fois, et l'intervalle signifie ce qu'il dit. Essayez trois traitements candidats, ou quatre ensembles de confondus, ou swappez les learners jusqu'à ce que la p-value ait l'air mieux, et vous ne faites plus d'inférence — vous exécutez une recherche, et la p-value rapportée est la p-value d'un maximum, pas d'un tirage.

Le blog a déjà mesuré ce que cela fait. Dans l'étude du Sharpe ratio déflaté, les recherches sur du bruit pur avec zéro avantage réel produisent un taux de fausse découverte naïf de 1,000 — le test non ajusté se déclenche à chaque fois — alors que la p-value naïve médiane du gagnant s'assoit près de 0,0007. Rien dans l'orthogonalité de Neyman ne vous protège de cela. L'orthogonalité corrige le biais de l'estimation de nuisance ; elle ne dit rien du biais de la recherche de spécification. Une p-value DML de 1e-05 obtenue après avoir essayé six spécifications mérite exactement le même traitement Bonferroni/Holm/BHY que tout autre gagnant tiré d'une grille, avec MM réglé au nombre de spécifications que vous avez réellement exécutées.

Cela a une conséquence pratique directe pour les fonctionnalités de commodité des outils. DoubleMLData accepte une liste dans d_cols et retournera avec plaisir trois effets de traitement dans un seul tableau récapitulatif :

dml_data_multi = dml.DoubleMLData(
    df, y_col='filled', d_cols=['queue_pos', 'toxicity', 'spread_at_post'],
    x_cols=confounder_cols,
)

Trois lignes, trois p-values, et un problème de tests multiples que le tableau récapitulatif ne mentionne pas. Si vous lisez les trois, ajustez les trois. Si seulement un était la question préenregistrée, dites-le, et traitez les deux autres explicitement comme exploratoires.

Cross-Fitting sur Séries Temporelles : Purge, Embargo, Folds Personnalisés

Les folds de séries temporelles rotatifs utilisent des lacunes de purge et des zones d'embargo avant que les résidus out-of-fold ne s'assemblent en une estimation causale unique

DML standard suppose des observations i.i.d. Les données de carnet ne le sont pas, et le mode d'échec est celui que le blog a déjà documenté en détail : les lignes adjacentes partagent des fenêtres forward qui se chevauchent, donc un TimeSeriesSplit ordinaire fuite encore la réponse à travers la limite du fold. Voir modélisation du spread avec le machine learning pour l'implémentation walk-forward purgée et embarguée et la raison pour laquelle un écart d'au moins horizon lignes est requis, et la taxonomie du biais de look-ahead pour le catalogue complet des fuites et leurs grandeurs mesurées.

La partie vraiment spécifique à DML est comment vous remettez des folds purgés à l'estimateur, car set_sample_splitting a un contrat qui fait trébucher les gens :

import numpy as np
import doubleml as dml

def purged_folds(n: int, n_splits: int, horizon: int):
    """Folds à fenêtre expansive avec un écart purge/embargo de `horizon` lignes.

    Même construction que le CV walk-forward purgé dans l'article de
    modélisation du spread : l'écart élimine le chevauchement entre la fenêtre
    forward d'une ligne d'entraînement et une ligne de validation.
    """
    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()

Deux choses à savoir, aucune d'entre elles évidente à partir des docs de la bibliothèque :

  1. Les folds walk-forward purgés ne couvrent pas chaque ligne. Les écarts de purge et le bloc d'entraînement initial ne sont jamais le fold de test de personne, donc θ0\theta_0 est estimé à partir de strictement moins de NN résidus. C'est un comportement correct, pas un bug, mais cela signifie que le NN effectif dans la formule de variance est le nombre de lignes de test regroupées — vérifiez-le plutôt que de le supposer.
  2. Les répétitions n_rep ne sont pas gratuites ici. Avec K-fold aléatoire, répéter le cross-fitting et moyenner est une réduction de variance bon marché. Avec un split déterministe ordonné dans le temps, il n'y a qu'un seul split, donc n_rep n'achète rien et ne cache rien ; la stabilité doit venir de la réexécution sur différentes fenêtres de données à la place.

Pour les structures de panel (plusieurs symboles sur la même période), DoubleML prend en charge les erreurs standard robustes en grappe — grouper sur symbole, pas sur temps, et voir validation multi-symboles pour la position du blog sur quand un résultat cross-instrument est réellement établi.

Le Cas Mesuré : Position dans la File et Probabilité de Remplissage

Les positions d'ordre dans une file FIFO convergent vers un effet de position dans la file ajusté DML avec un halo de confiance

C'est la seule question causale dans l'article où le projet a déjà les données, et elle devrait être exécutée plutôt que posée. L'analyse de position dans la file couvre déjà l'estimation de position, la mécanique FIFO, les taux de drainage et le temps-à-remplissage sur de vraies données de carnet ; la simulation de remplissage couvre la modélisation de probabilité de remplissage et la boucle d'étalonnage contre les remplissages en direct. Les deux produisent un modèle prédictif de remplissages. DML transforme les mêmes entrées en une estimation causale.

La spécification, préenregistrée avant de regarder l'estimation :

  • Résultat YY : rempli dans HORIZON snapshots (binaire).
  • Traitement DD : position dans la file normalisée au placement.
  • Confondus XX : volatilité réalisée 1s, spread coté en bps, déséquilibre de profondeur, taille de niveau au post, distance du mid en ticks, encodage de l'heure de la journée, étiquette de régime.
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)

Le résultat à rapporter est une comparaison à quatre colonnes, pas un seul coefficient : l'estimation naïve OLS de YY sur DD seul, l'estimation de contrôle linéaire de YY sur DD et XX, l'estimation DML avec son erreur standard, et la valeur de robustesse de l'analyse de sensibilité — à quel point un confondu non observé devrait être fort pour annuler l'effet. L'écart entre les colonnes naïves et DML est la quantité d'intérêt réel : c'est combien de la valeur apparente de la position dans la file était de l'état du marché déguisé.

Un θ\theta nul ou négatif ici est un résultat publiable et correspond mieux à ce blog qu'un positif propre. Si l'effet causal de la position dans la file s'effondre une fois la volatilité et la taille de niveau partiellement éliminées, c'est un résultat direct sur la politique de placement d'ordres : la place n'est pas ce qui gagne le remplissage, les conditions dans lesquelles vous avez obtenu la place le sont.

Analyse de Facteur Causal

L'approche standard à l'investissement factoriel est associatif : trier par une caractéristique, former des portefeuilles long-court, observer que les rendements diffèrent. DML permet un test différent — estimer l'effet causal direct d'une caractéristique sur les rendements, nettoyant les effets de confusion des autres caractéristiques. Si l'effet disparaît sous DML, le facteur n'est pas indépendamment causal ; c'est un proxy.

C'est une deuxième, forme indépendante de scepticisme factoriel, et cela vaut la peine d'être explicite sur la façon dont cela se rapporte à celui que le blog publie déjà. Le Sharpe ratio déflaté attaque le zoo de facteurs du côté de la sélection : avec suffisamment d'essais, un facteur peut paraître significatif purement parce que vous avez regardé plusieurs fois. DML l'attaque du côté de la confusion : un facteur peut paraître significatif sur un seul test honnête et être toujours un proxy pour autre chose dans l'ensemble de conditionnement. Un facteur doit survivre aux deux pour être intéressant, et les deux modes d'échec sont indépendants — en passer un ne vous dit rien sur l'autre.

Ce Que DML Ne Peut Pas Faire

  1. Il exige que les confondus soient observés. Si une variable non observée pilote à la fois le traitement et le résultat, DML est biaisé, et aucune sophistication ML ne corrige un problème d'identification. L'analyse de sensibilité borne le risque ; elle ne l'élimine pas.

  2. Il estime un effet moyen. Si l'effet de la position dans la file varie fortement à travers les régimes, l'estimation de point est la moyenne sur le mix de régimes de votre échantillon. Pour l'hétérogénéité, utilisez le Interactive Regression Model (DoubleMLIRM) ou une forêt causale.

  3. Il suppose un modèle structurel. La spécification partiellement linéaire exige que le traitement entre dans l'équation de résultat d'une manière particulière. Si le vrai processus est fondamentalement différent, DML est confiantément faux.

  4. Il ne découvre pas de structure causale. DML estime l'effet d'un traitement prédéfini. Il ne vous dit pas quelles variables sont des causes.

  5. Il ne vous exempte pas des tests multiples. Répéter le point ci-dessus parce que c'est le plus souvent sauté : l'orthogonalité de-biaise l'estimation de nuisance, pas la recherche de spécification.

Notes Pratiques

Taille d'échantillon. DML exige que les modèles de nuisance convergent à n1/4n^{-1/4}, ce qui en pratique signifie suffisamment de lignes pour que les modèles ML approximent g0g_0 et m0m_0 du tout. Plutôt que de faire confiance à des seuils de nombres ronds, établissez l'adéquation empiriquement de la manière dont la validation multi-symboles le fait — vérifiez si l'estimation tient à travers les instruments et les sous-périodes, et traitez l'instabilité comme le signal qu'elle est.

Choix du learner. Le fait spécifique à DML est étroit mais utile : étant donné la convergence n1/4n^{-1/4}, le learner affecte l'efficacité de θ^0\hat\theta_0 (largeur d'intervalle), pas sa cohérence. Quels learners valent la peine d'atteindre sur les données de marché tabulaires, et pourquoi le gradient boosting est le défaut, est déjà couvert dans modélisation du spread avec le machine learning. Si θ^0\hat\theta_0 se déplace matériellement à travers les learners, ce n'est pas un menu à choisir — c'est la preuve que les fonctions de nuisance sont mal estimées, et par la section ci-dessus, choisir le plus convivial transforme l'exercice en une recherche.

Conclusion

DML donne au blog quelque chose qu'il n'avait pas : un moyen d'énoncer une réclamation de microstructure de marché comme un paramètre causal avec une erreur standard défendable, plutôt que comme une prédiction avec un bon score de validation.

Les trois idées porteuses sont :

  • Orthogonalisez le score pour que les erreurs de première étape se compensent au second ordre.
  • Cross-fit, avec des folds purgés et embargués sur les données de séries temporelles, pour que le surajustement de première étape ne puisse pas déplacer θ0\theta_0.
  • Prédéfinissez, pour que l'intervalle que vous rapportez est l'intervalle que vous avez réellement gagné.

L'estimateur est la partie facile. Les parties difficiles restent inchangées : décider quels confondus importent, plaider que les hypothèses d'identification tiennent, et résister à l'envie d'exécuter la spécification une fois de plus.


Références

La lignée de DML est courte et vaut une ligne : c'est le modèle partiellement linéaire de Robinson (1988) avec ML remplaçant les estimateurs de noyau, atteignant la borne d'efficience semi-paramétrique, avec une condition d'orthogonalité remontant au test C(α\alpha) de Neyman et un proche cousin dans la littérature de l'apprentissage ciblé (TMLE). La contribution de Chernozhukov et al. était de montrer que cela pouvait être rendu opérationnel avec des learners ML arbitraires tout en retenant l'inférence N\sqrt{N}-cohérente, asymptotiquement normale.

  1. 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.
  2. Robinson, P. M. (1988). Root-N-Consistent Semiparametric Regression. Econometrica, 56(4), 931-954.
  3. 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.
  4. Facure, M. (2022). Causal Inference for the Brave and True. Chapter 22: Debiased/Orthogonal Machine Learning.
  5. Cahan, E., Bai, J., & Ng, S. (2024). Causal Factor Investing. Quantitative Finance.
blog.disclaimer

Authors

Eugen Soloviov
Eugen Soloviov

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.

Newsletter

Gardez une longueur d'avance sur le marché

Abonnez-vous à notre newsletter pour des insights exclusifs sur le trading IA, des analyses de marché et des mises à jour de la plateforme.

Nous respectons votre vie privée. Désabonnement possible à tout moment.