9. Designabsicht und einzigartige Vorteile
Dieses Kapitel konzentriert sich auf die Designabsicht und einzigartige Vorteile von qteasy: Warum es auf vektorisiertes Hochgeschwindigkeits-Backtesting abzielt, aber auf die „Vollzeitlinien-Vektorisierung“ verzichtet, wie es Geschwindigkeit und Vermeidung von Look-Ahead-Bias durch „Vektorisierung + Datenisolation“ in Einklang bringt und wie konfigurierbare Optionen wie use_latest_data_cycle Backtests mit langem Horizont beeinflussen. Es spiegelt [Gesamtarchitektur- und Designansatz] (00-overview.md) und [Daten in Strategien] (03-data-in-strategies.md) wider.
9.1. 1. 为何不做全时间轴向量化
1.1 Zukünftiges Funktionsrisiko
Wenn Sie Indikatoren einmal über die gesamte Zeitachse berechnen (z. B. einen EMA mit allen historischen Daten), ist die resultierende historische Reihe nicht konsistent mit dem Ergebnis der „Berechnung Segment für Segment unter Verwendung nur des zu diesem Zeitpunkt sichtbaren historischen Fensters“: Ein EMA mit allen Achsen verwendet zukünftige Preise, die im Live-Handel nicht reproduziert werden können, was zu Abweichungen zwischen Backtests und Live-Handel führt. Daher berechnet qteasy Indikatoren nicht „auf einmal für das gesamte Segment“ entlang der Zeitdimension; Stattdessen wird die Strategie Schritt für Schritt nur für das Datenfenster bereitgestellt, das im aktuellen Schritt sichtbar ist.
1.2 Zustände und Regeln können nicht ausgedrückt werden
Bei vollständiger Vektorisierung entlang der Zeitdimension wird die korrekte Implementierung schwierig:
Einschränkungen wie T+1-Abwicklung, Handelsgebühren und Mindestbestellmenge (MOQ);
Eine Modellierungsauswahl, ob die Verwendung der neuesten Daten „zum Zeitpunkt des Handels“ (der aktuelle Candlestick/K-Linie) zulässig ist.
Diese Details können bei langfristigen Backtests zu multiplizierten Renditeunterschieden führen (z. B. kann bei einem zehnjährigen Backtest der winzige Unterschied, „ob die K-Line-Daten des aktuellen Balkens verwendet werden sollen“, die kumulativen Renditen erheblich verändern). qteasy macht „ob aktuelle Balkendaten verwendet werden sollen“ zu einer expliziten use_latest_data_cycle-Konfigurationsoption und nicht zu einer impliziten Annahme.
9.2. 2. 事件驱动的替代与取舍
Ein gängiger Ansatz ist ereignisgesteuert: Rufen Sie für jedes Handelsereignis Daten pro Instrument ab und berechnen Sie Indikatoren Tick für Tick. Dadurch wird ein Look-Ahead-Bias vollständig vermieden und Sie bleiben nah am Live-Handel, aber es ist langsam. Der Kompromiss von qteasy besteht darin, die Korrektheit zu bewahren – „nach Zeitschritt, wobei nur zu diesem Zeitpunkt sichtbare Daten verwendet werden“ – und gleichzeitig Vektorisierung + Numba-Beschleunigung innerhalb eines einzigen Schritts zu verwenden, um die Geschwindigkeit auszugleichen und gleichzeitig die Korrektheit sicherzustellen.
9.3. 3. qteasy 的做法:向量化 + 数据隔离
3.1 Vektorisierung des Backtesting-Kerns
Die Backtest-Schleife und die Handelsberechnungen (Kauf-/Verkaufsvolumen, Gebühren, Positionen, Abwicklung) wurden mit NumPy + Numba implementiert: sequenzielles Vorwärtsgehen entlang der Zeitdimension und Vektorisierung über Instrumente hinweg innerhalb jedes Schritts. Siehe Backtest-Engine und Leistung (Designperspektive).
3.2 Vorverpacken und Zusammenbauen der Daten im Voraus und schrittweise Injektion
Vorbereitungsphase: Vor dem Backtesting alle erforderlichen historischen Daten aus dem DataSource über „check_and_prepare_backtest_data“, „prepare_data_buffer“ usw. abrufen und zwischenspeichern; Verwenden Sie dann „create_data_windows“, um mit „rolling_window“ einen Datenfenster-Stream zu generieren, der an der Laufkadenz ausgerichtet ist (jeder Schritt entspricht einem historischen Fenster fester Länge).
Bevor jeder Schritt ausgeführt wird: Die Engine ruft update_running_data_window auf, um das Datenfenster, das dem aktuellen Schritt entspricht, in Strategieattribute zu schreiben; Innerhalb von „realize()“ kann die Strategie das für diesen Schritt sichtbare Fenster nur über get_data(dtype_id) abrufen und Indikatoren wie den EMA für dieses Fenster berechnen – im Einklang mit „nur dem Verlauf, der zu diesem Zeitpunkt sichtbar war“ im Live-Handel – wodurch eine Voreingenommenheit durch Design vermieden wird.
Der Datenfluss ist „deklarieren → die Engine fügt Schritt für Schritt ein → referenziert durch get_data“, und der Strategiecode enthält keine „Tabellen lesen“ oder „Abruf/Pull“-Logik. Siehe [Wie Strategien Daten deklarieren und verwenden] (03-data-in-strategies.md).
3.3 Die Bedeutung und Auswirkung von use_latest_data_cycle (ulc)
use_latest_data_cycle steuert, ob das Datenfenster den aktuellen Balken (K-Linie) enthält:
Richtig: Das Fenster kann den aktuellen Balken (z. B. den Schlusskurs) enthalten, entsprechend der Modellierung „ob beim Handel der aktuellste Preis zu diesem Zeitpunkt verwendet werden darf“.
Falsch: Das Fenster liegt streng vor dem aktuellen Zeitpunkt und verwendet nur Daten, die in der Vergangenheit „bereits geschlossen“ wurden.
Dieser Wechsel hat erhebliche Auswirkungen auf die langfristigen Backtest-Ergebnisse. qteasy macht es als konfigurierbare Option in Strategiedeklarationen und Ausführungskonfigurationen verfügbar; Die Dokumentation und die API sollten dies klar darlegen und auf die Konfigurationshinweise verweisen.
9.4. 4. 独特优势小结
Hohe Geschwindigkeit + Look-Ahead-Verhinderung: Während sichergestellt wird, dass „jeder Schritt nur zu diesem Zeitpunkt sichtbare Daten verwendet“, wird ein schnelles Backtesting mit Vektorisierung + Numba erreicht, wodurch Geschwindigkeit und Glaubwürdigkeit des Backtests in Einklang gebracht werden.
Feingranulare Handelsmodellierung: T+1, Gebühren, Abwicklung, MOQ und „ob die Daten des aktuellen Balkens verwendet werden sollen“ usw. können alle modelliert werden. Backtests mit langem Horizont reagieren empfindlich auf solche Details, und qteasy unterstützt die explizite Konfiguration.
Präzise Schnittstelle: Benutzer müssen nur Daten über „get_data()“ in „realize()“ abrufen und Signale berechnen; Das Framework verwaltet das Datenfenster und die Zeitausrichtung und verringert so die Wahrscheinlichkeit einer versehentlichen Verwendung zukünftiger Daten.
9.5. 5. 代码依据摘要
Datenvorbereitung und Fenster: „check_and_prepare_backtest_data“ in „history.py“; „prepare_data_buffer“ und „create_data_windows“ in „qt_operator.py“ (wenden Sie „rolling_window“ auf „buffered_data.values“ an und richten Sie es an dem laufenden Zeitplan aus);
ulcbestimmt, ob das Fenster die aktuelle Leiste enthält.Schrittweise Injektion: In „qt_operator.py“ ruft „run_strategy(step_index)“ bei jedem Schritt „update_running_data_window(…, window_index=step_index)“ für die Strategie auf; In „strategy.py“ weist „update_running_data_window“ den Attributen der Strategie das entsprechende Datenfenster zu, und „get_data()“ liest genau das Fenster dieses Schritts.
Weitere Implementierungsdetails finden Sie in den Kapiteln in Architektur und Design und in der API-Referenz.