私のモデルは明日の新聞を読んでいた
しばらくの間、私のあるモデルは天才のように見えた。そのバックテストはクリーンで、自信に満ち、ほとんど滑らかすぎるほどだった。私はついに本当に機能するものを作り上げたのだと信じたかった。
それは、残しておく価値のあるものを何ひとつ学んではいなかった。学んでいたのはズルをすることだった——ひっそりと、私自身が作り込んだリークを通じて、過去に何をすべきかを決める前に未来からの情報を読み取れるようにしてしまっていたのだ。
出来すぎた生徒
期待より少しだけ良い成績を出すモデルはワクワクさせる。本来あり得るはずもないほど大幅に良い成績を出すモデルは、あなたを震え上がらせるべきだ。私のものは後者だった——本物の市場がギザギザなところで滑らかで、不確かであるべきところで自信に満ちていた。
以前の投稿で、最も危険な結果はあなたを喜ばせる結果だと書いた。これはその教訓が、より微妙な装いをまとって再び現れたものだった。今回は数字が不条理だったわけではない——ただ出来すぎていただけだ。そして「出来すぎ」はそれ自体が一種の危険信号だ。なぜなら市場における本物のエッジは小さく、ノイズに満ち、苦労して得られるものだからだ。市場を解き明かしたかのように見えるモデルは、ほぼ必ず、その代わりにあなたのシミュレーションの裂け目を見つけ出しているのだ。
未来はどこから入り込んだか
その裂け目は正規化にあった——モデルが学習できるように生の入力を再スケールする、地味な工程だ。正規化には統計量が必要だ——中心、ばらつき。そして私はそれらの統計量をデータセット全体に対して一度に計算していた。
そのたった一つの選択こそ、未来が漏れ込んだ場所だ。全履歴にわたって統計量を計算し、それを過去のある時点に適用すると、その過去の瞬間における「正規化済み」のあらゆる値が、まだ起きていないデータについての情報をひっそりと埋め込んでしまう。モデルは、ある任意の瞬間を見ているとき、暗黙のうちにタイムライン全体——その未来を含めて——の形について何かを教えられていたのだ。モデルが明日の価格を直接見ることは一度もなかった。その必要はなかった。明日が混ぜ込まれた空気を吸っていたのだから。
なぜ先読みはこんなにも簡単に作り込めるのか
先読みバイアスを危険にしているのは、それを作り出すのが難しいことではない。むしろ、ごく普通の前処理を通じてするりと忍び込んでくることだ。コードを書く最も自然で読みやすい方法——スケーラーをデータにフィットさせ、それからデータを変換する——は、時系列に対してはすでに間違っているのに、何も文句を言わない。例外は投げられない。テストが赤くなることもない。数字は完全に妥当に見える。唯一の症状は、モデルが本来あるべき以上に優れていることだ。そしてそれは、あなたが最も調べる気になれない、ただ一つの症状なのだ。
それがリークの罠だ。それはバグのようには見えない。成功のように見えるのだ。
兆候——ここでは輝き、外では死んでいる
ただ一つ、それ自体が証拠ではないものの、よく表れる特徴がある。先読みに汚染されたモデルは、自分が調整された相手であるデータの上では輝き、覗き見できないデータに出会った瞬間に崩れ落ちる傾向がある。インサンプルでの栄光とアウトオブサンプルでの崩壊との間の大きな隔たりは、リークの警告サインだ——ただし、それは過学習や、レジームの変化、あるいは過小評価したコストからも生じうる。私の場合、犯人はリークだった。
だから本当に重要だったテストは、決して「バックテストはどれだけ良いか?」ではなかった。それは「シミュレーションを正直にしたとき、どれだけ悪くなるか?」だった。リークを塞ぐと、パフォーマンスは下がった——そしてその下落は、痛みを伴うものではあったが、システムがそれまでに私に見せてくれた中で初めて信頼できる数字だった。
修正——まだ知り得なかったものは決して使わない
その修復は一行のコードではなく、一つの原則だ。シミュレーションのどの瞬間においても、モデルはその瞬間かそれ以前に存在していた情報だけを使ってよい。正規化について言えば、それは統計量を過去のトレーリングウィンドウから導くことを意味する——ある時点までに利用可能だったものにフィットさせ、決してタイムライン全体に対してはフィットさせず、未来の一点に対しても決してフィットさせない。
それは遅い。それは面倒だ。それはより見栄えの悪いバックテストを生む。これら三つはすべて、コストではなく特徴だ。なぜならそのどれもが、モデルにタイムトラベルを許すまいとするシミュレーションそのものだからだ。正直なパイプラインは見かけ上のパフォーマンスという税を払う。そしてその税こそが、実際に信頼できる数字の代価なのだ。
リークは単一のバグではなく、一族だ
これを修正する上で最も難しかったのは正規化処理そのものではなかった。それは、正規化処理が一つの扉にすぎず、未来は多くの扉から入り込みうるのだと気づくことだった。同じ過ちは、ラベルの作り方の中に、系列全体をこっそり要約してしまう特徴量の中に、過去と未来を一緒に触れるあらゆる前処理工程の中に潜んでいる。一つのリークを塞いでも、リークを塞いだことにはならない。それがどんな見た目をしているかを学んだだけであり、だからこそ残りを探しに行けるのだ。
私は先読みを、修正すべきバグとして考えるのをやめ、監査すべき性質として扱い始めた——いまや意図的に狩りに出るものとして。もし結果があまりにクリーンに見えるなら、未来が私のまだ確認していないどこかから入り込んでいる、という前提のもとで。
なぜバックテストはズルに報いるのか
これらすべての根底には、バックテストについての居心地の悪い真実がある。バックテストは、技量と後知恵を区別できないのだ。バックテストは、本当に市場を先読みするモデルと、ひっそり解答集を読んでいるモデルとに、まったく同じ額を支払う。どちらも美しい曲線を生む。厳密に前向きで、未知のデータこそが、両者を分け始めるより強いテストだ——もっとも、それすらも単独では、パイプラインがリークなしであることを証明できはしない。
だからこそ「バックテストでうまくいった」は、調査の終わりではなく始まりなのだ。見栄えの良いエクイティ曲線は一つの問いである。このモデルはこれを稼ぎ取ったのか、それとも私がうっかりズルを許してしまったのか? 正直な研究という営み全体は、市場があなたにその問いを突きつける前に、自分でその問いを問うことを学ぶ、ただそれだけのことなのだ。
明日の新聞を読んでいるモデルは、いつだって天才のように見えるだろう。その天才性はあなたのものであって、モデルのものではない——そしてそれは、あなたが塞ぎ忘れたリークの中に丸ごと宿っているのだ。
— シグナルなし、リターンなし、投資助言ではない。