前回は2ステージパイプラインの実装を解説しました。今回は どうやって各銘柄に最適なエンジンとパラメータを見つけるか を説明します。
なぜバックテストが必要か
Hermes Agent は銘柄ごとに異なる設定を持っています。
// data/strategy-params.json(抜粋)
{
"META": {
"engines": [
{ "type": "structural", "smaFast": 20, "smaSlow": 50, "rsiOverboughtStrong": 60, "rr": 2, ... },
{ "type": "structural", "smaFast": 50, "smaSlow": 100, "rsiOverboughtStrong": 65, "rr": 2.5, ... }
]
},
"GBP_USD": {
"engines": [
{ "type": "structural_htf", "smaFast": 50, "smaSlow": 100, ... },
{ "type": "structural", ... },
{ "type": "rebound", ... }
]
}
}
この設定値は手で決めたものではなく、Pythonのバックテストでグリッドサーチ最適化して得た値です。
バックテストの構成
python/backtest/
├── optimize.py # パラメータグリッドサーチ
├── walkforward.py # ウォークフォワード検証
├── fx_stage1.py # FX専用バックテストエンジン
├── run_fx_optimize.sh # FX一括最適化スクリプト
├── run_stock_optimize.sh # 株式一括最適化スクリプト
└── data/ # 過去データ(yfinance / Alpaca / OANDA)
最適化スクリプトの仕組み
ステップ1:過去データの取得
# yfinance / Alpaca API から過去2〜3年のOHLCVを取得
import yfinance as yf
df = yf.download("QQQ", period="3y", interval="1h")
ステップ2:グリッドサーチ
エンジンの種類(structural, rebound, breakout…)× パラメータ範囲を総当たりで検証。
param_grid = {
"engine_type": ["structural", "trend", "rebound", "breakout", "pullback"],
"sma_fast": [10, 20, 50],
"sma_slow": [50, 100, 200],
"rsi_overbought_strong":[60, 65, 70, 75],
"rsi_oversold_strong": [25, 30, 35, 40],
"rr": [2.0, 2.5, 3.0],
"atr_gate": [1.5, 2.0, 2.5],
"swing_bars": [5, 8, 13],
}
ステップ3:評価指標(SQN)
スコアリングは System Quality Number(SQN) を使っています。
SQN = (平均R倍数 / R倍数の標準偏差) × √取引数
R倍数 = 実際の損益 ÷ 想定リスク(エントリーからSLまで)
- SQN > 2.0 → 優秀
- SQN 1.0〜2.0 → 良好
- SQN < 0.5 → 採用しない
勝率だけで評価すると「小さく勝って大きく負ける」戦略が残ってしまうため、SQN を使うことでリスクリワードのバランスも評価できます。
ステップ4:ウォークフォワード検証
過学習を防ぐため、最適化したパラメータを未来データで検証します。
データ期間:3年
├─ 最適化 (IS): 2年 → 最良パラメータを選ぶ
└─ 検証 (OOS): 1年 → そのパラメータで未来を再現できるか確認
IS(In-Sample)で高スコアでも OOS で崩れる場合は採用しません。
実際の最適化結果例
| Symbol | Engine | SMA | RSI_ob | RR | SQN | Win Rate |
|---|---|---|---|---|---|---|
| META | structural | 20/50 | 60 | 2.0 | 1.97 | 58% |
| GBP_USD | structural_htf | 50/100 | 70 | 2.0 | 3.94 | 62% |
| BTC/USD | rebound | — | 70 | 2.5 | 2.15 | 55% |
GBP_USD の structural_htf(4時間足バイアスフィルター付き)が SQN=3.94 と突出して高いのが見てわかります。
注意点:スコア < 1.0 は採用しない
バックテスト結果がどれだけ良くても、SQN < 1.0 のエンジンは strategy-params.json に含めません。これにより「バックテストでは通るが現実では機能しない」戦略を除外しています。
# optimize.py
MIN_SQN = 1.0
best = results[results["sqn"] >= MIN_SQN].sort_values("sqn", ascending=False)
ダッシュボードでバックテスト結果を確認
Streamlit ダッシュボードの Backtest タブで最適化結果を可視化できます。
- 全シンボルのサマリー(SQN・勝率・トレード数)
- エンジン別の詳細グラフ
- ウォークフォワード結果の比較
まとめ
| 項目 | 内容 |
|---|---|
| 最適化手法 | グリッドサーチ → ウォークフォワード検証 |
| 評価指標 | SQN(リスクリワードバランスを考慮) |
| 採用基準 | SQN >= 1.0 |
| データソース | yfinance(株)/ Alpaca API(暗号資産)/ OANDA API(FX) |
次回(第4回)は リスク管理の実装。サーキットブレーカー、ポジションサイジング、VIXレジームフィルターなどを解説します。