27. August 2026 · Datenengineering

Dein Symboluniversum ist eine Zeitmaschine: Survivorship Bias in Krypto-Perp-Backtests

Dein Symboluniversum ist eine Zeitmaschine: Survivorship Bias in Krypto-Perp-Backtests

Du hast mir das Notebook am Sonntagabend geschickt, und seitdem ist es auf meinem zweiten Monitor geöffnet. Cross-Sectional Momentum, die 150 Binance-USDⓈ-M-Perps mit dem höchsten 30-Tage-Dollarvolumen, wöchentlicher Rebalance, long im obersten Dezil, short im untersten, von 2021-01 bis 2026-06. Sharpe 2.31, maximaler Drawdown 14.2 %, und ein Kostenmodell, das auf mich ehrlich wirkte: taker beim Einstieg, taker beim Ausstieg, Funding pro Intervall aufgelaufen, ein Slippage-Term, der mit deiner Größe im Verhältnis zum Orderbuch skaliert. Die schwierigen Teile hast du richtig gemacht. Dann hast du gefragt, warum sechs Wochen Paper-Trading unterm Strich nichts ergeben haben und ob der Edge nachgelassen hat.

Er hat nicht nachgelassen. Im Backtest war er nie enthalten. Sieh dir Zelle 4 an:

info = requests.get(BASE + "/fapi/v1/exchangeInfo").json()
symbols = [s["symbol"] for s in info["symbols"]
           if s["status"] == "TRADING" and s["quoteAsset"] == "USDT"]

Du hast diesen Endpunkt im Juni 2026 aufgerufen und die Antwort verwendet, um festzulegen, was im März 2021 handelbar war. Jedes Symbol auf dieser Liste hat per Definition bis Juni 2026 überlebt. Das ist der ganze Fehler und er wiegt schwerer als der Rest deines Kostenmodells zusammengenommen.

2.31 → 0.74Sharpe, Überlebendenliste gegenüber Point-in-Time
~1 von 5deines Universums von 2021 existiert nicht mehr
380 KBtäglicher exchangeInfo-Snapshot, gzip-komprimiert

Was der Endpunkt dir nicht verrät

In exchangeInfo gibt es keine Historie. Keinen Parameter asOf, kein Archiv, kein Änderungsprotokoll. Es ist eine Momentaufnahme von jetzt, und Binance hat dir nie etwas anderes versprochen. Wird ein Kontrakt delistet, wird sein Eintrag aus der Antwort gelöscht und der Ticker existiert aus Sicht der API nicht mehr. Seit 2019 hat Binance mehr als 600 USDⓈ-M-Perpetuals gelistet und weit über hundert davon wieder eingestellt. BTS, COCOS, TOMO, RAY, FTT, SC – eine lange Liste von Kontrakten aus der Altcoin-Saison 2021, die ein glanzvolles Quartal hatten und dann ausdünnten, bis die Börse sie entfernte.

Frag dich, welche Namen ein 30-Tage-Momentum-Screen besonders mag. Nicht BTC. Er mag genau das, was nach einem Listing-Pump und einem Twitter-Zyklus gerade eine Verdreifachung hingelegt hat. Diese Gruppe überschneidet sich stark mit den späteren Delistings, und dein Universumsfilter hat genau diese Überschneidung entfernt.

Ich habe deinen Lauf mit unserem Snapshot-Archiv neu gerechnet: Point-in-Time-Universum, dasselbe Signal, dieselben Kosten. Die Sharpe Ratio lag bei 0.74, bei einem Drawdown von 31 %. Etwa zwei Fünftel der Differenz entfallen auf delistete Namen, die du nie hättest halten dürfen. Ein weiteres Viertel stammt vom spiegelbildlichen Problem – es ist subtiler und ich vermute, es wird dir noch weniger gefallen.

Das andere Ende der Zeitmaschine: Symbole, die es noch nicht gab

Dein Merkmal ist eine Rendite über 90 Tage. Dein rollierendes Fenster hat min_periods=20, weil du es einmal so festgelegt hast, damit die Aufwärmphase nicht das erste Quartal der Stichprobe auslöscht, und es danach nie wieder überprüft hast. Ein Kontrakt, der vor 21 Tagen gelistet wurde, erhält also einen Momentum-Score auf Basis von drei Wochen Kursbewegung nach dem Listing. Wenn das Listing gut lief, landet er ungefähr jedes Mal im obersten Dezil und wird in dein Portfolio aufgenommen.

