📝

Draft article

This draft is visible to admins and superusers only. Sign in with an authorized account.

← Zurück zu den Artikeln
August 21, 2026
5 min read

Synthetische Kontrollmethoden zur Bewertung von Handelsstrategien

Synthetische Kontrollmethoden zur Bewertung von Handelsstrategien
#causal-inference
#synthetic-control
#counterfactual
#evaluation
#econometrics

Diese Serie hat lange Zeit mit einem Weg zu einer falschen Kante verbracht: Auswahl. Das Deflated Sharpe Ratio ermittelt den Gewinner einer Suche. Die Wahrscheinlichkeit einer Backtest-Überanpassung bewertet die Suche selbst. Das ehrliche Negativ ist das, was passiert, wenn Sie beide auf eine Strategie hinweisen, mit der Sie eigentlich handeln wollten. Dieses Gerät beantwortet eine Frage gut: Habe ich das gefunden, weil ich zu oft gesucht habe?

Es berührt nicht einen zweiten, völlig separaten Weg: verwirrend. Sie haben eine Sache geändert – einen neuen Ausführungsalgorithmus eingesetzt, einen Parameter geändert, auf ein Regime reagiert – und die Leistung verbessert. Es gab keine Suche. Es gab kein Problem mit mehreren Tests. Und die Verbesserung hat möglicherweise immer noch nichts mit Ihnen zu tun, da sich die Volatilität in der Woche, in der Sie versendet haben, verdoppelt hat. Keine noch so große Deflation fängt das auf, weil die Deflation die Versuche korrigiert und Sie nur einen durchgeführt haben.

Die von Abadie und Gardeazabal (2003) entwickelte und von Abadie, Diamond und Hainmueller (2010, 2015) verfeinerte Synthetic Control Method (SCM) greift Confounding direkt an. Es wird ein kontrafaktisches erstellt – eine gewichtete Kombination von Instrumenten, die Sie nicht berührt haben und die so ausgewählt wurde, dass sie dem behandelten Instrument vor dem Eingriff genau folgte. Die Abweichung zwischen beiden nach der Intervention ist Ihre Effektschätzung. Entscheidend ist, dass SCM über ein Falsifikationskriterium verfügt, das Ihnen sagt, wann es kein glaubwürdiges kontrafaktisches Ergebnis liefern kann, sowie über einen permutationsbasierten p-Wert, der nicht erfordert, dass Sie irgendeine asymptotische Geschichte glauben.

Warum die offensichtlichen Alternativen scheitern

Kontrafaktische Vergleichspfade

Der Vorher-Nachher-Vergleich verwechselt den Eingriff mit allem anderen, was sich an diesem Datum geändert hat. Der Vergleich mit einem einzelnen Benchmark-Instrument schlägt fehl, weil kein einzelnes Asset Ihres nachbildet – das ist die Single-Instrument-Falle aus der anderen Richtung: Wenn die eigenwillige Struktur eines Instruments eine Kante vortäuschen kann, kann die eigenwillige Struktur eines Instruments auch eine Kontrolle vortäuschen. Der Spenderpool von SCM ist die formelle Antwort auf genau diesen Einwand: Anstatt einen vergleichbaren Vermögenswert auszuwählen, lassen Sie die Daten vor der Periode einen gewichteten Korb davon auswählen.

„Unterschied-in-Unterschiede“ verdient mehr als einen Satz, denn es handelt sich um ein Beinahe-Missgeschehen. DiD vergleicht die Veränderung in der behandelten Einheit mit der Veränderung in einer Kontrollgruppe und identifiziert den Effekt nur unter parallelen Trends: Ohne die Intervention hätten sich behandelte und Kontrollgruppe zusammen bewegt. Auf den Finanzmärkten ist diese Annahme nahezu unhaltbar – Vermögenswerte unterscheiden sich im Beta, im Volatilitätsregime, in der Liquiditätsstufe und ihre relativen Pfade schwanken. SCM ersetzt die Annahme durch ein angepasstes Objekt: Anstatt ein Steuerelement anzunehmen, das sich parallel bewegt, konstruiert es eines und zeigt Ihnen dann, wie gut es tatsächlich verfolgt wurde. Wenn die Spur schlecht ist, werden Sie aufgefordert, aufzuhören.

Die Methode

Konstruktion synthetischer Kontrollspender

Aufbau und Notation

