バックテスト内部仕様
このページは、atc backtest が内部で何をしているかを、実装ベースで説明します。
対象コード:
src/atc/cli/backtest.pysrc/atc/execution/execution_manager.pysrc/atc/features/feature_engine.py
0. この文書でいう「イベント」とは
ATCにおけるイベントは、src/atc/core/event_models.py の CanonicalEvent です。
1件のイベントは「市場または内部状態の1回の更新」を表します。
主要フィールド:
event_type: 何の更新か(例:TRADE,TICKER,ORDERBOOK_SNAPSHOT)exchange_ts_utc: 取引所時刻(UTC)recv_ts_utc: 受信時刻(UTC)symbol: 対象銘柄(例:ETH_JPY)payload: イベント固有データ(約定価格、bid/ask、板スナップショットなど)
戦略は、このイベント列を1件ずつ処理して TargetPositionIntent を返します。
0.2 イベントはどこから来るか(取得元と使用データ)
ATCでバックテストに使うイベントは、主に次の2系統です。
| EventType | 主な取得元 | 具体的な入力データ | Canonical化コード | バックテストで主に使うフィールド |
|---|---|---|---|---|
TRADE | GMOヒストリカルCSV | symbol,side,size,price,timestamp | src/atc/data/ingest_historical.py | price, side, size, exchange_ts_utc |
TRADE | GMO Public WS trades | 約定メッセージ(side/size/price/timestamp) | src/atc/data/ingest_ws_public.py + src/atc/exchange/gmo/ws_public.py | price, side, size, exchange_ts_utc |
TICKER | GMO Public WS ticker | best bid/ask, last, timestamp | 同上 | bid, ask, last |
ORDERBOOK_SNAPSHOT | GMO Public WS orderbooks | bids/asks スナップショット | 同上 | 上位板価格・サイズ(imbalance/depth/microprice計算) |
補足:
- ヒストリカルCSVのURLパターン:
https://api.coin.z.com/data/trades/{SYMBOL}/{YYYY}/{MM}/{YYYYMMDD}_{SYMBOL}.csv.gz - 保存フロー:
raw -> canonical -> derived - 通常のヒストリカルバックテストでは
TRADEが中心です(板情報はWS収集データがある期間のみ利用可能)。
0.1 処理フロー(全体)
1. 入力と初期状態
atc backtest は次を受け取ります。
- 期間:
--start,--end(JST営業日) - 戦略:
--strategy - 実行制約:
--order-latency-sec(既定0.3秒)--min-order-interval-sec(既定300秒)- 比較基準:
--benchmark-hold-eth(既定10.0)
初期ポジションと初期現金は次で指定します。
--initial-position-eth--initial-cash-jpy
2. イベントごとの処理順序
各イベントで次を実行します。
FeatureEngine.update(event)
mid,spread,logret_1s/5s/30s,rv_5s/30s,trade_imbalance_1sなどを更新
- 保留中limit注文の約定判定
- 注文有効化時刻(submit + latency)以降の
TRADEを見て fill 判定 - 買い:
trade_price <= limit_price - 売り:
trade_price >= limit_price
- 戦略評価(該当イベントタイプのみ)
on_event()がTargetPositionIntentを返す
- リスク判定
RiskManager.allow_target(...)が拒否した注文は採用しない
- 発注制約
min_order_interval_sec未満ならthrottled_min_interval- 既存保留注文があれば置換キャンセルして新規注文を保留
- 損益更新
equityの差分をstrategy_pnl_stepとして累積- benchmark差分:
benchmark_hold_eth * (mid_t - mid_{t-1}) alpha_step = strategy_step - benchmark_step
3. セッション強制クローズ(任意)
--enforce-session-close をONにした場合のみ、以下が有効です。
- 新規建て抑制:
05:49:00以降(既定10分) - 強制クローズ窓:
05:55:00以降 - デッドライン:
05:59:50以降 - fallback: 未解消なら market close(許可時)
関連引数:
--no-new-entry-minutes--force-close-start-jst--close-deadline-jst--allow-market-fallback / --no-market-fallback
4. 出力JSONの読み方
主なフィールド:
strategy_total_pnl_jpy: 戦略の累積損益benchmark_total_pnl_jpy: 固定保有の累積損益alpha_total_pnl_jpy: 超過損益metrics.alpha_sharpemetrics.alpha_max_ddorders,fills,metrics.fill_rate,metrics.turnover
強制クローズ関連:
forced_close_ordersforced_close_fillsmarket_fallback_countdeadline_breach_flag
4.1 Postgres への結果同期(任意)
ATC_POSTGRES_WRITE_ENABLED=true のとき、run_backtest_cli は JSON ファイル出力後に
src/atc/storage/postgres_sink.py 経由で backtest_runs へ upsert します。
設計方針:
- ファイル出力を主系とし、DB同期は副系
- DB同期失敗は backtest 自体を失敗させない(例外を吸収)
- Dashboardは保存済みレコードのみを比較対象にする
5. 価格可視化(overlay)
--plot を付けると、注文マーカー付きチャートを生成します。
- HTML: インタラクティブ確認向け
- PNG: レポート添付向け
uv run atc backtest \
--symbol ETH_JPY \
--start 2026-01-01 \
--end 2026-01-31 \
--strategy ml_hold10_softmax_overlay_derisk_only_aggressive \
--initial-position-eth 10 \
--benchmark-hold-eth 10 \
--target-abs-qty-eth 10 \
--max-abs-position-eth 10 \
--min-order-interval-sec 300 \
--plot --plot-format both --plot-interval 5m
6. 再現性を壊しやすいポイント
- 初期条件の不一致
initial_position_ethとbenchmark_hold_ethが揃っていない比較
- 実行制約の差
order_latency_sec/min_order_interval_secの違い
- セッション制約の混在
enforce_session_closeのON/OFFが実験間で一致していない
- 学習モデルの参照先違い
- 環境変数や
latestモデルが別ファイルを指している