Dokumentation

Backtest & Optimierung

Wie partiqon Strategien auf Historien testet, Parameterwerte sucht und sie auf Daten misst, die die Suche nicht verwendet hat: Backtesting, PSO-Optimierung, Walk-Forward-Validierung und WFO.

Backtesting

Ein Backtest simuliert eine Strategie auf historischen Daten. Für jeden Bar wird geprüft, ob Ein- oder Ausstiegssignale ausgelöst werden, und alle Trades mit P&L werden aufgezeichnet. Es wird kein echtes Geld verwendet. Es ist reine Simulation zur Messung vergangener Performance.

So funktioniert es

  1. Daten laden: Historische Bars (OHLCV) aus BAR6-Dateien
  2. Zustand zurücksetzen: Strategie-Parameter, Indikatoren und Positionen auf Start zurücksetzen
  3. Bars durchlaufen: Jeden Bar im Zeitraum an die Strategie übergeben
  4. Signale prüfen: Erzeugt die Strategie Ein- oder Ausstiegssignale?
  5. Trades ausführen: Einstieg öffnet eine Position; Ausstieg schließt sie. Einstiegs-/Ausstiegspreis und P&L aufzeichnen
  6. Kennzahlen berechnen: Win-Rate, Drawdown, Profit-Factor usw.
  7. Ergebnisse ausgeben: Trade-Liste, Equity-Kurve, Performance-Statistiken

Zeitstempel der Trades

Bar-Daten gehen als UTC in die Engine. Trade-Zeitstempel kommen in Europe/Berlin-Ortszeit heraus (CET im Winter, CEST im Sommer). Das betrifft die Spalten EntryTime und ExitTime in detailed_trades.csv, die Trade-Liste sowie die Auswertungen nach Tagesstunde und Wochentag.

Gate.Session-Fenster verwenden dieselbe Uhr. Ein Trade steht damit in derselben Uhr wie die Session-Regel, die ihn zugelassen hat.

⚠ Die Tagesblöcke verwenden diese Uhr NICHT. Aggregator.D1, Aggregator.TickToBar.D1, der tägliche Reset von Indicator.VWAP und Indicator.PivotPoints legen ihren Tag ganzjährig auf ein festes UTC+1, 23:00→23:00 UTC. Das ist im Winter Mitternacht Berliner Zeit und im Sommer 01:00. Ein halbes Jahr lang sind sich ein Gate.Session-Fenster und ein Aggregator.D1-Bar also um eine Stunde uneinig, wann ein Tag beginnt. Ein selbst konvertierter Datensatz und die Bars, die der Chart zeichnet, verwenden noch eine dritte Grenze: das schlichte UTC-Raster, 00:00 UTC. Alle drei sind Absicht und keine davon wird geändert, denn eine verschobene Tagesgrenze verschiebt still die Ergebnisse jeder gespeicherten D1-Strategie. Die Block-Referenz hält fest, welche Oberfläche welche verwendet.
⚠ Der Versatz ist nicht konstant. Berlin ist im Winter UTC+1 und im Sommer UTC+2. Derselbe UTC-Bar liest sich am 15. Januar als 10:00 und am 15. Juli als 11:00. Wer diese Zeitstempel wieder in Zeitpunkte zurückrechnet (in einer Tabelle, einem Notebook oder eigenen Werkzeugen), muss sie als Europe/Berlin mit Sommerzeit interpretieren. Als UTC oder als festes UTC+1 gelesen, liegt jeder Sommer-Trade eine Stunde daneben.

Wichtige Kennzahlen

Am Datenende offene Positionen

Eine Position, die beim Ende der Daten noch offen ist, schließt die Engine zum Preis des letzten Balkens, mit dem Ausstiegsgrund END_OF_DATA. Dieser Ausstieg ist keine Entscheidung der Strategie, und sein Ergebnis hängt davon ab, wo die Daten zufällig enden. Die Kennzahlen sind deshalb zweigeteilt:

