唯一の道具は rolling walk-forward であり、それが検証しているのはひと組のパラメータではありません。
教科書でも、さらには私たち自身の〈バックテストの読み方〉でも、同じ一文を読んだことがあるはずです。データ全体で最適化してはいけない、少なくとも 20–30% はアウトオブサンプル検証のために取り置くこと。そしてワークスペースを開き、タブを一通りクリックしてみても、その比率設定はどこにも見つかりません。
見つからないのは正常で、製品にその機能がありません。アウトオブサンプルという件について Blave にある実装はひとつだけ、5 番目のタブの rolling walk-forward であり、そこに入れるのは日数で、検証する対象も単純な分割とは少し違います。この記事では違いがどこにあるか、そのタブ上の数字をどう読むかをはっきりさせます。
〈戦略の過剰最適化を避ける方法〉には 3 つのやり方を格付けした表があります。全データで最適化(無効)、前半 70% で学習し後半 30% でテスト(有効だが限定的)、ローリングで選び直し(最も現実的)。あの表は概念レベルの判断です。製品レベルの事実はというと——ボタンがあるのは 3 番目だけです。
| やり方 | 概念上 | Blave では |
|---|---|---|
| 全履歴で最適化し、全履歴で報告する | インサンプル。必然的に楽観的 | バックテストタブはもともと全履歴の上で成績を計算するので、だからこそ別途の検証が要る |
| 一度切る:前半で学習、後半でテスト | 有効だが一度しか使えない | この機能はありません。比率設定は見つかりません |
| Rolling walk-forward:毎ラウンド選び直し、次の区間でテスト | 実運用に最も近いやり方 | ワークスペースの 5 番目のタブ「アウトオブサンプル」 |
違いはインターフェースだけではありません。単純な分割が検証するのは「このひと組のパラメータが後半のデータで良いかどうか」です。rolling walk-forward が検証するのは「過去データでパラメータを選ぶ」というやり方そのものがこの戦略において成り立つかどうかであり、「ひと区間の過去データでパラメータを選ぶ」という行為を n 回繰り返し、そのたびに見たことのない次の区間で採点します。
一文で言うと:すべての学習期間の中でパラメータを選び直し、直後のテスト期間に適用し、テスト期間をすべてつないで 1 本にする。
| ラウンド | 学習期間 | テスト期間 |
|---|---|---|
| 1 | 2022-01-05 → 2024-12-30 | 2024-12-31 → 2025-01-29 |
| 2 | 2022-02-04 → 2025-01-29 | 2025-01-30 → 2025-02-28 |
| 3 | 2022-03-06 → 2025-02-28 | 2025-03-01 → 2025-03-30 |
| … | (間の各ラウンドも同様にテスト期間ひとつ分ずつ前へ進み、全 20 ラウンド) | |
| 20 | 2023-07-29 → 2026-07-23 | 2026-07-24 → 2026-08-22 |
テスト期間は日単位で端から端までつながります:ラウンド 1 は 2025-01-29 で止まり、ラウンド 2 は 2025-01-30 から引き継ぎ、間に隙間も重なりもありません——20 区間をつないだものが、あのアウトオブサンプル系列です。
一方、学習期間は大きく重なります:3 年の期間が 1 ラウンドにつき 30 日しか進まないため、どの 2 ラウンドを取っても学習期間はほぼ同じデータです。重なるものはひと続きの線につなげません——だからこそ図にはアウトオブサンプルの 1 本しかないのです。
実装上は 2 回走ります。1 回目は候補パラメータごとのシグナルを全履歴の上で一度だけ計算し、各ラウンドの学習スライスを切り出して価格評価します。2 回目は各ラウンドの勝ち組だけを計算し直し、テストスライスをつないで 1 本にし、一度の価格評価で全区間を計算します。だから「完全な探索を n 回走らせる」よりはるかに速いのです——下記の 20 ラウンド、4.7 年の 1 時間足の例は、2026-09-17 の実行では 3.5 秒で終わりました(インターフェースの確認ダイアログが示しているのは一般論です:「通常 2 分ほどで完了し、結果はこのタブに表示されます。」)。
Rolling は学習期間が毎ラウンドまるごと前へ滑っていくもの、anchored は始点を固定して学習期間がどんどん長くなっていくものです。製品が提供するのは rolling のみで、anchored は意図的に提供していません。 agent に anchored を頼むと、決まった一文を返したうえで rolling を走らせます:
回り道を考える必要もありません。walk-forward を走らせる lib は読み取り専用で、常駐プログラムが編集をそのまま拒否します。さらに結果ファイルには「これは anchored で走らせた」と記録できるフィールドがありません。本当に書き換えたとしても、画面は依然として rolling として表示します。
タブにあるのは 2 つの入力欄だけです——学習期間とテスト期間、単位はどちらも日で、隣に「全 n ラウンド」に切れることがリアルタイムで表示されます。どちらも入れなければ、この既定の表に従います:
| データの長さ(日) | 学習期間(日) | テスト期間(何日ごとに選び直すか、日) |
|---|---|---|
| ≥ 1185 | 1095(3 年) | 30 |
| 455–1184 | 365(1 年) | 30 |
| < 455 | テスト期間の 4 倍 | 総日数 ÷ 12、最小 30 |
3 年という段には理由があります。「ユーザーがバックテスト全体からひと組の固定パラメータを選ぶ」という実際のやり方に近いからです。中くらいの長さの履歴にそのまま比率の式を当てはめると学習期間が 1 年を下回ってしまうため、間に 365/30 の段を足してあります。
2 つのハードな上下限が、中途半端な結果を渡さずにその場で止めます。3 ラウンド未満は走らせず、結果ファイルも書きません(「データは {n} ラウンド分しかありません。アウトオブサンプルを読むには最低 3 ラウンド必要です」)。1000 ラウンド超も同様に止めます(「テスト期間を長くしてください」)。末尾の 1 ラウンドに満たないデータを無理につなぐことはなく、図の下に「末尾 {d} 日は 1 ラウンドに満たないため除外」と注記されます。
結論カードが見るのは 1 つの数字だけです:
WFE = アウトオブサンプル Sharpe ÷ インサンプル平均 Sharpe
分子はつなぎ合わせた区間全体のアウトオブサンプル系列の Sharpe、分母は各ラウンドの学習期間で選ばれたそのセル自身の Sharpe の平均です。4 段階のラベルはこの境界に従います(いずれも「未満」なので、0.5 は「基準をわずかに上回る」に、0.7 は「基準以上」に入ります):
| WFE | 結論カードの表示 |
|---|---|
| 算出できない | アウトオブサンプル効率:判定不能 |
| < 0.2 | アウトオブサンプル効率:基準を大きく下回る |
| < 0.5 | アウトオブサンプル効率:基準未満 |
| < 0.7 | アウトオブサンプル効率:基準をわずかに上回る |
| ≥ 0.7 | アウトオブサンプル効率:基準以上 |
そしてその数字の隣にある説明は、どうか文字どおりに読んでください:
とても小さい、あるいは負の分母は、診断全体をひっくり返します。インサンプルでもともと強くなかった戦略が、かえって「吐き出すものがなかった」せいで非常に高い「効率」を得てしまうのです。そこで 2 つの防御線があります:
チュートリアル用サンプル戦略 btc_sma_cross(BTCUSDT 1h、2022-01-01 から、計 1,720 日、SMA 45/100、パラメータは一字も変えず)。データは最初の段に入るので既定の期間 1095/30 が適用され、20 ラウンド(テスト期間は合計 600 日)に切れます。末尾の 25 日は 1 ラウンドに満たないため除外されました。
| 項目 | アウトオブサンプル(テスト期間をつないだもの、600 日) | インサンプル(20 ラウンドの学習期間をそれぞれ計算して平均) |
|---|---|---|
| Sharpe | −0.45 | 1.3471 |
| 年率リターン | −16.55% | +50.16% |
| 最大ドローダウン | −46.57% | — |
| 取引回数 | 183 | — |
アウトオブサンプル効率 WFE = −0.45 ÷ 1.3471 = −0.334 → 基準を大きく下回る
指摘する価値のあることが 3 つあります。第一に、除外されたラウンドはひとつもありません——20 ラウンドすべての学習期間の Sharpe が 0 を上回っており、分母は完全な 20 ラウンドの平均であって、選別後の残りではありません。
第二に、分母の 1.3471 は 0.25 をはるかに上回るため、2 つ目の防御線は作動せず、割り算は有効です:「WFE が負」と「WFE が判定不能」は別のことであり、前者は算出された結果、後者は回答の拒否です。
第三に、その 2 列がカバーする期間はもともと違います——インサンプルは互いに重なる 20 の学習期間の平均、アウトオブサンプルはその後の 600 日なので、きれいな同期間の対照ではありません。WFE が測ろうとしているのは、まさにこの落差そのものです。
同じ日、同じコードで、この戦略の MCPT の p 値は 0.0160(n = 2000)であり、標準出力も自ら significant edge at 95% と印字しています——掲載の品質基準に照らせば合格です。
| 検定 | それが問うている問い | 結果 |
|---|---|---|
| MCPT | この固定されたポジション系列の上で、この成績は実力と運を区別できるか? | p = 0.0160 → 合格 |
| Walk-forward | 過去データからパラメータを選ぶこと自体が、次の区間でも通用するか? | WFE = −0.334 → 基準を大きく下回る |
どちらも計算違いではありません。同じ問いに答えていないからです。これは、p 値がどれだけ美しくてもアウトオブサンプルを通ったことにはできない理由でもあります(〈MCPT の p 値の読み方〉参照)。ついでにはっきりさせておくと、これはこの戦略が壊れていると言っているのではありません——ワークスペースに付属するチュートリアル用サンプルであり、ここで示しているのは 2 つの検定の意味の違いです。
各ラウンドがパラメータ選択に使うのは 3×3 の近傍平均です(パラメータ探索と同じルール、つまり〈戦略の過剰最適化を避ける方法〉で述べたピークではなくプラトーを選ぶやり方)。しかしラウンド表で報告される学習 Sharpe は、選ばれたそのセル自身の数字です。これは意図的です:
| 分母に何を使うか | 結果 |
|---|---|
| そのセル自身の Sharpe(現行) | 分母が高めになり、WFE は保守的に出る |
| 3×3 の近傍平均 | 近傍平均は構造上、それが囲んでいるセルより必ず低くなる → 分母が押し下げられる → WFE が水増しされ、タブ全体が過度に楽観的に読めてしまう |
分母が水増しされた診断なら、やらないほうがましです。
2 ラウンドの境目で、系列が持っているのは新しいラウンド自身のポジションです——切り開かれているのであって、ゼロに戻されているのではありません。継ぎ目ごとに強制的に手仕舞いさせるのは、誰も取引していないエグジットを n−1 件でっち上げるのと同じです。
パラメータを変えるコストが漏れることもありません。継ぎ目でウェイトが変わり、価格評価の際に手数料がきちんと取られます。また、各ラウンドの数字は同じつなぎ合わせた系列から切り出したもので、価格を評価し直してはいないため、ラウンド表の合計は区間全体の総数とぴたりと一致します。
シグナルは全履歴の上で計算しますが(rolling の指標はそうでないと正しくならないため)、各学習スライスはそれぞれ自分の先頭のウォームアップ本数を飛ばします——最初のラウンドだけではありません。この手順がないと、ラウンド 1 は指標がまだ温まっていないバーで学習してノイズを拾い、各ラウンドの有効な長さも揃わず比較できなくなります。上のラウンド表がその実証です。戦略の START には 2022-01-01 と書かれていますが、ラウンド 1 の学習期間は 2022-01-05 からしか始まっていません——その数日の差こそが、WARMUP = 100 本の 1 時間足(約 4.2 日)が差し引かれた分です。
テスト期間は切り詰めません。すでに温まっており、しかもつなぎ合わせるためには連続していなければならないからです。ついでに、上級者からよく出る質問にも答えておきます:ここに embargo(隔離期間)は必要ありません——テスト期間はそのパラメータを選んだ学習期間のすぐ後ろに貼り付いており、それより後のデータはまったく使われていないからです。
走り終えても「推奨パラメータを適用」というボタンはなく、agent がこの結果を理由にあなたの戦略コードを書き換えることも許されていません。空の状態が最初から言い切っています:
なぜ写せないのか。その実行のパラメータのドリフトを見てください。20 ラウンドで選ばれた異なるパラメータは 4 通りだけです:
(45,100) ×14 → (55,80) → (45,100) → (45,80) ×3 → (35,80)
最初の 14 ラウンドは同じセルに留まっています。「たいていは 45/100 を選ぶ」が結論のように見えたとしても、あの −0.45 のアウトオブサンプル曲線は45/100 の成績ではありません——4 通りのパラメータがリレーして走った一続きの区間であり、そのどれにも属していないため、「採用」できるひと組は存在しません。適用を求めると、agent は決まった一文を返します:
パラメータのドリフト図は、各ラウンドがどのセルを選んだか、そのセルが何ラウンドで選ばれたかを描き、破線の枠が現在のパラメータを示します。凡例にも「最後のラウンドで選ばれたパラメータは参考であり、推奨値ではありません」と明記されています——その実行の最後のラウンドが選んだのは 35/80 ですが、それは「最後のラウンドの学習期間がたまたまこのセルに当たった」という意味しかありません。なお、このタブはp 値を表示せず、MCPT を走らせることも決してありません。walk-forward を 1 回走らせることは、agent の作業ルール上1 回のイテレーションに数えます。
ラウンド数は足りているか? 3 ラウンド未満はそもそも走りません。ラウンド数が少なすぎるとき、WFE はテスト期間 1 つか 2 つの運でしかありません。
除外されたラウンドはあるか? ラウンド明細に、どのラウンドの学習期間の Sharpe が ≤ 0 だったかが注記されます。上記の実行では 1 ラウンドも除外されていません。除外されるラウンドが多いほど、この戦略は自分の学習期間の中ですら何も選べていないことが多い、ということです。
WFE は「判定不能」か、それとも負の数か? 別物です。「判定不能」はインサンプル平均が 0.25 を下回り、この比に意味がないということ。負の数は割り算が行われ、アウトオブサンプルの区間が負けていたということです。
パラメータはどれくらい激しくドリフトしているか?「{n} ラウンドで {u} 通りのパラメータが選ばれました」の行を見てください。上記の実行は 20 ラウンドで 4 通りでした。毎ラウンドまったく違うセルへ飛ぶなら、選び直すたびに違うものを追いかけているのと同じです。
推奨パラメータを探していませんか? ありません。パラメータを変えるならパラメータ探索のロバストな点を使ってください。最後のラウンドを写すのではありません。
一度走らせてみて WFE がひどく落ち込むなら、問題はたいていアウトオブサンプルのこの手順ではなく、パラメータを選ぶ手順のほうにあります——それは〈戦略の過剰最適化を避ける方法〉の範囲です。検証する価値のある戦略がまだ手元にないなら、戦略ライブラリの公式戦略はどれも実際のバックテストと品質基準の結果が付いているので、まず数字を見てから決められます:戦略ライブラリ。