26. September 2026 · Forschung

Wir haben versucht, den Backtest einer Strategie zu reproduzieren. Dabei sind die Zahlen abgewichen.

Wir haben versucht, den Backtest einer Strategie zu reproduzieren. Dabei sind die Zahlen abgewichen.

Wir haben einen gespeicherten Backtest erneut ausgeführt und eine andere Equity-Kurve erhalten. Derselbe Strategiecode, derselbe Zeitraum, dasselbe Symbol. Der Endstand wich um 1.8% ab, und drei Trades hatten sich um einen Balken verschoben.

Das reicht, um einem Forschungsergebnis schwer vertrauen zu können. Wenn ein Teammitglied, dein zukünftiges Ich oder ein Paper-Trading-Dienst den Lauf nicht reproduzieren kann, lässt sich nicht sagen, ob eine Änderung die Strategie verbessert oder nur das Experiment verändert hat. So sind wir bei der Suche nach der Abweichung vorgegangen.

Tag 1: Wir haben festgehalten, was „derselbe Lauf“ bedeutet

Unser erster Fehler war, eine Strategiedatei mit dem Experiment gleichzusetzen. Das war sie nicht. Der Lauf hing auch von den Eingabedaten, der Engine-Version, dem Kalender, den Instrumentenmetadaten und den Ausführungseinstellungen ab. Der Code beschrieb nur einen Teil der Berechnung.

Bevor wir etwas änderten, erstellten wir ein Laufmanifest. Darin hielten wir den Strategie-Commit, die Kennungen der Datensnapshots, den Zeitraum, den Handelsplatz, den Gebührenplan, die Funding-Quelle, das Fill-Modell und die Softwareversionen fest. Außerdem speicherten wir die resultierenden Orders und Fills, denn eine Equity-Kurve allein zeigt nicht, wo zwei Läufe erstmals voneinander abwichen.

ArtefaktWas zu erfassen istWarum es wichtig ist
MarktdatenSnapshot-ID, Schema-Version, AnpassungenAnbieter korrigieren historische Daten und überarbeiten Kapitalmaßnahmen
AusführungGebührenstufe, Funding-Zeitreihe, Fill- und Impact-EinstellungenStandardeinstellungen und Kontoannahmen verändern die Ergebnisse
LaufzeitumgebungCode-Commit, Engine- und AbhängigkeitsversionenBibliotheken können Reihenfolge, Rundung oder Indikatoren verändern
ErgebnisOrders, Fills, Positionen und KennzahlenZeigt, wo die Läufe auseinanderlaufen

Tag 2: Wir haben die Trades verglichen, nicht den Sharpe

Die zusammenfassenden Kennzahlen lenkten uns ab. Beide Läufe hatten nahezu denselben Sharpe, doch ihre Fill-Protokolle zeigten die erste Abweichung bei einer Funding-Abrechnung. Ein Lauf belastete die zum Abrechnungszeitpunkt offene Position mit dem Satz; der andere verwendete die Position nach dem Rebalancing zu diesem Zeitpunkt.

Der Strategiecode hatte sich nicht geändert. Die Ereignisreihenfolge der Engine schon. Durch ein kleines Versionsupdate wurde die Reihenfolge explizit festgelegt, während sie zuvor davon abhing, wie zwei Ereignisse zufällig sortiert wurden.

Wir haben den Laufvertrag angepasst und die Reihenfolge festgelegt: Funding auf die in die Abrechnung eingebrachte Position anwenden, dann die Strategieentscheidungen für diesen Zeitpunkt verarbeiten. Die genaue Konvention kann je nach Handelsplatz und Engine variieren. Sie implizit zu lassen, ist der Fehler.

Tag 3: Eine „gleiche“ Datendatei stellte sich als anders heraus

Nachdem wir die Ereignisreihenfolge festgelegt hatten, konzentrierten sich die verbleibenden Abweichungen auf einige Aktien-Trades. Der Anbieter hatte eine historische Split-Anpassung korrigiert. Unsere Datei hatte denselben Namen und dieselbe Zeilenanzahl wie zuvor, wodurch sie unverändert wirkte.

Jetzt erstellen wir für jeden unveränderlichen Datensnapshot einen Fingerabdruck und speichern die Anpassungsrichtlinie dazu. Ein Hash sagt uns, ob sich Bytes geändert haben; er erklärt aber nicht warum. Deshalb enthält das Manifest auch Quelle, Abrufzeitpunkt und Transformationsversion. Bei Daten, die überarbeitet werden, gehören diese Angaben zum Ergebnis.

Ein reproduzierbarer Backtest braucht eine Antwort auf die Frage: „Welche Version der Vergangenheit hat er gesehen?“

Tag 4: Wir fanden eine unauffällige Standardeinstellung

Die letzte Abweichung ging auf eine Maker-Gebühr zurück, die auf null gesetzt war, weil das Feld in der Strategiekonfiguration fehlte. Eine neuere Engine verwendete die Standardgebühr des Kontos. Diese eine Einstellung veränderte die Trades an der Marge so stark, dass sie den größten Teil der Abweichung beim Endstand erklärte.

Wir haben wirtschaftlich relevante Einstellungen explizit festgelegt und die Engine die aufgelöste Konfiguration in den Laufdatensatz schreiben lassen. Standardeinstellungen sind beim Erkunden praktisch. Beim Vergleich von Ergebnissen über die Zeit sind sie ein schlechter Beleg.

3gefundene Ursachen für Abweichungen
1.8%anfängliche Abweichung beim Endstand
0Aussagekraft eines übereinstimmenden Sharpe allein

Was wir beim nächsten Mal überspringen würden

Wir haben einen halben Tag lang aggregierte Kennzahlen verglichen, bevor wir uns den ersten abweichenden Fill angesehen haben. Fangt nicht damit an. Sortiert beide Ereignisprotokolle nach Zeitstempel und vergleicht die erste Abweichung; spätere Unterschiede gehen oft auf dieselbe Ursache zurück.

Wir würden auch die Annahme weglassen, ein Container-Image allein mache einen Lauf reproduzierbar. Es fixiert einen großen Teil der Softwareumgebung, aber keine externe Datendatei, keinen zur Laufzeit abgerufenen Gebührenplan und keine überarbeitete Historie eines Anbieters.

Wenn sich ein Backtest ändert, bewahrt beide Laufmanifeste und Protokolle auf und behebt dann jeweils eine Abweichungsursache. Das nützliche Ergebnis ist nicht nur eine erneut ausführbare Kurve. Es ist ein Datensatz, der erklärt, welche Daten und Annahmen sie hervorgebracht haben und warum der nächste Lauf abweichen könnte.

ReproduzierbarkeitBacktestingDatenengineeringPapertrading
← Alle Beiträge