Die Ergebnisse zeigen, wie viele Positionen am Ende offen waren und ihr unrealisiertes Ergebnis; Trade-Liste und Trade-Export kennzeichnen sie in der Spalte Open at data end. Der Nettogewinn ist Bruttogewinn minus Bruttoverlust plus dieses unrealisierte Ergebnis. Besteht ein Ergebnis nur aus Trades, die am Ende noch offen waren, zeigen die aus Trades berechneten Kennzahlen einen Strich. Ergebnisse, die vor dieser Regel berechnet wurden, zählten solche Positionen in jeder Kennzahl als gewöhnliche Trades und behalten ihre Zahlen.

MFE und MAE

Die Trade-Liste zeigt, wie weit sich der Preis bewegt hat, während ein Trade offen war, in Preispunkten pro Einheit der Positionsgröße:

Beide werden ab dem Preis gemessen, zu dem der Trade ausgeführt wurde (Spread und Slippage des Einstiegs sind in diesem Preis enthalten), über jeden Bar vom Bar der Ausführung bis zum Bar, in dem der Trade geschlossen wurde, einschließlich dieses Ausstiegsbars, jeweils mit Hoch und Tief des Bars. Für einen Long-Trade ist MFE = höchstes Hoch − Ausführungspreis und MAE = tiefstes Tief − Ausführungspreis; für einen Short-Trade MFE = Ausführungspreis − tiefstes Tief und MAE = Ausführungspreis − höchstes Hoch.

Weil der Ausstiegsbar zählt, liegt der Preis, zu dem ein Stop oder Ziel ausgeführt wurde, oder die Eröffnung eines Bars, der darüber hinweg gegappt ist, im gemessenen Bereich: Die Preisbewegung von der Ausführung bis zum Ausstieg ist höchstens MFE und mindestens MAE, ein Take-Profit hat einen MFE von mindestens seinem Zielabstand und ein Stop-Loss einen MAE, der mindestens so groß ist wie sein Stop-Abstand. Der ganze Ausstiegsbar zählt, auch sein Teil nach dem Ausstieg, weil ein Bar ein Hoch und ein Tief liefert und nicht die Reihenfolge seiner Preise; bei einem Bar, der Stop und Ziel erreicht hat, geht deshalb einer der beiden Werte über sein Niveau hinaus.

Spread und Slippage des Ausstiegs, Kommission und Finanzierung sind nicht Teil von MFE und MAE. Das P&L eines Trades enthält sie und steht in Kontowährung für die ganze Position; direkt mit MFE und MAE vergleichbar ist es deshalb nur bei einem Wert pro Punkt von 1 und einer Größe von 1. Ein Ergebnis, das vor dieser Definition gespeichert wurde, zeigt MFE und MAE so, wie sie gespeichert sind, mit einem Hinweis: ohne den Ausstiegsbar und in Kontowährung pro Einheit.

Trade-Kontext

Der Tab Context gruppiert dieselben Trades nach der Lage, in der jeder eingegangen wurde, in Tabellen mit Trades, Anteil, Win-Rate, Profit-Factor, Erwartungswert und Netto-P&L je Gruppe. Jeder Wert wird auf dem letzten Bar gelesen, der vor dem Einstieg abgeschlossen war, nie auf dem Bar, in dem der Trade eingegangen wurde, denn dessen Hoch, Tief und Schluss liegen nach dem Einstieg.

Volatilität, Trendstärke, Abstand und Lage werden in Drittel geteilt. Die beiden Grenzen werden über jeden Bar des Datensatzes bestimmt, bei Abstand und Lage mit jedem Bar einmal als Long und einmal als Short gezählt, und jede Tabelle nennt sie. Weil die Grenzen auch die Bars nach jedem Trade verwenden, beschreiben die Bänder die Vergangenheit und lassen sich nicht als Filter im Live-Trading verwenden. Eine Gruppe mit weniger als 30 Trades ist als Low Sample markiert; bei mehreren Tabellen nebeneinander sind kleine Unterschiede zwischen Bändern meist Rauschen. Der Trade-Export enthält die vier Werte jedes Trades in den Spalten entry_adx, entry_mean_distance, entry_range_position und streak_before (+n nach n Gewinnen, −n nach n Verlusten, 0 nach einem Trade bei 0, leer ohne vorherigen Trade).