Überlegen Sie J+1J + 1 Einheiten (Vermögenswerte, Strategien oder Portfolios), die über beobachtet wurden TT Perioden. Einheit 1 ist die behandelte Einheit – der Vermögenswert oder die Strategie, bei der Sie interveniert haben. Einheiten 2,,J+12, \ldots, J+1 bilden den Spenderpool vergleichbarer unbehandelter Einheiten.

Lassen Y1tIY_{1t}^I bezeichnen das Ergebnis für die behandelte Einheit zum jeweiligen Zeitpunkt tt mit der Intervention, und Y1tNY_{1t}^N das Ergebnis ohne. Der Behandlungseffekt zum jeweiligen Zeitpunkt t>T0t > T_0 Ist:

τ1t=Y1tIY1tN\tau_{1t} = Y_{1t}^I - Y_{1t}^N

Wir beobachten Y1tIY_{1t}^I direkt. Das ganze Problem ist das Schätzen Y1tNY_{1t}^N.

Aufbau der synthetischen Kontrolle

SCM-Schätzungen Y1tNY_{1t}^N als gewichteter Durchschnitt der Spenderergebnisse:

Y^1tN=j=2J+1wjYjt\hat{Y}_{1t}^N = \sum_{j=2}^{J+1} w_j \, Y_{jt}

wo der Gewichtsvektor w=(w2,,wJ+1)\mathbf{w} = (w_2, \ldots, w_{J+1})' befriedigt wj0w_j \geq 0 für alle jj Und jwj=1\sum_j w_j = 1.

Diese beiden Einschränkungen leisten echte Arbeit. Sie erzwingen, dass die synthetische Kontrolle eine konvexe Kombination von Spendern ist, was eine Extrapolation außerhalb der Datenunterstützung verhindert. Eine uneingeschränkte Regression kann Ihnen ein kontrafaktisches Ergebnis liefern, das aus einer 3,4-fachen Long-Position in einer Münze gegenüber einer 2,4-fachen Short-Position in einer anderen besteht – numerisch gesehen eine hervorragende Anpassung vor der Periode und ein kontrafaktisches Ergebnis, das keinem Portfolio entspricht, das irgendjemand halten könnte. Die Konvexitätsbeschränkung macht das Kontrafaktische interpretierbar und die Gewichte spärlich: Normalerweise erhalten nur eine Handvoll Spender eine Gewichtung ungleich Null, und Sie können sie lesen.

Optimale Gewichtsauswahl

Die Gewichte werden so gewählt, dass der Abstand zwischen der behandelten Einheit und der synthetischen Kontrolle in der Zeit vor dem Eingriff minimiert wird:

minwX1X0wV=minw(X1X0w)V(X1X0w)\min_{\mathbf{w}} \| \mathbf{X}_1 - \mathbf{X}_0 \mathbf{w} \|_V = \min_{\mathbf{w}} (\mathbf{X}_1 - \mathbf{X}_0 \mathbf{w})' \mathbf{V} (\mathbf{X}_1 - \mathbf{X}_0 \mathbf{w})

Wo X1\mathbf{X}_1 ist ein (k×1)(k \times 1) Vektor der Merkmale vor dem Eingriff für die behandelte Einheit, X0\mathbf{X}_0 ist das (k×J)(k \times J) Matrix gleicher Merkmale für den Spenderpool und V\mathbf{V} ist ein (k×k)(k \times k) positive semidefinite Diagonalmatrix, die jedem Prädiktor Bedeutung zuweist.

V\mathbf{V} wird durch Kreuzvalidierung ausgewählt: pick V\mathbf{V} so dass das Ergebnis w(V)\mathbf{w}^*(\mathbf{V}) minimiert den mittleren quadratischen Vorhersagefehler (MSPE) der Ergebnisvariablen im Zeitraum vor der Intervention. Dies ist eine verschachtelte Optimierung – eine äußere Schleife V\mathbf{V}, eine innere eingeschränkte Lösung für w\mathbf{w}.

Prädiktorvariablen für Handelsanwendungen

Wo Abadie et al. Verwendetes BIP pro Kopf und Branchenzusammensetzung, Handelsanwendungen wollen:

  • Renditemerkmale: mittlere Rendite, Volatilität, Schiefe, Kurtosis im Vorzeitraum
  • Liquiditätsmaße: durchschnittlicher Spread, Tagesvolumen, Amihud-Illiquiditätsverhältnis
  • Mikrostrukturmerkmale: Ungleichgewicht des Auftragsflusses, Handelseingangsrate, Quote-zu-Handel-Verhältnis
  • Faktor-Engagements: Beta-to-Market-, Momentum-, Value- und Volatilitätsfaktoren
  • Verzögerte Ergebnisse: kumulative PnL-Werte zu mehreren Zeitpunkten vor der Intervention

