10. プロセスデータ (proc.*) と動的バックテスト (設計仕様)

この章では、qteasy における プロセス データの定義とアクセス方法、バックテスト中の 静的ブランチ動的ブランチの選択、およびそれらの間の一貫性規則について説明し、実装および拡張の際の参考にします。使用レベルの説明については、「戦略によるデータの宣言と使用方法」および API ドキュメントと合わせて読んでください。

10.1. 1. 背景与目标

1.1 プロセスデータの意味

一部の戦略は、バックテストまたはライブ取引実行パスによって変化するデータに依存する必要があります。次に例を示します。

  • 現在/過去のポジション、利用可能な現金。

  • 過去の約定数量、約定価格、取引コスト。

  • ポジションや価格から導き出される時価や総資産など。

このようなデータは、バックテストの開始前に一度に事前生成することはできません。これは実行時にBacktester (バックテスト) または Trader (ライブ取引) によってのみ維持でき、「現在表示されているスコープ」に従ってシグナル生成の各ステップで戦略に提供されます。これを総称して プロセス データと呼びます。

1.2 設計の目的

  • 統合されたエントリ ポイント: 静的な履歴データと同様に、プロセス データは Strategy.get_data() 経由で取得されるため、学習曲線が短縮されます。

  • 先読みなし: ステップ k の信号を生成するとき、ストラテジーはステップ k の実行結果を確認できません。完了したステップの履歴のみを使用できます。

  • バックテスト/ライブの一貫性: バックテストとライブ取引の両方で、同じ戦略セットと同じ get_data('proc.xxx') 呼び出しパターンを使用できます。プロセス データが必要な場合は、動的実行パスに従いますが、それ以外の場合は、結果に関して元の静的パスとの一貫性を保つことができます。

10.2. 2. 过程数据的统一定义(proc.*)

2.1 命名と公開方法

  • すべてのプロセス データは、proc.<field_name> (proc.own_cashproc.trade_records など) の形式でストラテジーに公開されます。

  • プロセス データは、戦略の __init__data_types を介して宣言する必要はありません**。これは、Backtester / Trader によって実行時に挿入され、ストラテジーは必要に応じて realize()get_data('proc.xxx', ...) を呼び出すだけで済みます。

2.2 実装された組み込みフィールド

現在のバージョンに実装され、戦略で使用できるプロセス データ フィールドには次のものがあります。

カテゴリ

フィールド名

意味

アカウントのスカラー

proc.own_cash

現在のステップの開始時点での口座内の現金の合計

proc.available_cash

現在のステップの開始時に注文に利用できる現金

proc.total_value

現在のステップ開始時の総資産市場価値 (ポジション評価 + 現金)

位置ベクトル

proc.own_amounts

現在のステップ開始時の各商品の合計ポジション数量

proc.available_amounts

現在のステップの開始時の各商品の販売可能数量

proc.position_value

現在のステップ開始時の各商品のポジション市場価格 (内部価格とポジションから計算)

実行結果

proc.trade_records

各ステップにおける各商品の実際の約定数量 (買いの場合はプラス、売りの場合はマイナス)

proc.trade_cost

各ステップにおける各商品の取引コスト

proc.trade_price

各ステップにおける各商品の約定価格

バックテストおよびライブ取引における上記フィールドの時間セマンティクスと可視性の制約については、セクション 4 を参照してください。

2.3 将来拡張可能なフィールド (オプション)

設計によってさらに拡張できるフィールドには、proc.realized_pnlproc.unrealized_pnlproc.last_trade_priceproc.last_trade_volume などがあります。詳細については、実装とドキュメントを参照してください。

10.3. 3. 访问接口:Strategy.get_data() 与 proc.*

3.1 静的データ (proc. プレフィックスなし)

  • 単一ソース: self.get_data('close_E_d');複数のソース: self.get_data('close_E_d', 'high_E_d')

  • 静的データは、lag / window パラメータをサポートしません。指定した場合、英語の ValueError が生成されます。

3.2 プロセスデータ(proc.プレフィックス)

  • 呼び出しの例:

    • self.get_data('proc.own_cash'): 現在のステップまでの現金シリーズ。

    • self.get_data('proc.own_cash', lag=0): 最新のステップでの現金価値。

    • self.get_data('proc.own_cash', lag='1d'): 1 日を時間ごとに振り返るステップに相当します。

    • self.get_data('proc.own_cash', window='5d'): 過去 5 日間のウィンドウ スライス。

  • 制約:

    • 1 回の呼び出しで許可されるのは 1 つのみ proc.* フィールドです。複数のフィールドが使用されている場合、または同じ呼び出し内で静的データが混在している場合は、英語の ValueError が発生します。

    • lagwindow を同時に指定することはできません。 lag は整数 (ステップ) または文字列 (例: '1d''8h')、window は文字列 (例: '5d''8h') です。

  • 戻り値: 常に np.ndarray;形状とデータ型は API ドキュメントに従います。

10.4. 4. 回测分支选择与过程数据协作

