Méthodes de contrôle synthétiques pour évaluer les stratégies de trading
Cette série a passé beaucoup de temps sur une route vers un faux bord : la sélection. Le ratio de Sharpe dégonflé évalue le gagnant d'une recherche. La probabilité de surajustement du backtest évalue la recherche elle-même. Le négatif honnête est ce qui se produit lorsque vous pointez les deux vers une stratégie que vous vouliez réellement échanger. Cet appareil répond bien à une question : est-ce que j'ai trouvé cela parce que j'ai cherché trop de fois ?
Cela ne touche pas à une deuxième voie, entièrement distincte : confondante. Vous avez changé une chose – déployé un nouvel algorithme d’exécution, changé un paramètre, réagi à un régime – et les performances se sont améliorées. Il n'y a pas eu de recherche. Il n’y a eu aucun problème de tests multiples. Et l’amélioration n’a peut-être toujours rien à voir avec vous, car la volatilité a doublé la semaine où vous avez expédié. Aucune déflation ne permet de détecter cela, car la déflation corrige les essais et vous n'en avez exécuté qu'un seul.
La méthode de contrôle synthétique (SCM), développée par Abadie et Gardeazabal (2003) et affinée par Abadie, Diamond et Hainmueller (2010, 2015), s'attaque directement à la confusion. Il construit un contrefactuel — une combinaison pondérée d'instruments que vous n'avez pas touchés, choisis de manière à suivre de près l'instrument traité avant l'intervention. La divergence post-intervention entre les deux est votre estimation de l’effet. Fondamentalement, SCM est livré avec un critère de falsification qui vous indique quand il ne peut pas produire un contrefactuel crédible, et une valeur p basée sur la permutation qui ne vous oblige pas à croire une histoire asymptotique.
Pourquoi les alternatives évidentes échouent

La comparaison avant-après confond l’intervention avec tout ce qui a changé à cette date. La comparaison avec un seul instrument de référence échoue car aucun actif ne suit le vôtre — c'est le piège à instrument unique dans l'autre sens : si la structure idiosyncratique d'un instrument peut simuler un avantage, la structure idiosyncratique d'un instrument peut également simuler un contrôle. Le pool de donateurs de SCM est la réponse formelle à cette objection : au lieu de choisir un actif comparable, vous laissez les données pré-périodes en choisir un panier pondéré.
La différence dans les différences mérite plus qu’une phrase, car c’est un quasi-accident. DiD compare le changement dans l'unité traitée au changement dans un groupe témoin, et identifie l'effet uniquement sous des tendances parallèles : sans l'intervention, le traitement et le contrôle auraient bougé ensemble. Sur les marchés financiers, cette hypothèse est presque indéfendable : les actifs diffèrent en termes de bêta, de régime de volatilité, de niveau de liquidité, et leurs trajectoires relatives varient. SCM remplace l'hypothèse par un objet ajusté : plutôt que de supposer un contrôle qui se déplace en parallèle, il en construit un et vous montre ensuite dans quelle mesure il a réellement été suivi. Si le suivi est mauvais, on vous dit d'arrêter.
La méthode

