10. 過程數據(proc.*)與動態回測(設計說明)

本章說明 qteasy 中過程數據(process data)的定義、訪問方式,以及回測時靜態分支動態分支的選擇與一致性約定,供實現與擴展時參考。使用層面的說明可在《策略如何聲明與使用數據》與 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

當前步開始時各標的持倉市值(由內部 price 與持倉計算)

成交結果

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 天內的窗口切片。

  • 約束

    • 一次調用僅允許一個 proc.* 字段;多字段或與靜態數據混合調用時拋出英文 ValueError

    • lagwindow 不可同時指定;支持 lag 爲整數(步)或字符串(如 '1d''8h'),window 爲字符串(如 '5d''8h')。

  • 返回值:統一爲 np.ndarray,形狀與數據類型以 API 文檔爲準。

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

4.1 靜態分支與動態分支

  • 靜態分支_backtest_static_operator):一次性對所有時間步調用 run_strategies 生成全部信號,再用 Numba 向量化函數 backtest_batch_steps 等完成回測。適用於不依賴過程數據的策略。

  • 動態分支_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.",若包含則視爲依賴過程數據。

因此,只要在 realize() 中調用了 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_index 設爲與 op_signal_index 對齊的時間軸。

  • Operator:在 run_strategy(step_index) 中,在每次調用 stg.generate() 前根據 group_timing_tablegroup_merge_type 計算並更新 _current_signal_index,供 Strategy 截取“當前可見”的過程數據。

4.5 實盤(Trader)中的過程數據

operator.check_dynamic_data() 爲 True 時,Trader 在 _run_strategy() 中會:

  • 將當前賬戶現金、持倉、可用數量及當前價格等組裝爲單步_process_data_sources_process_time_index(實盤單次運行視爲一步);

  • 策略在該步內調用 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 組:check_dynamic_data() 在純靜態 / 使用 proc.* 策略下的行爲;

    • B 組:靜態策略與“調用 proc 但邏輯等價”策略的回測數組一致性;

    • C 組:get_data 對靜態多源、lag/window 拒絕、proc 單字段與混合調用的報錯行爲;

    • D 組:proc.trade_records 無前視驗證;

    • E 組:基於 process data 的真實動態策略路徑正確性。

  • 項目記憶.cursor/rules/process-data-and-dynamic-backtest.mdc(實現與約定摘要)。

  • 策略數據總覽策略如何聲明與使用數據回測入口與模式回測、實盤與優化