Dieser Teil ist womöglich legitim. Das hier ist es nicht: Dein Datenanbieter hat einige dieser Symbole mit Spot- oder Indexdaten aus der Zeit vor dem Perp-Listing ergänzt. Dadurch haben einige Kontrakte Kline-Historien, die ihrem eigenen onboardDate vorausgehen. Das kannst du in etwa einer Minute prüfen. Verknüpfe deine Preistabelle mit den Onboard-Daten und zähle die Zeilen vor dem Listing. In deinen Daten haben 41 Symbole Bars aus der Zeit vor dem Listing, und eines davon trägt im Sommer 2023 mit einem Gewinn von 6 % in einer einzigen Woche zur Equity-Kurve bei – aus einer Position in einem Kontrakt, der erst neun Tage später existieren würde.

Ein Ticker-String ist keine Kennung. Er ist ein Label, das die Börse vermietet – manchmal gleich zweimal.

Damit kommen wir zu Umbenennungen. MATICUSDT wurde zu POLUSDT. FTMUSDT wurde durch eine 1:1-Konvertierung zu SUSDT. Die LUNA-Geschichte im Mai 2022 hinterließ ein LUNCUSDT und später ein völlig neues LUNAUSDT, dessen Ticker denselben Stamm hat wie ein Asset, das so ziemlich alles verloren hat. Wenn dein Loader den Symbol-String als Schlüssel verwendet und beliebige gefundene Dateien zusammenfügt, hast du mindestens eine Zeitreihe mit einem Bruch, der keine Kursbewegung ist. Dein Momentum-Merkmal wird diesen Bruch als stärkstes Signal im Querschnitt lesen.

Alles andere, das sich unter dir verschiebt

Sobald du akzeptierst, dass sich die Symbolliste mit der Zeit ändert, gilt dasselbe Argument für jedes andere Feld in dieser Antwort. Du verwendest für alles die heutigen Werte.

FeldWie es sich verändertWas dadurch schiefläuft
statusTRADING → SETTLING → verschwundenSurvivorship Bias; scheinbare Ausstiege zu einem Schlusskurs, zu dem nie gehandelt wurde
onboardDateJede Woche neue Listings; bei toten Symbolen nicht mehr vorhandenHandel mit Kontrakten, bevor es sie gab
tickSize / stepSizeAn neue Kursniveaus angepasstRundung von Orders und Limitpreise, die abgelehnt worden wären
minNotionalIm Lauf der Zeit für illiquide Orderbücher angehobenKleine Positionen, die dein Live-Router abgelehnt hätte
fundingIntervalHoursJahrelang 8h, dann bei vielen Symbolen 4h oder 1hFunding um den Faktor 2–3× falsch berechnet – ausgerechnet bei den Altcoins, die dein Screen hält
leverage bracketsStufen und Maintenance Margin überarbeitetLiquidationsmodellierung und Margin-Kapazität

Das Funding-Problem schmerzt in deinem Fall am meisten. Deine Auflaufschleife geht über die gesamte Historie von drei Zahlungen pro Tag aus. Ein beträchtlicher Teil des Altcoin-Portfolios wurde auf Funding alle vier Stunden umgestellt, und Short-Positionen in Assets mit hohem Funding sind eine wichtige Quelle deines simulierten PnL. Da liegst du nicht wegen eines Rundungsfehlers daneben. Du liegst um einen Faktor daneben.

Das Delisting selbst ist ein Ereignis, das du nicht modellierst

