Sechs Wochen nachdem wir einen Backtest ausgeführt hatten, ließen wir ihn mit demselben Code, derselben Konfiguration und demselben Zeitraum erneut laufen. Das Endkapital war anders. Nicht dramatisch anders, aber genug, um die Sharpe-Ratio von 1.31 auf 1.08 zu verschieben und zu ändern, welches Parameterset am besten aussah.
Die Strategie hatte sich nicht geändert. Die historischen Daten schon. Ein Anbieter hatte mehrere Tage mit Trades und Bars revidiert, und bei unserem ersten Durchlauf hatten wir den exakten Eingabe-Snapshot nicht aufbewahrt. Die nächsten Tage verbrachten wir damit herauszufinden, ob das neue Ergebnis auf eine Datenkorrektur, einen Fehler in der Pipeline oder einen Forschungsprozess zurückging, den wir nicht reproduzieren konnten.
Montag: Der erneute Lauf wich ab
Der erste Hinweis war eine kleine Lücke bei einem liquiden Spot-Paar. Unser ursprünglicher Bar zeigte ein Hoch von 62,418. Beim erneuten Lauf waren es 62,431. Der Unterschied schien harmlos, bis wir den Einstieg der Strategie zurückverfolgten: Ihr Schwellenwert lag zwischen diesen Preisen. Einige geänderte Bars bedeuteten andere Signale und damit mehrere Tage später andere Positionen.
Wir verglichen die täglichen Trade-Zahlen und stellten fest, dass die Abweichung an einem einzigen Datum begann. Dann verglichen wir die Rohzeilen, die in dieses Datum einflossen. Die aktuelle Antwort des Anbieters enthielt einige korrigierte Trades und einen revidierten aggregierten Bar. An der Antwort, die wir zuvor verwendet hatten, hing kein Änderungsprotokoll.
Das ist normales Datenverhalten. Börsen korrigieren Datensätze; Anbieter füllen Lücken nach, korrigieren fehlerhafte Prints und passen ihre Aggregationslogik an. Eine Abfrage nach „Januardaten“ kann im März eine andere Antwort liefern.
Dienstag: Wir fanden den fehlenden Beleg
Im Laufprotokoll hatten wir den Namen des Anbieters, das Symbol und den Zeitraum gespeichert. Die Antwort selbst oder einen Content-Hash für jede Eingabepartition hatten wir nicht gespeichert. Wir konnten also belegen, was wir angefragt hatten, aber nicht, welche Bytes der Anbieter zurückgegeben hatte.
Wir holten die ältesten Cache-Dateien hervor, die wir finden konnten, und verglichen sie mit der aktuellen Antwort. Der Unterschied beruhte weder auf einer Split-Bereinigung noch auf einer Zeitzonenumrechnung. Es handelte sich um eine kleine Menge korrigierter Trade-Datensätze, die durch unseren Bar-Builder liefen. Damit konnten wir eine Theorie ausschließen, doch der Cache war unvollständig, sodass wir weiterhin nicht jeden betroffenen Bar exakt rekonstruieren konnten.
| Was wir aufgezeichnet hatten | Welche Frage sich damit beantworten ließ | Was fehlte |
|---|---|---|
| Anbieter, Symbol, Zeitraum | Welche Anfrage der Lauf gestellt hatte | Der Inhalt der Antwort |
| Pipeline-Version | Welcher Code die Bars erstellt hatte | Die genauen Eingabezeilen |
| Zeitstempel des Laufs | Wann wir den Job ausgeführt hatten | Welche Anbieterversion damals verfügbar war |
Wir hatten „gleiche Abfrage“ mit „gleiche Daten“ gleichgesetzt. Diese Annahme ließ das Experiment reproduzierbarer erscheinen, als es tatsächlich war.
Mittwoch: Die Korrektur änderte die Aussage
Wir spielten die betroffenen Daten mit beiden verfügbaren Datenversionen erneut ab. Die revidierten Bars entfernten 2 Einstiege und verschoben einen Ausstieg um einen Bar. Diese 3 Trades machten den Großteil der Änderung der Sharpe-Ratio aus. Die Strategie reagierte empfindlich auf einige Beobachtungen nahe ihrem Auslöser, obwohl die gesamte Kursreihe im Diagramm fast identisch aussah.
Das bedeutete weder, dass das ursprüngliche Ergebnis betrügerisch war, noch, dass das revidierte Ergebnis automatisch besser war. Es bedeutete, dass die Aussage eingegrenzt werden musste: Der alte Lauf beschrieb den damaligen Datensnapshot, während der erneute Lauf die aktuelle Historie des Anbieters beschrieb. Wir konnten den einen nicht ehrlich als Reproduktion des anderen bezeichnen.
Donnerstag: Wir änderten die Forschungsdokumentation
Für neue Forschungsdurchläufe fügten wir unveränderliche Eingabe-Snapshots hinzu. Jede Partition erhält einen Content-Hash, und das Laufmanifest hält Quelle, Abrufzeitpunkt, Schema-Version, Bereinigungsrichtlinie und Version des Transformationscodes fest. Bei großen Datensätzen speichern wir die tatsächlichen Dateien in einem Content-Addressed Storage, sodass identische Partitionen gemeinsam genutzt werden können, ohne frühere Versionen zu überschreiben.
Wenn Speicher- oder Lizenzregeln verhindern, dass wir Rohdaten aufbewahren, sichern wir den bestmöglichen zulässigen Beleg: Hashes, Anfrageparameter, Kennungen der Quellversion und eine kleine Stichprobe geparster Zeilen zur Diagnose. Ein Hash kann die Daten nicht wiederherstellen, aber er zeigt uns, wenn zwei Läufe nicht dieselben Bytes verarbeitet haben.
Ein reproduzierbarer Backtest braucht eine eindeutige Kennung der Eingabedaten, nicht nur eine Daten-URL. Haltet fest, was eingetroffen ist, wann es eingetroffen ist und wie daraus die Zeilen wurden, die eure Strategie verarbeitet hat.
Freitag: Was wir beim nächsten Mal überspringen würden
Wir würden darauf verzichten, nur die Kennzahlen auf einen Blick zu vergleichen. Eine veränderte Sharpe-Ratio zeigt, dass sich etwas verschoben hat; sie verrät nicht die Ursache. Beginnt mit Zeilenzahlen und Partitions-Hashes und sucht dann das erste abweichende Eingabedatum. Vergleicht anschließend in dieser Reihenfolge transformierte Zeilen, Signale, Orders und Fills.
Wir würden auch darauf verzichten, alte Daten stillschweigend durch korrigierte Historie zu ersetzen. Korrekturen sind nützlich, aber alte Läufe sollten an ihre ursprünglichen Eingaben gebunden bleiben. Ein neuer Datensatz sollte einen neuen Lauf erzeugen, der sichtbar mit dem älteren verknüpft ist.
Unsere praktische Regel ist jetzt einfach: Soll ein erneuter Lauf ein Experiment reproduzieren, fixieren wir den Datensnapshot. Soll er von einer korrigierten Historie profitieren, kennzeichnen wir ihn als neues Experiment. Wir brauchten einige Tage, um diesen Unterschied zu verstehen; im Laufmanifest steht er in einer Zeile.
← Alle Beiträge


