バックテストで勝っていたのに、実運用では勝てない。原因の一つは「未来を見たつもりはない」検証にも情報が漏れていることだ。特に数日保有する売買を日次データで学習する場合、訓練に使った取引の損益確定日が、検証期間に食い込む。日付を例に、パージ(重なりの除去)とエンバーゴ(検証期間の直後に設ける空白)を整理する。
シグナル日と結果確定日は別の日
各営業日の終値で買いシグナルを作り、5営業日後の収益がプラスかを予測するとしよう。9月1日のシグナルの答えは9月8日頃に確定する。検証期間が9月7日に始まるのに、この9月1日の取引を「訓練期間は9月6日までだから安全」として残すと、訓練ラベルが検証期間の価格を使う。モデルは検証期間の一部を答えとして見てしまう。

パージとは、検証期間と情報利用区間が重なる訓練標本を除く処理だ。単純に「検証開始前の5日間を捨てる」でも固定5日保有なら近似できる。ただし損切りや利確で終了日が変わる手法では、標本ごとの開始時刻と終了時刻を記録し、重なったものを個別に除く方が正確だ。
エンバーゴはいつ必要か
時系列を過去から未来へ一方向に分ける単純なウォークフォワードなら、検証後のデータをその検証の訓練にはそもそも入れない。したがって「必ずエンバーゴが必要」ではない。一方、複数の時期を交互に検証ブロックへ取り、検証ブロックより後の期間も訓練に使う交差検証では、検証直後の標本の特徴量が検証期間の移動平均などを含み得る。境界直後を一定期間空けるのがエンバーゴの考え方だ。

たとえば特徴量に20日移動平均を使い、検証が9月7~18日、9月21日からの標本を再び訓練に使うなら、9月21日の移動平均は検証期間の価格を含む。後方の訓練標本をそのまま残さず、特徴量が検証区間に触れなくなるまで空白を置く。ただしエンバーゴを何日にするかは、特徴量の窓、ラベルの保有期間、検証目的で変わる。「常に一律5日」ではない。
実装の順序を固定する
まず各行に、シグナルを観測した時点、特徴量が参照する最も古い時点、結果確定時点を付ける。次に検証ブロックを決め、重なりを持つ訓練行を除外する。訓練と検証が確定してから、標準化、欠損値補完、外れ値の閾値、特徴量選択を訓練データだけで学習し、同じ変換を検証側に適用する。全期間の平均と標準偏差で先に正規化すれば、パージをしても情報漏れは残る。
株式の例では、決算発表の時刻、指数構成銘柄の変更時刻、配当修正の公表時刻も確認する。「決算日のデータ」でも、場が閉じた後に公表された数値を当日の引けで取引できたように扱えば先読みになる。約定コスト、スリッページ、現実の発注可能時刻は別途検証する。
小さな検証設計例
2018~2021年でパラメータ候補を作り、2022年を検証、2023年以降を完全な最終確認用に確保する。2022年を何度も見てルールを変えれば、それはもう純粋な未知データではない。検証を繰り返す際は、各回の訓練時点で知り得た銘柄・価格・財務データだけを復元し、パージした行数もログに残す。行数が大幅に減った場合は、精度の数値だけでなく不確実性も増える。
「パージとエンバーゴを入れたから本番でも勝つ」とは言えない。しかし、それをしないバックテストは、性能を測る物差し自体が歪みかねない。未来価格が訓練ラベルや前処理へ入り込む経路を一つずつ塞ぐことが、売買ルールの評価の出発点になる。
境界の重複を機械的に判定する
各標本を「情報を使い始めた日時」から「答えが確定した日時」までの区間として表す。検証ブロックを9月7日から9月18日とすると、訓練標本の区間がこの期間と1日でも重なれば、原則として除外候補になる。9月1日の買い判断の損益が9月8日に確定するなら重複する。9月1日に判断し9月4日に手仕舞った標本なら重複しない。ただし、説明変数に将来のデータが含まれていないことも別に点検する。
この区間を記録せず、単純な行番号で5行空ける実装は危うい。祝日や売買停止で5行と5営業日がずれたり、同一日に複数銘柄の標本が並んだりするからだ。時刻付きの元データで開始・終了を保存し、時系列順に分割した後、境界をまたぐ行数を毎回監査する。訓練行がほとんど消えるなら保有期間に対してデータが短すぎる可能性もある。
最終確認用の期間は、途中のモデル選択にも使わない。「2023年の成績が悪いから説明変数を一つ追加した」と決めた時点で、2023年は検証に利用したことになる。再び未知期間として扱わず、次の未使用期間を待つか、成績推定の不確実性を明記する。手法の良し悪し以前に、データの使い方が検証結果を左右する。


コメント