⚠ Wichtig: Backtest-Ergebnisse sind historisch. Sie zeigen, was die Regeln auf vergangenen Daten getan haben, nicht was sie tun werden. Eine Kennzahl aus dem Zeitraum, auf dem die Regeln oder ihre Parameter gewählt wurden, enthält alles, was diese Wahl an den Zeitraum angepasst hat. Die Out-of-Sample-Messungen weiter unten verwenden Daten, die die Wahl nicht gesehen hat, und bleiben trotzdem Messungen der Vergangenheit, keine Prognose.

PSO-Optimierung

PSO (Particle Swarm Optimization, Partikelschwarm-Optimierung) ist ein Suchalgorithmus, der Parameterwerte automatisch sucht. Jeder Partikel ist ein Satz von Parameterwerten. Nach jeder Generation bewegt sich jeder Partikel in Richtung des besten Satzes, den er bisher gefunden hat, und des besten Satzes des ganzen Schwarms, gemessen an der gewählten Metrik.

Wie PSO funktioniert

  1. Suchbare Parameter definieren: Welche Block-Parameter können angepasst werden? (z.B. EMA-Periode 10–100, RSI-Level 20–50)
  2. Schwarm initialisieren: N Partikel mit zufälligen Parameter-Werten erstellen (z.B. 30 Partikel)
  3. Jeden Partikel bewerten: Backtest mit diesen Parametern ausführen. Profit-Factor (oder gewählte Metrik) aufzeichnen
  4. Bestes verfolgen: Jeder Partikel merkt sich sein bestes Ergebnis. Der Schwarm merkt sich das globale Beste.
  5. Geschwindigkeiten aktualisieren: Jeder Partikel passt seine Parameter in Richtung seines persönlichen Besten und des globalen Besten an (mit Zufälligkeit)
  6. Wiederholen: Mehrere Generationen durchlaufen (z.B. 60 Iterationen). Der Schwarm sammelt sich um die Sätze, die bei der gewählten Metrik am höchsten gemessen wurden.
  7. Champion ausgeben: Der Parametersatz, der über alle Generationen am höchsten gemessen wurde

Was PSO tut und was nicht

Iteration 1: Partikel → Backtest → Bewertung Iteration 2: Partikel bewegen sich zum Besten → Backtest → Bewertung Iteration 3: Partikel bewegen sich erneut → Backtest → Bewertung ... Iteration 60: Endpositionen → Bestes zurückgeben

Walk-Forward-Validierung

Eine einzelne Aufteilung in In-Sample und Out-of-Sample misst die Strategie auf einem späteren Zeitraum. Walk-Forward wiederholt diese Messung auf mehreren aufeinanderfolgenden Zeiträumen. So zeigen die Kennzahlen, wie sich das Ergebnis von einem Zeitraum zum nächsten unterscheidet.

Warum ein eigener Zeitraum

Parameter, die auf einem Zeitraum gewählt werden, können neben einem Muster auch das Rauschen dieser einen Historie abbilden. Auf demselben Zeitraum gemessen, enthält das Ergebnis diese Anpassung. Ein späterer Zeitraum, den die Wahl nicht gesehen hat, misst dieselben Regeln ohne sie.

Walk-Forward-Prozess

  1. In-Sample-Fenster: Der erste Out-of-Sample-Block beginnt IS Window (months) Monate nach Full Range Start.
  2. Out-of-Sample-Blöcke: Der Zeitraum danach wird in aufeinanderfolgende Blöcke von je OOS Block Size (months) Monaten geteilt.
  3. Blockgrenzen: Jeder Out-of-Sample-Block endet am Tag, bevor der nächste beginnt, kein Tag gehört also zu zwei Blöcken. Der letzte Block endet bei Full Range End und kann kürzer sein als die Blockgröße. Die Daten sind ganze Tage in UTC, beide Enden eingeschlossen.
  4. Welche Trades ein Block zählt: Ein Trade gehört zu dem Block, in dem er eröffnet wurde. Die Trade-Liste zeigt die Zeiten in mitteleuropäischer Zeit; im Winter gehört ein Trade, der am ersten Tag eines Blocks um 00:30 eröffnet wurde (23:30 UTC am Vortag), deshalb zum vorherigen Block.
  5. Walk-Forward-Tab: Das In-Sample-Fenster jedes Blocks reicht vom Startdatum bis zu diesem Block (verankert), und der Graph wird auf jedem Block so getestet, wie er ist, ohne Re-Tuning.
  6. WFO-Tab: Die Parameter werden auf dem In-Sample-Fenster jedes Blocks neu optimiert, bevor dieser Block gemessen wird (siehe unten).
