9. 設計意図と独自の利点
この章では、qteasy の 設計意図 と **独自の利点 ** に焦点を当てます。つまり、高速ベクトル化されたバックテストをターゲットとしながら「フルタイムライン ベクトル化」を放棄する理由、「ベクトル化 + データ分離」を通じて速度と先読みバイアスの防止のバランスをどのように取るか、use_latest_data_cycle などの構成可能なオプションが長期バックテストにどのように影響するかについて説明します。これは、全体的なアーキテクチャと設計アプローチ および 戦略におけるデータ を反映しています。
9.1. 1. 为何不做全时间轴向量化
1.1 将来の機能リスク
タイムライン全体にわたってインジケーターを 1 回計算する場合 (全履歴 EMA など)、結果として得られる履歴シリーズは、「その時点で表示されている履歴ウィンドウのみを使用してセグメントごとに計算する」結果と一貫性がありません。全軸 EMA では将来の価格が使用されますが、これはライブ取引では再現できないため、バックテストとライブ取引の間に乖離が生じます。したがって、qteasy は、時間次元に沿って「セグメント全体のワンショットで」指標を計算しません。代わりに、段階的に、現在のステップでデータ ウィンドウのみが表示される戦略を提供します。
1.2 状態とルールは表現できない
時間次元に沿って完全にベクトル化すると、正しく実装することが難しくなります。
T+1 決済、取引手数料、最小注文数量 (MOQ) などの制約。
「取引時」の最新データ (現在のローソク足/K ライン) の使用を許可するかどうかのモデリングの選択。
これらの詳細により、長期バックテストではリターンに何倍もの違いが生じる可能性があります(たとえば、10 年間のバックテストでは、「現在の足の K ライン データを使用するかどうか」という小さな違いが累積リターンを大きく変える可能性があります)。 qteasy は、「現在バー データを使用するかどうか」を、暗黙的な仮定ではなく明示的な use_latest_data_cycle 構成オプションにします。
9.2. 2. 事件驱动的替代与取舍
一般的なアプローチは イベント駆動型です。取引イベントごとに、商品ごとにデータを取得し、ティックごとに指標を計算します。これにより、先読みバイアスが完全に回避され、ライブ取引に近い状態が保たれますが、時間がかかります。 qteasy のトレードオフは次のとおりです。ベクトル化 + Numba アクセラレーションを単一ステップ内で使用しながら、「タイム ステップごとに、その時点で表示されているデータのみを使用」して正確さを確保しながら速度のバランスを保ちます。
9.3. 3. qteasy 的做法:向量化 + 数据隔离
3.1 バックテストコアのベクトル化
バックテスト ループと取引計算 (売買量、手数料、ポジション、決済) は NumPy + Numba を使用して実装されています。時間次元に沿って順次前進し、各ステップ内で商品全体をベクトル化します。 バックテスト エンジンとパフォーマンス (設計の観点) を参照してください。
3.2 事前のデータのパッケージ化と組み立て、および段階的な注入
準備段階: バックテストの前に、
check_and_prepare_backtest_data、prepare_data_bufferなどを介して、DataSource から必要な履歴データをすべてプルしてキャッシュします。次に、create_data_windowsを使用して、rolling_windowで実行ケイデンスに合わせたデータウィンドウ ストリームを生成します (各ステップは固定長の履歴ウィンドウに対応します)。各ステップの実行前: エンジンは update_running_data_window を呼び出して、現在のステップに対応するデータ ウィンドウをストラテジ属性に書き込みます。
realize()内では、この戦略は get_data(dtype_id) を介して そのステップで表示されるウィンドウ のみを取得でき、ライブ取引で「その時点で表示されていた履歴のみ」と一致して、そのウィンドウで EMA などの指標を計算します。これにより、設計により先読みバイアスが回避されます。
データフローは「宣言→エンジンが段階的に注入→get_dataで参照」となり、ストラテジーコードには「テーブルの読み取り」や「フェッチ/プル」ロジックは含まれません。 ストラテジーによるデータの宣言と使用方法 を参照してください。
3.3 use_latest_data_cycle (ulc) の意味と影響
use_latest_data_cycle は、データ ウィンドウに 現在のバー (K ライン) を含めるかどうかを制御します。
True: ウィンドウには、「その時点での最新価格を使用した取引が許可されているかどうか」のモデリングに対応する、現在のバー (終値など) が含まれる場合があります。
False: ウィンドウは厳密に現時点より前であり、過去に「すでに閉じられた」データのみを使用します。
この切り替えは、長期的なバックテストの結果に大きな影響を与えます。 qteasy は、戦略宣言および実行構成で構成可能なオプションとしてこれを公開します。ドキュメントと API にはそれを明確に記載し、構成メモにリンクする必要があります。
9.4. 4. 独特优势小结
高速 + 先読み防止: 「各ステップはその時点で表示されているデータのみを使用する」ことを保証しながら、ベクトル化 + Numba による高速バックテストを実現し、速度とバックテストの信頼性のバランスをとります。
きめ細かい取引モデリング: T+1、手数料、決済、MOQ、「現在のバーのデータを使用するかどうか」などをすべてモデル化できます。長期的なバックテストはそのような詳細に敏感であり、qteasy は明示的な構成をサポートしています。
簡潔なインターフェイス: ユーザーは、
realize()のget_data()を介してデータをフェッチし、信号を計算するだけで済みます。フレームワークはデータ ウィンドウと時間調整を処理し、将来のデータを誤って使用する可能性を減らします。
9.5. 5. 代码依据摘要
データの準備とウィンドウ:
history.pyのcheck_and_prepare_backtest_data;qt_operator.pyのprepare_data_bufferとcreate_data_windows(rolling_windowをbuffered_data.valuesに適用し、実行スケジュールに合わせます)。ulcは、ウィンドウに現在のバーが含まれるかどうかを決定します。ステップバイステップインジェクション:
qt_operator.pyでは、run_strategy(step_index)が各ステップで戦略に基づいてupdate_running_data_window(..., window_index=step_index)を呼び出します。strategy.pyでは、update_running_data_windowは対応するデータ ウィンドウを戦略の属性に割り当て、get_data()が読み取るものはまさにそのステップのウィンドウです。
実装の詳細については、アーキテクチャと設計の章と API リファレンスを参照してください。