Configuration et notation
Considérez unités (actifs, stratégies ou portefeuilles) observées au cours périodes. L'unité 1 est l'unité traitée — l'actif ou la stratégie dans laquelle vous êtes intervenu. Unités former le pool de donneurs d'unités comparables non traitées.
Laisser désigne le résultat pour l'unité traitée à un moment donné avec l'intervention, et le résultat sans cela. L'effet du traitement à un moment donné est:
Nous observons directement. Tout le problème est d'estimer .
Construction du contrôle synthétique
Estimations SCM comme moyenne pondérée des résultats des donateurs :
où le vecteur poids satisfait pour tous et .
Ces deux contraintes font un vrai travail. Ils forcent le contrôle synthétique à être une combinaison convexe de donneurs, ce qui empêche l'extrapolation en dehors du support des données. Une régression sans contrainte peut vous fournir un contrefactuel construit à partir d’une position longue de 3,4x dans une pièce contre une position courte de 2,4x dans une autre – numériquement un excellent ajustement avant la période et un contrefactuel qui ne correspond à aucun portefeuille que quiconque pourrait détenir. La contrainte de convexité rend le contrefactuel interprétable et les pondérations clairsemées : généralement, seule une poignée de donateurs obtiennent un poids non nul, et vous pouvez les lire.
Sélection optimale du poids
Les poids sont choisis pour minimiser la distance entre l'unité traitée et le contrôle synthétique dans la période pré-intervention :
où est un vecteur de caractéristiques pré-intervention de l'unité traitée, est le matrice des mêmes caractéristiques pour le pool de donateurs, et est un matrice diagonale semi-définie positive attribuant une importance à chaque prédicteur.
est choisi par validation croisée : pick de telle sorte que le résultat minimise l'erreur quadratique moyenne de prédiction (MSPE) de la variable de résultat dans la période pré-intervention. Il s'agit d'une optimisation imbriquée - une boucle externe sur , une solution contrainte interne pour .
Variables prédictives pour les applications de trading
Où Abadie et al. En utilisant le PIB par habitant et la composition industrielle, les applications de trading souhaitent :
- Caractéristiques de rendement : rendement moyen, volatilité, asymétrie, kurtosis sur la pré-période
- Mesures de liquidité : spread moyen, volume quotidien, ratio d'illiquidité Amihud
- Caractéristiques de la microstructure : déséquilibre du flux d'ordres, taux d'arrivée des transactions, ratio cotation/transaction
- Expositions aux facteurs : facteurs bêta par rapport au marché, momentum, valeur et volatilité
- Résultats décalés : valeurs PnL cumulées à plusieurs dates pré-intervention
Les résultats décalés comptent le plus. Abadie et coll. (2010) montrent que si le contrôle synthétique correspond à l'unité traitée sur des résultats décalés sur une longue fenêtre de pré-intervention, il contrôle implicitement les facteurs de confusion non observés dans le cadre d'un modèle à facteurs linéaires - ce qui est la seule raison pour laquelle la méthode en vaut la peine. Vous n'êtes pas obligé de nommer le facteur de confusion qui a conduit votre PnL. Vous devez également trouver des donateurs qui y ont été exposés.
Où cela s'applique

Scénario 1 : Évaluation d'un nouvel algorithme d'exécution
Vous déployez un nouveau planning TWAP sur un instrument et souhaitez connaître son effet sur le déficit de mise en œuvre. La métrique et la famille d'algorithmes sont couvertes en profondeur ailleurs - voir implementation shortfall and TCA pour la décomposition des coûts et TWAP/VWAP/POV algorithms pour les planificateurs eux-mêmes. La contribution SCM est la couche d'évaluation supérieure : le pool de donateurs est constitué des mêmes instruments qui exécutent toujours l'ancien planificateur, sur la même fenêtre, de sorte que les changements de répartition ou de volume à l'échelle du site affectent à la fois les traités et les donateurs.
Période de pré-intervention : 60 jours de bourse avant le switch. Période post-intervention : 30 jours de bourse après. L'estimation de l'effet est l'écart :
Si le nouveau planificateur réduit réellement les coûts, avec persistance après – et, plus important encore, les lacunes traitées se situent en dehors du nuage des lacunes des donateurs.
Scénario 2 : Impact d'un événement de marché
Un changement de barème de frais, un projet pilote de taille de tick, une taxe sur les transactions ou un changement de règle de coupe-circuit touche un seul endroit. Unité traitée : votre stratégie sur le site concerné. Pool de donateurs : la même paire sur les sites que le changement n'a pas touchés. Les effets de la structure des frais sur l'exécution sont traités séparément dans frais et remises maker-taker ; SCM est ce qui transforme « nos remplissages se sont détériorés après le changement » en une estimation avec une valeur nulle attachée.
Scénario 3 : Changement de stratégie en fonction de conditions de régime
Vous passez du retour à la moyenne à l'élan sur un actif lorsqu'un signal de détection de régime se déclenche. Le changement a-t-il été préférable de rester sur place ? Pool de donateurs : actifs similaires sur lesquels le signal s'est déclenché mais vous n'avez pas changé. Notez le piège ici : si le signal du régime se déclenche à l’échelle du marché, vos donateurs sont également traités et la conception s’effondre. Voir la règle de débordement ci-dessous.
Tests placebo et inférence