Verankert Block 1: IS [2020─────2021] OOS [2021─2022] Verankert Block 2: IS [2020──────────2022] OOS [2022─2023] Verankert Block 3: IS [2020─────────────────2023] OOS [2023─2024] ...

Ergebnisse lesen

Walk-Forward-Optimierung (WFO)

WFO optimiert die tunable Parameter mit PSO auf dem In-Sample-Fenster jedes Blocks neu und testet die neu gewählten Parameter dann auf dem folgenden Out-of-Sample-Block. Das In-Sample-Fenster ist standardmäßig am Startdatum verankert oder rollierend: ein Fenster von IS Window (months) Monaten, das mit den Blöcken weiterwandert.

WFO-Prozess

  1. Daten aufteilen: In-Sample-Fenster und Out-of-Sample-Blöcke wie bei Walk-Forward oben.
  2. Pro Block: PSO auf dem In-Sample-Fenster des Blocks → Backtest der neu gewählten Parameter auf dem Block
  3. Zusammenfassung: Profitable Blöcke, durchschnittlicher und niedrigster Out-of-Sample-Profit-Factor, durchschnittliche Sharpe-Ratio und die Anzahl der Out-of-Sample-Trades, dazu die Werte jedes Blocks in der Blocktabelle
💡 Was WFO misst: das Vorgehen, auf einem In-Sample-Fenster neu zu optimieren und das Ergebnis dann auf dem Zeitraum danach zu messen, Block für Block wiederholt. Jede Out-of-Sample-Kennzahl stammt aus Daten, die die Optimierung dieses Blocks nicht gelesen hat. Die In-Sample-Kennzahl eines Blocks enthält auch, was die Optimierung an dieses Fenster angepasst hat; der Abstand zwischen In-Sample- und Out-of-Sample-Kennzahlen enthält deshalb diese Anpassung. Alle bleiben Messungen vergangener Zeiträume, keine Prognose.

Auf voller Historie anpassen

Ein WFO hinterlässt einen Parametersatz pro Block, keinen für die spätere Verwendung. Nach einem abgeschlossenen WFO führt Fit on full history (Auf voller Historie anpassen) in seinen Ergebnissen dasselbe Vorgehen noch einmal aus, auf dem Fenster, auf dem ein nächster Block optimiert würde: vom Startdatum bis zum letzten Bar des Datensatzes bei verankertem In-Sample-Fenster, bei rollierendem die letzten IS Window (months) Monate vor diesem Bar (Fit on the last N months). Die Anpassung verwendet die PSO-Einstellungen, die Fitness-Metrik und die Mindestzahl an Trades des WFO und wird als neue Version des Graphen gespeichert; die Version davor bleibt im Versionsverlauf erhalten.

Für diese Parameter gibt es keinen Out-of-Sample-Zeitraum: Die Out-of-Sample-Kennzahlen des WFO beschreiben das Vorgehen, nicht diesen Parametersatz. Das Vorgehen optimiert alle OOS Block Size (months) Monate neu, deshalb zeigt der Graph, wann die nächste Anpassung fällig ist, und Fit again wiederholt die Anpassung auf neueren Daten. Die erste Anpassung nach einem WFO ist im WFO-Lauf enthalten; jede spätere zählt als ein Optimierungslauf.