Am wichtigsten sind verzögerte Ergebnisse. Abadie et al. (2010) zeigen, dass, wenn die synthetische Kontrolle mit der behandelten Einheit bei verzögerten Ergebnissen über einen langen Zeitraum vor der Intervention übereinstimmt, sie implizit unbeobachtete Störfaktoren unter einem linearen Faktormodell kontrolliert – was der Grund dafür ist, dass die Methode die Mühe wert ist. Sie sind nicht verpflichtet, den Confounder zu benennen, der zu Ihrer PnL geführt hat. Sie müssen auch Spender finden, die davon betroffen waren.

Wo dies zutrifft

Kausale Brücken zwischen Marktregimen

Szenario 1: Evaluierung eines neuen Ausführungsalgorithmus

Sie implementieren einen neuen TWAP-Zeitplan auf einem Gerät und möchten dessen Auswirkungen auf Implementierungsdefizite ermitteln. Sowohl die Metrik als auch die Algorithmenfamilie werden an anderer Stelle ausführlich behandelt – siehe Implementierungsdefizit und TCA für die Kostenzerlegung und TWAP/VWAP/POV-Algorithmen für die Scheduler selbst. Der SCM-Beitrag ist die darüber liegende Bewertungsebene: Der Spenderpool besteht aus denselben Instrumenten, auf denen immer noch der alte Planer über dasselbe Fenster ausgeführt wird, so dass veranstaltungsweite Änderungen in der Verteilung oder im Volumen gleichermaßen auf Behandelte und Spender wirken.

Vorinterventionszeitraum: 60 Handelstage vor der Umstellung. Zeitraum nach der Intervention: 30 Handelstage danach. Die Effektschätzung ist die Lücke:

τ^1t=Y1tactualY^1tsynthetic,t>T0\hat{\tau}_{1t} = Y_{1t}^{\text{actual}} - \hat{Y}_{1t}^{\text{synthetic}}, \quad t > T_0

Wenn der neue Planer die Kosten tatsächlich senkt, τ^1t<0\hat{\tau}_{1t} < 0 beharrlich danach T0T_0 – und, was noch wichtiger ist, die behandelte Lücke liegt außerhalb der Wolke der Spenderlücken.

Szenario 2: Auswirkungen eines Marktereignisses

Eine Änderung der Gebührenordnung, eines Tick-Size-Pilotprojekts, einer Transaktionssteuer oder einer Änderung der Schutzschalterregel betrifft einen einzigen Veranstaltungsort. Behandelte Einheit: Ihre Strategie für den betroffenen Veranstaltungsort. Spenderpool: das gleiche Paar an Veranstaltungsorten, die von der Änderung nicht berührt wurden. Auswirkungen der Gebührenstruktur auf die Ausführung werden in Maker-Taker-Gebühren und Rabatte gesondert behandelt; SCM ist es, was „unsere Füllungen wurden nach der Änderung schlechter“ in eine Schätzung mit einer angehängten Null umwandelt.

Szenario 3: Regimebedingter Strategiewechsel

Sie wechseln bei einem Vermögenswert von der Mean-Reversion zum Momentum, wenn ein Regimeerkennungssignal ausgelöst wird. War es besser, den Schalter gedrückt zu halten? Spenderpool: ähnliche Vermögenswerte, bei denen das Signal ausgelöst wurde, Sie aber nicht gewechselt haben. Beachten Sie hier die Falle: Wenn das Signal des Regimes auf dem gesamten Markt ausgelöst wird, werden auch Ihre Spender behandelt und das Design bricht zusammen. Siehe die Spillover-Regel unten.

Placebo-Tests und Schlussfolgerungen

Placebo-Trajektorien und getesteter Pfad

Die Schlussfolgerung von SCM basiert auf Permutationen. Der allgemeine Fall für die Bildung einer empirischen Null durch Resampling statt dem Vertrauen in eine geschlossene Verteilung wird in Monte-Carlo- und Bootstrap-Methoden für Backtests dargelegt. Was folgt, ist die SCM-spezifische Konstruktion.

Pünktliches Placebo