4.1 静的ブランチと動的ブランチ

  • 静的分岐 (_backtest_static_operator): すべてのタイム ステップに対して run_strategies を 1 回呼び出してすべての信号を生成し、backtest_batch_steps などの Numba ベクトル化関数を使用してバックテストを完了します。プロセスデータに依存しない戦略に適しています。

  • 動的分岐 (_backtest_dynamic_operator): 時間ステップごとにループします。各ステップでシグナルを生成→解析して約定をシミュレート→ポジションとキャッシュを更新し、次のステップに進みます。プロセス データは Backtester によって維持され、各ステップの前に Operator に注入されるため、戦略は get_data('proc.xxx') を介してアクセスできます。

実行前に、Backtester は Operator.check_dynamic_data() を介してどの分岐を取るかを決定します。

4.2 check_dynamic_data()の判定ロジック(現在の実装)

次のいずれかに該当する場合は、True を返し、動的分岐を実行します。

  1. op_type == 'stepwise': Operator は明示的にステップワイズ モードに設定されています。

  2. ストラテジーのソース コードで proc. を使用する*: _strategies_use_proc_data() は、各ストラテジーの realize() のソース コードに 'proc.' または "proc." が含まれているかどうかを確認します。そうであれば、プロセスデータに依存していると考えられます。

したがって、実現()でget_data('proc.xxx')が呼び出されている限り、宣言なしで自動的に動的分岐を実行します。プロセスデータには、proc.* を介してのみアクセスできます。 DataType を介した宣言はサポートされなくなりました (従来の op_* タイプは削除されました)。

4.3 先読み保証なし

  • 戦略がステップ k でシグナルを生成すると、次のようになります。

    • 口座/ポジション データ (例: own_cashesown_amounts) は、最大でインデックス [0..k] (つまり、現在のステップの開始時の状態) まで表示されます。

    • 取引関連データ (例: trade_recordstrade_cost) は、このステップでまだ発生していない取引を除く として、最大で [0..k-1] まで表示されます。

  • 実装では、Operator の _current_signal_index と Strategy の _get_process_data_single() が上記の範囲でスライスされます。 Backtester は、各ステップで信号を生成する前にインデックスを更新し、先読みを行わないようにします。

4.4 BacktesterとOperatorの注入関係

  • Backtester (動的ブランチ): _backtest_dynamic_operator エントリ ポイントで、own_cashesavailable_cashesown_amounts_arrayavailable_amounts_arraytrade_records_arraytrade_cost_arraytrade_price_arraytrade_price_data などを _process_data_sources として Operator に追加し、_process_time_indexop_signal_index に合わせたタイムラインに設定します。

  • Operator: run_strategy(step_index) では、stg.generate() を呼び出す前に、Strategy が「現在表示されている」プロセス データをスライスするために、group_timing_tablegroup_merge_type に基づいて _current_signal_index を計算して更新します。

4.5 ライブ取引におけるプロセスデータ (Trader)

operator.check_dynamic_data() が True の場合、Trader は _run_strategy() で次の処理を実行します。

  • 当座預金の現金、ポジション、利用可能な数量、現在の価格などを シングルステップ _process_data_sources および _process_time_index に組み立てます (単一のライブ取引実行は 1 ステップとして扱われます)。

  • このステップ内で、ストラテジーは get_data('proc.own_cash') などを呼び出して、現在の口座/ポジションのビューを取得できます。このステップ内の取引履歴は空であり、「このステップではまだ取引が行われていない」というセマンティクスと一致します。

10.5. 5. 动态/静态路径一致性约定

  • 戦略が プロセス データを使用しない場合、静的ブランチを選択する必要があります。他の理由で動的ブランチを選択する場合、バックテストの結果は、(同じ構成とデータの下で) 静的ブランチと数値的にまったく同じになるはずです。

  • 戦略がデータを使用する場合、動的ブランチを通過する必要があります。そうしないと、_process_data_sources が挿入されず、RuntimeError がトリガーされます。

  • テスト規約: StaticSignalStg (純粋に静的) と ProcAwareButStaticLogicStg (proc を呼び出すがシグナルには使用しない) を使用して、同じ構成の下でバックテストを行い、own_cashesown_amounts_arraytrade_records_array などの数値の一貫性を主張します。 tests/test_process_data_api.py のグループ B を参照してください。

10.6. 6. 测试与文档索引

  • 専用テスト: tests/test_process_data_api.py

    • グループ A: 純粋に静的な戦略 / proc.* を使用した戦略の下での check_dynamic_data() の動作。

    • グループ B: 静的戦略と「プロシージャを呼び出すが論理的に同等」戦略の間の配列の一貫性をバックテストします。

    • グループ C: 静的マルチソースのget_data エラー動作、ラグ/ウィンドウ、proc 単一フィールド、および混合呼び出しの拒否。

    • グループ D: proc.trade_records の先読み検証なし。

    • グループ E: プロセス データに基づく実際の動的戦略パスの正確さ。

  • プロジェクト メモリ: .cursor/rules/process-data-and-dynamic-backtest.mdc (実装と規約の概要)。

  • 戦略データの概要: 戦略がデータを宣言および使用する方法; バックテストのエントリ ポイントとモード: バックテスト、ライブ取引、最適化