Bei deinem Point-in-Time-Neulauf habe ich der Strategie einen großzügigen Ausstieg eingeräumt. Reale Delistings laufen nach einem festen Ablauf: eine Ankündigung, meist sieben bis vierzehn Tage vorher, dann ein Reduce-Only-Zeitfenster und anschließend eine erzwungene Abrechnung zum Mark-Preis. Die Ankündigung ist öffentlich, und du kannst darauf reagieren. Eine faire Simulation setzt den Ausstieg daher zum Schlusskurs des Ankündigungstags an. Doch dieser Schlusskurs liegt bei einem typischen Altcoin-Delisting bereits 10-20 % unter dem der Vorwoche, das Orderbuch ist dünn, und dein Slippage-Term muss wissen, dass er sich in einem anderen Marktregime befindet. Liefert dir deine Fill-Engine ohne Impact den Abrechnungspreis, hast du sterbende Assets stillschweigend zum fairen Wert handelbar gemacht.

Wenn du exchangeInfo nie archiviert hast, bist du noch nicht aufgeschmissen. Der öffentliche Dump unter data.binance.vision/data/futures/um/monthly/klines/ enthält noch lange Verzeichnisse für delistete Symbole, nachdem die API sie vergessen hat. Liste die Verzeichnisse auf: Anhand der ersten und letzten Monatsdatei pro Symbol lässt sich ein brauchbares Listing- und Delisting-Zeitfenster ermitteln, ganz ohne Datenanbieter. Das ist eine Rekonstruktion, kein Protokoll, und Tick-Größen oder Funding-Intervalle bekommst du damit nicht zurück. Aber du erfährst, welche Symbole wann existierten – das sind 80 % dessen, was du am Montag brauchst.

Was du bauen solltest, bevor du das Signal wieder anfasst

  1. Einen Cron-Job, der täglich exchangeInfo von jeder Börse abruft, die du untersuchst, und die Daten nach Datum in einem Objektspeicher ablegt. Gzip-komprimiert ist das weniger als ein halbes Megabyte. Zehn Jahre kosten dich in S3 kaum etwas und verschaffen dir eine Research-Möglichkeit, die du später nicht nachkaufen kannst.
  2. Einen Asset-Master, der aus diesen Snapshots abgeleitet wird: eine Zeile pro (Börse, Symbol, valid_from, valid_to) mit dem vollständigen Feldsatz. Vergleiche aufeinanderfolgende Snapshots, um ihn zu erzeugen, und behandle jede Feldänderung als neue Zeile.
  3. Eine Universumsfunktion mit einem obligatorischen Zeitstempel-Argument. universe(ts), niemals universe(). Mach es unmöglich, dass der Standardwert fehlt, damit niemand – auch nicht dein zukünftiges Ich um 1am – versehentlich auf die Überlebendenliste zurückgreifen kann.
  4. Eine Prüfung auf Bars vor dem Listing im Daten-Loader: Kein Bar darf vor onboard_ts minus einem Tag liegen. Lauf abbrechen, nicht nur warnen.
  5. Eine stabile interne Instrumenten-ID, die Umbenennungen übersteht, während der Ticker nur noch ein Attribut ist. Ordne POL und MATIC derselben ID zu und kennzeichne Redenominierungen, damit die Kontinuitätslogik sie nicht zusammenführen kann.

Setz das um und starte den Lauf erneut. Ich schätze, du landest in der Nähe meiner 0.74. Dann stellt sich die interessante Frage, ob in einer 0.74, die die toten Namen einbezieht, genug steckt, um sie im Paper-Trading zu testen. Vielleicht. Cross-Sectional Momentum bei Perps ist nicht nichts, und ein Teil dessen, was nach der Korrektur des Universums übrig bleibt, ist echtes Carry auf der Short-Seite. Außerdem werden deine Paper-Ergebnisse und dein Backtest allmählich übereinstimmen, weil dein Paper-Trading schon immer mit einem Point-in-Time-Universum lief. Es hatte keine Wahl.

P.S. Das ist keine Eigenheit von Krypto, hier fällt es nur stärker auf. Aktien-Researcher kämpfen schon seit CRSP mit Delisting-Renditen und wiederverwendeten Tickern. Prediction Markets treiben das Prinzip auf die Spitze: Jeder Kontrakt läuft absichtlich aus, das Universum besteht also ausschließlich aus Listings und Todesfällen. Wenn du diesen Screen jemals auf Kalshi überträgst, erstelle zuerst den Asset-Master. Eine andere Art von Historie gibt es dort nicht.

Survivorship BiasPoint-in-Time-DatenKrypto-FuturesBacktestingDatenengineering
← Alle Beiträge