L'inférence de SCM est basée sur la permutation. L'argument général en faveur de la construction d'un nul empirique par rééchantillonnage plutôt que de faire confiance à une distribution de forme fermée est présenté dans Méthodes de Monte Carlo et bootstrap pour les backtests ; ce qui suit est la construction spécifique à SCM.
Placebo à temps
Décalez la date d’intervention vers la pré-période – à mi-chemin, disons – et réexécutez. Si le SCM détecte un « effet de traitement » à une date où rien ne s'est produit, il détecte une divergence préexistante et non votre intervention. Un contrôle synthétique crédible ne montre aucun effet à de fausses dates d'intervention.
Placebo dans l'espace (test de permutation)
Appliquez l’intégralité de la procédure SCM à chaque donneur, en prétendant que chacun à son tour était l’unité traitée :
- Pour chaque donateur , construisez un contrôle synthétique à partir des donneurs restants ainsi que de l'unité traitée d'origine.
- Calculer l'écart post-intervention .
- Comparez l'écart de l'unité traitée à la répartition des écarts du placebo.
La valeur p est un rang :
où
Le ratio, plutôt que l’écart brut après la période, est la bonne statistique : un donateur qui n’a jamais été en bonne forme physique présentera un écart post-période important pour des raisons qui n’ont rien à voir avec une intervention, et le diviser par son MSPE d’avant la période pénalise exactement cela.
Il s'agit du même mouvement d'inférence que le Deflated Sharpe Ratio : classez votre candidat dans une distribution de référence générée empiriquement, jamais contre zéro. DSR classe votre gagnant par rapport à un score nul au meilleur des N lors des essais ; SCM classe votre unité traitée par rapport à une valeur nulle sur les unités. Un estimateur différent, la même discipline et le même avertissement s'appliquent : avec donneurs, la plus petite valeur p atteignable est . Un test de permutation ne peut pas résoudre au-delà de sa propre granularité, donc un petit pool de donateurs limite l'importance que vous êtes en droit de revendiquer, quelle que soit l'ampleur de l'effet.
Filtrage pratique
Abadie et coll. recommander d'exclure les unités placebo avec un mauvais ajustement avant l'intervention - pré-MSPE plus de fois celle de l'unité traitée, avec généralement 2 à 20. Les placebos mal ajustés ont de minuscules dénominateurs et produisent d'énormes ratios MSPE, contaminant la distribution de référence et donnant à votre unité traitée un aspect banal. Reporter le ratio à plusieurs seuils ; si votre valeur p n'est significative qu'à un moment particulier , vous avez trouvé un paramètre de réglage, pas un effet.
Implémentation