Wie die Werkzeuge zusammenhängen

  1. Bauen: Eine Strategie ist ein Graph aus Blöcken im Graph-Editor.
  2. Backtest: Lässt den Graphen auf einem Zeitraum mit seinen aktuellen Parameterwerten laufen.
  3. Optimieren: PSO durchsucht die tunable Parameter auf einem In-Sample-Zeitraum.
  4. Out-of-Sample-Backtest: Misst die gewählten Parameter auf einem späteren Zeitraum, den die Suche nicht gelesen hat.
  5. Walk-Forward: Misst den unveränderten Graphen auf mehreren aufeinanderfolgenden Out-of-Sample-Blöcken.
  6. WFO: Optimiert auf dem In-Sample-Fenster jedes Blocks neu und misst dann den Block danach.
  7. Auf voller Historie anpassen: Führt das Vorgehen eines abgeschlossenen WFO noch einmal aus, auf dem Fenster nach seinem letzten Block, und speichert die Parameter als neue Version des Graphen.

Jeder Schritt liefert Messungen auf vergangenen Daten. Keiner davon sagt, ob eine Strategie zum Handeln taugt.

Structure Finder: Pattern-Mining

Ein Structure-Finder-Lauf (Premium) zeichnet einen Muster-Bericht auf, bevor seine Suche beginnt. Er testet den In-Sample-Teil jedes Walk-Forward-Folds auf 36 feste Bedingungen:

Für jede Bedingung wird die Bewegung des nächsten Bars (Schlusskurs bis nächster Schlusskurs, in Basispunkten) nach den Bars, auf denen die Bedingung gilt, mit der Bewegung des nächsten Bars nach allen anderen Bars des Fensters verglichen, mit einem zweiseitigen Mann-Whitney-U-Test. Vor dem Vergleich wird jede Bewegung durch die mittlere absolute Schlusskurs-zu-Schlusskurs-Bewegung der 8 Bars geteilt, die an dem Bar enden, an dem die Bedingung beurteilt wird, damit eine Bedingung, die eher in unruhigen Phasen auftritt, nicht auf der Rohskala mit ruhigen verglichen wird; die Kennzahlen der Ansicht bleiben in Basispunkten. Ein Bar ohne 8 frühere Bewegungen oder mit 8 früheren Bewegungen, die alle null sind, bleibt in beiden Gruppen unberücksichtigt, und vor dieser Änderung gespeicherte Ergebnisse behalten die q-Werte, mit denen sie berechnet wurden. Getestet wird eine Bedingung nur, wenn sie auf mindestens 30 Bars gilt und auf mindestens 30 nicht. Die p-Werte aller in einem Fenster getesteten Bedingungen werden mit der Benjamini-Hochberg-Korrektur angepasst, weil das gleichzeitige Testen vieler Bedingungen Zufallstreffer erzeugt; als gefunden gilt eine Bedingung, wenn ihr angepasster Wert (q) 0,05 oder kleiner ist.

Die Ansicht „Patterns“ des Ergebnisses zeigt pro Fold das untersuchte und das gemessene Fenster, wie viele Bedingungen getestet wurden, und für jede gefundene Bedingung: ihre Beschreibung und die Blöcke, die sie bauen, wie oft sie galt, den Anteil steigender nächster Bars, die mittlere Bewegung des nächsten Bars, die Rangwahrscheinlichkeit und q. Jede gefundene Bedingung wird danach im Out-of-Sample-Fenster des Folds gemessen, ohne dort erneut getestet zu werden, und der zurückgehaltene Holdout wird nie gelesen. Erreicht keine Bedingung q 0,05 oder kleiner, sagt die Ansicht das.

Die Korrektur läuft innerhalb jedes Fensters, die genannten 5 % gelten also pro Fenster: Auf Daten ohne Struktur listen etwa 5 % der Fenster eine Bedingung. Ein Lauf untersucht drei Folds, deshalb zeigt auf Daten ohne Struktur etwa jeder zehnte Lauf in mindestens einem Fold eine Bedingung (zwischen 8,6 % und 10,3 % der Läufe, gemessen an simulierten Reihen mit 20.000 Bars ohne Struktur). Jede Bedingung zeigt, in wie vielen Folds sie gefunden wurde; eine Bedingung, die in allen drei Folds gefunden wurde, ist mehr Evidenz als eine, die nur in einem Fold gefunden wurde, auch wenn sich die Fenster der Folds überlappen.