Verschieben Sie das Interventionsdatum nach hinten in die Vorperiode – sagen wir zur Hälfte – und wiederholen Sie den Vorgang. Wenn SCM einen „Behandlungseffekt“ zu einem Zeitpunkt feststellt, an dem nichts passiert ist, erkennt es eine bereits bestehende Divergenz und nicht Ihren Eingriff. Eine glaubwürdige synthetische Kontrolle zeigt bei falschen Interventionsterminen keine Wirkung.

In-Space Placebo (Permutationstest)

Wenden Sie das gesamte SCM-Verfahren auf jeden Spender an und tun Sie dabei so, als ob jeder nacheinander die behandelte Einheit wäre:

  1. Für jeden Spender jjKonstruieren Sie eine synthetische Kontrolle aus den verbleibenden Spendern und der ursprünglich behandelten Einheit.
  2. Berechnen Sie die Lücke nach der Intervention gapjt=YjtY^jtsynth\text{gap}_{jt} = Y_{jt} - \hat{Y}_{jt}^{\text{synth}}.
  3. Vergleichen Sie die Lücke der behandelten Einheit mit der Verteilung der Placebo-Lücken.

Der p-Wert ist ein Rang:

p=rank of treated unit’s post/pre MSPE ratioJ+1p = \frac{\text{rank of treated unit's post/pre MSPE ratio}}{J + 1}

Wo

MSPE ratio=MSPEpostMSPEpre=1TT0t>T0(Y1tY^1tN)21T0tT0(Y1tY^1tN)2\text{MSPE ratio} = \frac{\text{MSPE}_{\text{post}}}{\text{MSPE}_{\text{pre}}} = \frac{\frac{1}{T - T_0} \sum_{t > T_0} (Y_{1t} - \hat{Y}_{1t}^N)^2}{\frac{1}{T_0} \sum_{t \leq T_0} (Y_{1t} - \hat{Y}_{1t}^N)^2}

Das Verhältnis und nicht die rohe Lücke nach der Periode ist die richtige Statistik: Ein Spender, der nie gut fit war, wird aus Gründen, die nichts mit einer Intervention zu tun haben, eine große Lücke nach der Periode aufweisen, und die Division durch seinen MSPE vor der Periode bestraft genau das.

Dies ist derselbe schlussfolgernde Schritt, den die Deflated Sharpe Ratio macht – ordnen Sie Ihren Kandidaten innerhalb einer empirisch generierten Referenzverteilung ein, niemals gegen Null. DSR bewertet Ihren Gewinner im Vergleich zu einem Best-of-N-Null-Over-Trials; SCM bewertet Ihre behandelte Einheit mit einem Nullwert über Einheiten. Es gilt ein anderer Schätzer, dieselbe Disziplin und dieselbe Warnung: mit J=15J = 15 Spender ist der kleinste erreichbare p-Wert 1/160.061/16 \approx 0.06. Ein Permutationstest kann nicht über seine eigene Granularität hinaus aufgelöst werden, daher begrenzt ein kleiner Spenderpool die Signifikanz, auf die Sie Anspruch haben, unabhängig davon, wie groß der Effekt aussieht.

Praktische Filterung

Abadie et al. empfehlen den Ausschluss von Placebo-Einheiten mit schlechter Passform vor der Intervention – mehr als vor der MSPE kk mal so hoch wie die der behandelten Einheit, mit kk typischerweise 2 bis 20. Schlechte Placebos haben winzige Nenner und erzeugen enorme MSPE-Verhältnisse, wodurch die Referenzverteilung verunreinigt wird und Ihre behandelte Einheit unauffällig aussieht. Geben Sie das Verhältnis bei mehreren Schwellenwerten an; wenn Ihr p-Wert nur zu einem bestimmten Zeitpunkt signifikant ist kk, Sie haben einen Tuning-Parameter gefunden, keinen Effekt.

Implementierung

Kontrafaktische Analysepipeline

Der folgende Code verwendet nur numpy Und scipy sodass die Mechanik sichtbar ist. Produktionsalternativen — SparseSC (Microsoft Research), pysyncon, SyntheticControlMethods – Randfälle bewältigen und besser skalieren.

Aufbau einer Prädiktormatrix

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 Hier ist eine Übersicht der kumulierten Renditen – behandelte Einheit in Spalte 0, Spender im Rest, eine Zeile pro Balken. Verwenden Sie kumulative Renditen, keine Preisniveaus.

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:]
])

Gewichtsoptimierung

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}")

Die Lückenreihe ist dann df["Treated"].values - df.iloc[:, 1:].values @ weights, aufgetragen gegen das Interventionsdatum zusammen mit den Spenderlücken aus dem Placebo-Durchlauf unten.