Le code ci-dessous utilise uniquement numpy et scipy donc la mécanique est visible. Alternatives de production — SparseSC (Recherche Microsoft), pysyncon, SyntheticControlMethods - gérer les cas extrêmes et mieux évoluer.
Construction de la matrice de prédicteurs
import numpy as np
import pandas as pd
from scipy.optimize import minimize
def build_predictors(series: pd.Series, T0: int) -> np.ndarray:
"""
Extract predictor vector from pre-intervention data.
Features: mean return, volatility, skewness, kurtosis,
plus lagged outcome values at regular intervals.
"""
pre = series.iloc[:T0]
daily_ret = pre.diff().dropna()
stats = [
daily_ret.mean(),
daily_ret.std(),
daily_ret.skew(),
daily_ret.kurtosis(),
]
lag_indices = np.linspace(0, T0 - 1, 5, dtype=int)
lags = pre.iloc[lag_indices].values.tolist()
return np.array(stats + lags)
df voici un panel de rendements cumulés — unité traitée dans la colonne 0, donneurs dans le reste, une ligne par barre. Utilisez les rendements cumulés, pas les niveaux de prix.
X1 = build_predictors(df["Treated"], T0).reshape(-1, 1) # (k x 1)
X0 = np.column_stack([ # (k x J)
build_predictors(df[col], T0) for col in df.columns[1:]
])
Optimisation du poids
def solve_weights(
X1: np.ndarray,
X0: np.ndarray,
Y1_pre: np.ndarray,
Y0_pre: np.ndarray,
) -> np.ndarray:
"""
Solve for optimal synthetic control weights.
Nested optimization:
Outer: optimize V (predictor importance)
Inner: optimize w (donor weights) given V
"""
k = X1.shape[0]
J = X0.shape[1]
def solve_w_given_V(V_diag: np.ndarray) -> np.ndarray:
"""Inner: find w minimizing weighted predictor distance."""
V = np.diag(V_diag)
def objective(w):
gap = X1.flatten() - X0 @ w
return gap @ V @ gap
constraints = {"type": "eq", "fun": lambda w: np.sum(w) - 1.0}
bounds = [(0, 1)] * J
w0 = np.ones(J) / J
result = minimize(objective, w0, method="SLSQP",
bounds=bounds, constraints=constraints,
options={"maxiter": 1000, "ftol": 1e-12})
return result.x
def outer_objective(V_diag: np.ndarray) -> float:
"""Outer: minimize pre-period MSPE given V."""
w = solve_w_given_V(np.abs(V_diag))
return np.mean((Y1_pre - Y0_pre @ w) ** 2)
V0 = np.ones(k)
result = minimize(outer_objective, V0, method="Nelder-Mead",
options={"maxiter": 5000, "xatol": 1e-8})
return solve_w_given_V(np.abs(result.x))
Y1_pre = df["Treated"].iloc[:T0].values
Y0_pre = df.iloc[:T0, 1:].values
weights = solve_weights(X1, X0, Y1_pre, Y0_pre)
for col, w in zip(df.columns[1:], weights):
if w > 0.01:
print(f" {col}: {w:.4f}")
La série des écarts est alors df["Treated"].values - df.iloc[:, 1:].values @ weights, tracé par rapport à la date d'intervention ainsi qu'aux écarts entre donateurs par rapport à l'analyse placebo ci-dessous.
Tests placebo
def run_placebo_tests(df: pd.DataFrame, T0: int) -> pd.DataFrame:
"""In-space placebo: treat each unit in turn as if intervened upon."""
results = []
all_columns = df.columns.tolist()
for placebo_col in all_columns:
donor_cols = [c for c in all_columns if c != placebo_col]
donor_df = df[donor_cols]
X1_p = build_predictors(df[placebo_col], T0).reshape(-1, 1)
X0_p = np.column_stack([
build_predictors(donor_df[c], T0) for c in donor_cols
])
w_p = solve_weights(
X1_p, X0_p,
df[placebo_col].iloc[:T0].values,
donor_df.iloc[:T0].values,
)
gap_p = df[placebo_col].values - donor_df.values @ w_p
mspe_pre = np.mean(gap_p[:T0] ** 2)
mspe_post = np.mean(gap_p[T0:] ** 2)
results.append({
"unit": placebo_col,
"mspe_pre": mspe_pre,
"mspe_post": mspe_post,
"mspe_ratio": mspe_post / mspe_pre if mspe_pre > 1e-10 else np.inf,
"gap_series": gap_p,
"is_treated": placebo_col == "Treated",
})
return pd.DataFrame(results)
placebo_results = run_placebo_tests(df, T0)
treated_pre = placebo_results.loc[placebo_results["is_treated"], "mspe_pre"].values[0]
filtered = placebo_results[placebo_results["mspe_pre"] <= 5 * treated_pre]
treated_ratio = filtered.loc[filtered["is_treated"], "mspe_ratio"].values[0]
p_value = (filtered["mspe_ratio"] >= treated_ratio).sum() / len(filtered)
print(f"MSPE ratio (treated): {treated_ratio:.2f} p = {p_value:.3f}")
Calibrage de l'estimateur
Il y a une manifestation qui vaut la peine d’être organisée et une manifestation qui vaut la peine d’être refusée. Générer des données de panel synthétiques, injecter un effet de +0,3 %/jour, récupérer environ +0,3 %/jour et présenter cela comme une preuve prouvant uniquement que SLSQP converge. C'est circulaire, et ce blog ne le publie pas.
Ce à quoi sont utiles les données synthétiques, c'est l'étalonnage - la même norme appliquée dans l'article DSR et PBO, où la valeur nulle connue est ce qui rend la statistique fiable. Deux contrôles, tous deux exécutés sur des données générées à partir d'un modèle factoriel linéaire avec le nombre de donneurs et la durée de la pré-période dont vous disposez réellement :
- Puissance à une taille d'effet connue. Injectez un effet d'ampleur connue. L’écart post-période estimé le récupère-t-il, et dans quelle marge d’erreur ? Baissez la taille de l'effet jusqu'à ce que la récupération échoue - ce plancher est le plus petit effet que la géométrie de votre panneau peut détecter, et tout résultat réel en dessous est du bruit, quelle que soit sa valeur p.
- Taille sous un vrai null. Injectez rien. Exécutez le pipeline placebo complet. La valeur p doit être à peu près uniforme sur , il devrait donc tomber en dessous de 0,10 environ 10 % du temps lors de tirages répétés. S'il se déclenche beaucoup plus souvent que cela, votre ensemble de prédicteurs ou seuil de filtre est important pour la fabrication et le pipeline est rompu avant même qu'il ne touche des données réelles.
Le contrôle 2 est celui que les gens sautent et celui qui compte. Exécutez-le d'abord.
Considérations pratiques