Der Bericht steht neben den Kandidaten und steuert die Suche nicht. Er beschreibt vergangene Daten: eine Bedingung, die den Test bestanden hat, ist eine gemessene Regelmäßigkeit dieses Fensters, kein Handelssignal. Bei Tickdaten werden die Ticks zuerst zu 1-, 5-, 15- und 30-Minuten-Bars aus dem Mittelkurs zusammengefasst, nach der Regel der Tick-zu-Bar-Blöcke, und die Bedingungen aller vier Perioden werden als eine Familie korrigiert.

Structure Finder: Fitness und Mindestzahl an Trades

Die Fitness eines Kandidaten ist der Median seiner Out-of-Sample-Werte über die Walk-Forward-Folds, standardmäßig 3. In jedem Fold werden die abstimmbaren Parameter auf dem In-Sample-Fenster des Folds angepasst, und der Kandidat wird danach auf dem anschließenden Out-of-Sample-Fenster gemessen.

Ein Kandidat hat nur dann eine Fitness, wenn jeder Fold genug Trades enthält. Die Mindestzahl des Laufs, standardmäßig 30 Trades, wird auf die Folds verteilt und aufgerundet: bei 3 Folds braucht jeder Fold mindestens 10 Out-of-Sample-Trades, bei 4 Folds mindestens 8. Ein Kandidat, bei dem ein Fold darunter liegt, steht ohne Wert in der Liste, was auch immer die anderen Folds gemessen haben, und die Erklärung seiner Zeile nennt den Fold und die Zahl, die ihm fehlte.

Der Grund ist die Obergrenze des Profitfaktors. Der Profitfaktor eines Folds zählt höchstens 10, und ein Fold mit drei gewinnenden Trades erreicht sie. Wird die Mindestzahl über alle Folds zusammen gezählt, kann ein solcher Fold den Median eines Kandidaten bestimmen, dessen übrige Trades auf die beiden anderen Folds fallen.

Ist die Fitness eine Sharpe-, Sortino- oder Adjusted-Sortino-Ratio, wird ein Fold, dessen Quotient den Hinweis „few observations“ (wenige Beobachtungen) trägt (weniger als 6 Monatsergebnisse oder Monatsergebnisse, die kaum schwanken), bei den Folds des Kandidaten angezeigt und im Median nicht gezählt. Ein Kandidat, bei dem kein Fold zum Zählen übrig bleibt oder bei dem ein Fold einen nicht definierten Quotienten hat, hat keine Fitness und steht ohne Wert in der Liste.

Neben der Fitness und dem zurückgehaltenen Wert zeigt jeder Kandidat das Risiko, das geschlossene Trades nicht zeigen. Distance to stop ÷ avg win ist der mittlere Abstand vom Einstieg zum Stopp bei den Out-of-Sample-Trades des Kandidaten, geteilt durch seinen durchschnittlichen Gewinntrade. MAE ÷ avg win ist die weiteste Bewegung eines einzelnen Trades gegen seinen Einstieg, geteilt durch denselben durchschnittlichen Gewinn. Wide stop markiert einen Kandidaten, dessen Stopp mehr als das 20-Fache so weit vom Einstieg entfernt liegt wie sein Ziel, oder wie sein durchschnittlicher Gewinn, wenn er kein Ziel setzt. Nichts wird ausgeschlossen und die Reihenfolge ändert sich nicht: Die Kennzahlen sind Spalten der Ergebnistabelle und Teil des Exports eines Kandidaten.

Ein Profitfaktor zählt nur die Trades, die geschlossen wurden: Hat ein Stopp innerhalb der Fenster nie ausgelöst, steckt kein Verlust daraus in der Kennzahl, wie weit der Stopp auch entfernt liegt. Ein Profitfaktor von 10 neben einem Stopp, der nie ausgelöst hat, zeigt deshalb, wie oft das Ziel erreicht wurde, und nicht, was der Stopp gekostet hätte.

Was ein Backtest abbildet und was nicht

Nächste Schritte

Bereit, eine Strategie zu bauen? Starte im Graph-Editor auf der /graph-Seite. Oder lies die Block-Referenz, um zu verstehen, was verfügbar ist.