Choisir le pool de donateurs
Les donneurs doivent être plausiblement comparables à l'unité traitée et non affectés par l'intervention. Pour le travail d'exécution : le même algorithme sur des instruments similaires — même secteur, décile de capitalisation boursière, niveau de liquidité. La taxonomie de niveau dans validation multi-symbole est directement réutilisable ici ; les propriétés qui font des instruments un test de robustesse équitable en font également un pool de donneurs équitable. Pour les événements sur place : le même instrument sur les lieux que le changement n'a pas atteint.
Exclure les unités avec débordement. Si la modification de votre algorithme sur un instrument a modifié votre cotation sur des instruments corrélés, ces instruments sont partiellement traités. Les laisser biaise le contrôle synthétique vers le chemin post-période de l'unité traitée et réduit votre estimation vers zéro - un défaut de conception qui produit des résultats nuls aussi facilement qu'un mauvais contrôle produit des résultats positifs.
L'ajustement pré-intervention est tout l'argument
La crédibilité de SCM repose entièrement sur son adéquation avant la période. Signalez la MSPE pré-intervention et montrez l’ajustement. Un mauvais pré-ajustement invalide tout après .
Abadie et coll. (2015) énoncent clairement la règle : si aucune combinaison convexe de donneurs ne reproduit la trajectoire pré-intervention de l'unité traitée, ne pas appliquer la méthode. Il s'agit d'un critère de falsification honnête, et il est plus rare qu'il ne devrait l'être : la plupart des estimateurs renvoient un nombre quel que soit le nombre que vous leur fournissez. SCM vous indique lorsqu’il ne peut pas produire de contrefactuel crédible, et la bonne réponse à ce message est de publier l’échec, et non d’élargir le bassin de donateurs jusqu’à ce que l’adéquation s’améliore. L'élargissement du pool pour chasser le pré-ajustement est le même surajustement dont parle le reste de cette série, déplacé vers l'étape de contrôle-construction.
Surajustement dans les panneaux courts
La quantité spécifique à SCM à surveiller est le ratio de donateurs aux observations pré-périodes . Avec poids libres installés sur points, un pré-ajustement parfait devient réalisable par la construction car approches - et un pré-ajustement parfait obtenu de cette manière ne contient aucune information. Garder sensiblement plus grand que ; si une stratégie a fonctionné 30 jours avant le changement et que vous avez 20 candidats donateurs, vous n'avez pas de problème SCM, vous avez une interpolation. Atténuations :
- Régularisation : SparseSC ajoute et pénalités à l’optimisation du poids.
- Restreindre le pool de donateurs : moins de donateurs, mieux justifiés, battent plus de donateurs — au prix d'une grille de permutation plus grossière, puisque définit également votre valeur p minimale. Cette tension est réelle et n’a pas de résolution claire.
- SCM augmenté : Ben-Michael, Feller et Rothstein (2021) utilisent un modèle de résultats pour corriger les biais lorsqu'un pré-ajustement parfait est impossible à atteindre.
Non-stationnarité
Exécutez le SCM sur les rendements cumulés, jamais sur les niveaux de prix – les niveaux invitent à des ajustements parasites. Confirmez que l’écart pré-intervention est égal à zéro et stationnaire avant de faire confiance à la divergence post-période ; les machines ADF et Engle-Granger pour cela, y compris les valeurs critiques corrigées dont vous avez besoin lors du test d'un résidu ajusté plutôt que d'une série observée, sont couvertes dans [arbitrage statistique et trading de paires] (/en/blog/post/statistical-arbitrage-pairs-trading-crypto).
Plusieurs unités traitées
Le déploiement sur plusieurs actifs à la fois rompt la conception à unité traitée unique. Extensions : conceptions SCM groupées (effets moyens sur toutes les unités traitées) et adoption échelonnée (Ben-Michael et al., 2022) pour les unités traitées à différents moments.
Quand ne pas utiliser SCM

Bien adapté à : une intervention discrète et bien définie à une date connue ; un pool de donneurs raisonnable d'unités comparables non traitées ; interventions non anticipées à l'avance, puisque l'anticipation déplace l'unité traitée avant et viole l'identification.
Peu adapté à : un traitement continu, comme un paramètre qui dérive au fil des semaines ; des paramètres sans comparables véritablement non traités ; évaluation à haute fréquence où le rapport signal/bruit annule l'estimation du poids.
Conclusion

La sélection et la confusion sont des modes de défaillance différents et nécessitent des instruments différents. Le DSR et le DPB évaluent la recherche. SCM évalue le contrefactuel et c'est le seul outil de cette série qui traite le cas où vous avez effectué exactement une expérience et où vous ne pouvez toujours pas faire confiance au résultat.
La raison pour laquelle on le préfère à un critère de référence ad hoc n’est pas qu’il produit des effets plus importants – il en produit souvent de plus petits – mais qu’il peut refuser. Si aucune combinaison convexe de donneurs ne suit votre instrument avant l'intervention, SCM le dit et vous arrêtez. Si l'espace traité se trouve à l'intérieur du nuage du donneur, la valeur p du placebo l'indique et vous signalez une valeur nulle. Ces deux sorties représentent la valeur de la méthode, et un rapport SCM sans MSPE pré-période rapportée et sans valeur p placebo a ignoré les seules parties qui en font plus qu'un graphique de deux lignes divergentes.
Lectures complémentaires
- Abadie, A., Diamond, A. et Hainmueller, J. (2010). "Méthodes de contrôle synthétique pour les études de cas comparatives." Journal de l'American Statistical Association, 105(490), 493-505.
- Abadie, A. (2021). "Utilisation de contrôles synthétiques : faisabilité, exigences en matière de données et aspects méthodologiques." Journal de littérature économique, 59(2), 391-425.
- Ben-Michael, E., Feller, A. et Rothstein, J. (2021). "La méthode de contrôle synthétique augmentée." Journal de l'American Statistical Association, 116(536), 1789-1803. -Cunningham, S. (2021). Inférence causale : la mixtape. Chapitre 10 : Contrôle synthétique. Disponible sur mixtape.scunning.com.
- Recherche Microsoft. SparseSC : contrôles synthétiques clairsemés. github.com/microsoft/SparseSC.
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.