今回やること

前回、冷蔵庫に食材を詰め込みました。数年分の株価CSV、あなたの戦略を検証するための「過去の相場そのもの」です。

今回はその冷蔵庫を開けて、料理を始めます。

やることはバックテスト。過去の相場データの上で、自分のルールどおりに売買していたら成績はどうだったか、をシミュレーションすることです。味見ならぬ答え合わせ。第2回で作った「わがまま→数字のルール」を、実際の相場にぶつけてみる。

ゴールは、あなたの戦略の成績表が、数字で目の前に出ること。

先に結果を言ってしまいます。最初に出た数字はPF2.38でした。AIに「超・優秀です!」と絶賛されました。でも私は喜びませんでした。良すぎたからです。

ここからPFが削られて「信用できる数字」に変わっていく過程が、今回の本題です。


冷蔵庫を開けて、レシピをAIに渡す

第2回の終わりに、こんな3条件が仮置きされていました。

  • 移動平均線からの乖離が◯%以下
  • RSIが30以下
  • 出来高が前日までの平均の1.5倍以上

この「わがまま→数字のルール」を、そのままAIに渡します。CSVの先頭数行をサンプルとして見せながら、こう頼みました。

SMA25 乖離率, RSI, 出来高を用いて逆張りの戦略を作ろうと思っている。長くても1か月以内での決済を目標として、システムトレードの案を組んでみてください。

AIにバックテストの条件を伝えた画面
AIにバックテストの条件を伝えた画面

第3回の環境構築やデータ取得と比べると、プロンプトの解像度が少し上がっています。「ナビゲートして」から「この指標でこういう戦略を組んで」へ。使う指標と時間軸を指定しているのは私ですが、具体的な数字はAIに提案させる。この距離感が「対等に話し合う」の実態です。


AIが返してきた「セリクラ狙いの極反発スイング戦略」

すると、AIが戦略にかっこいい名前まで付けて返してきました。

AIの戦略提案。名前まで付いてきた
AIの戦略提案。名前まで付いてきた

「セリング・クライマックス(セリクラ)狙いの極反発スイング戦略」——大げさな名前ですが、中身は至ってシンプルです。「売られすぎて、パニック売りで出来高が急増した銘柄を拾い、移動平均線に戻るまでの反発を取る」。第2回で書いた私のわがまま(勝率高め・薄利OK・短期)を、そのまま形にしたもの。

AIが提案してきた初期条件は、乖離率-10%以下、RSI25以下、出来高は25日平均の2倍以上。第2回で「うろ覚え」として出した数字と微妙に違いますが、そんなものです。AIは毎回少しずつ異なる数字を出してきます。大事なのは数字そのものではなく、「これでいいか確かめる」プロセスのほうです。

エグジット条件も一式出てきました。SMA25タッチで利確、-5%で損切り、20営業日で時間切れ。これも後で変わりますが、最初の一歩としてはこれで十分。

そして、「バックテストのコードを書こうか?」と聞いてきます。もちろん、お願いします。

そのやり方でいいと思います。データは確か4年分くらいあったと思うので十分だと思います。このデータを使ってバックテストで成績を出してみたいです!良さげな感じだったら改善していってもっといい感じにすればいいと思います。なのでそれらを実現するコードをくれますか?

このプロンプト、読み返すとだいぶ雑です。「良さげな感じだったら改善」「もっといい感じに」。ですが、手法を構築する最初の段階では、これくらいのノリでいいと私は思っています。最初から細かいパラメータを詰めようとすると、「正しい数字はいくつだろう」と考え込んで動けなくなる。まずは雑に投げて、結果を見て、そこから自然に厳密になっていく。実際にこのあと私は、自分でも気づかないうちに数字を少しずつ調整し始めました。最初の雑さは、動き出すための燃料です。

AIが返したバックテストコード
AIが返したバックテストコード

もう何度も繰り返しているのでお分かりだと思いますが、このコードの中身を私は読んでいません。コピーボタンを押して、VS Codeに貼って、ファイル名を付けて保存。前回と全く同じ作業です。


動かす。止まる。貼る。直る。

貼って実行。すぐにエラーが出ます。

VS Codeでエラー発生
VS Codeでエラー発生

前回と同じです。赤い文字を読まず、コピーしてAIに貼る。

エラーをAIに報告
エラーをAIに報告

AIが修正案を出す。貼って直す。今回のエラーは3往復で突破できました。前回(データ取得)の5往復より少ない。前回のコツ——データをローカルに全部置いておく——が効いています。通信エラーが起きる余地がないので、詰まるとしたらコードの中身だけ。実感として、かなりの時短です。

ただし実行してみると、ターミナルが黄色い文字を出して画面が止まったように見えました。「これ……フリーズした?」と不安になって、AIに聞きます。

「これ正常に動いてる?」とAIに確認
「これ正常に動いてる?」とAIに確認

答えは「それはWarning(警告)であってError(エラー)ではありません。今この瞬間も裏で計算中です。安心してください」。なるほど。前回の「エラーは読まなくていい」に加えて、今回は「止まったように見えても動いている」を学びました。脳が勝手に2割学んだ、の続きです。

正常に計算が進んでいるターミナル
正常に計算が進んでいるターミナル

4年分のデータを全銘柄で回すので、それなりに時間がかかります。数分待つと——

バックテスト完走
バックテスト完走

ターミナルに結果が出ました。決済理由の内訳まで表示されています。フォルダにはbacktest_results.csvが生まれています。

結果ファイルが生成された
結果ファイルが生成された

4年間のすべてのシグナル、すべての売買、すべての損益が、1つのCSVファイルに記録されたということです。


「PFとか出さないとまずいのでは?」

ここで、AIに結果のCSVを渡して分析を頼みました。

結果CSVをAIに報告
結果CSVをAIに報告

AIはCSVの中身を断片的に読んで、「V字回復で利確できている美しいトレードがある」「落ちるナイフを掴んでいるケースもある」と定性的なコメントを返してきました。

ここ、結構大事な場面です。AIの分析は、それ単体では間違っていません。でも、これだけ見て「じゃあ落ちるナイフのパターンを減らせばもっと良くなりそうだ」と素直に従ってしまう人がいるかもしれない。定量的な裏付けがないまま、AIの定性コメントに乗っかってしまう——技術面だけでなく判断までAIに丸投げすると、こういうことが起きます。

この連載をここまで読んでくださっている方なら、相場の経験がある方のはずです。そういう人なら、この場面で「いや、まず数字を出してからでしょ」と立ち止まれる。あなたの投資経験は、AIの前でも機能する。

実際、私はここで突っ込みました。

PFとか期待値とかいろいろ評価をするための数字を出さないとまずいのでは?結果のcsvはあるわけだからここからそういうのをpythonで計算すればいいんでないの?それでよさそうならコードをください。

「PFを計算するコードをくれ」と要求
「PFを計算するコードをくれ」と要求

プログラミングの知識はゼロでも、投資の世界で「数字で評価しないと意味がない」ことは知っている。これが暗黙知です。AIが見落としたわけではありません(聞けば当然出してきます)。ただ、聞くべきことを知っていたのは人間の側だった。技術はAIに任せる、戦略は対等に話し合う。このテーゼが、この1往復に凝縮されています。

AIは「その認識は完全に正しい」と認め、評価用のPythonコードを出してきました。またコピペして、実行。


PF2.38が出た

評価コードの実行結果。PF2.383
評価コードの実行結果。PF2.383

ターミナルに出た数字がこれです。

プロフィットファクター (PF) : 2.383
勝率                        : 62.31%
期待値 (1トレードあたり)    : 4.005%
総トレード数                : 7,217回

PF2.38。勝率62%。期待値4%。トレード数7,000回超。

この数字をAIに投げると——

AIの評価「超・優秀」
AIの評価「超・優秀」

「文句なしの超・優秀なシステムです!」「4年間で7,217回という膨大な試行回数を経ているため、カーブフィッティングの可能性は極めて低い」「打ち出の小槌レベル」——

AIはそう言っています。

——ちょっと待ってくれ。

PF2.38。勝率62%。1トレードの期待値4%。「打ち出の小槌レベル」。いきなりメッシが出てきたような数字です。そんなわけないだろう、という感覚のほうが先に立ちました。

これは何年も相場にいれば分かる感覚だと思います。「初めて組んだシステムで超・優秀」なんて、話がうますぎる。もしこの数字を素直に信じて実運用していたら、どこかで痛い目を見る。PF1.5以上あれば検討に値するという温度感で生きてきた人間にとって、2.38は嬉しい数字ではなく、怖い数字です。

正直に書くと、実際に初めてこの作業をやった4ヶ月前は、PFが4を超えていた記憶すらあります。さすがにそれはおかしい。当時の私でも即座に気づきました。


ここからPFが「正直」になっていく

4ヶ月前の記憶なので正確な順序は曖昧ですが、ここから先の大筋は確かです。初手の「すごい数字」が、現実の制約を入れるたびに削られていった。

まずやったのはセカンドオピニオンです。1つ目のAIが絶賛してくれた数字を、別のAIに見せた。すると別のAIは、もう少し冷静にいくつかの問題を指摘してきます。

当初のデータセットにはETF(指標連動型の銘柄)が混ざっていました。ETFは個別株とは値動きの性質が違うのに、同じ条件でスクリーニングしていた。これを除外したらPFが変わる。

次に見つかったのが、特定の期間が異常にPFを押し上げていた問題です。2024年の植田ショック、2025年のトランプ関税ショック——暴落相場では逆張りのシグナルが大量に出て、リバウンドも強烈になる。この期間だけでとんでもない利益が積み上がっていて、全体のPFを歪めていました。

「じゃあその期間を除外して、平時だけのPFはどうなる?」

下がります。

さらに、AIが次々と細かい指摘を入れてきます。約定時のスリッページ(注文と実際の価格のズレ)。急激なギャップダウンで損切りラインを飛び越えるケース。資金の制約は難しすぎるから一旦棚上げしたものの、概念としては理解しておく必要がある——。

指摘が入るたびに、PFは少しずつ削られていきました。

これを2週間ほど、ひたすら繰り返しました。AIに指摘される→コードを直す→回す→別の問題が見つかる→またAIに聞く。作業量は相当なものでしたが、AIと組んでいるのでスピードはとんでもなく速い。

ちなみにこの2週間、バックテストを回しながら実際にこの手法で取引もしていました。第2回の取引ログで見せた、JDSC(+152,000円)やサン電子(+130,000円)はまさにこの期間中の成果です。システムはまだ完成していないのにシグナルだけ先に出して、手動で買い付けていた。せっかちです。でも、実弾を入れながら検証を回すことで、「机上の数字」と「手元の損益」が同時に動く感覚があった。この並行作業が、2週間で仕上げるスピード感に繋がっていたと思います。


【コラム】雑に10倍回す——学びの密度とスピードの話

第3回で「脳が勝手に2割学習していた」と書きました。あの話の続きをします。

バックテストの2週間、私がやっていたのは「丁寧にコードを読む」ではなく「ひたすら回数を回す」でした。

考え方はこうです。1回のバックテストを丁寧にレビューして学び100%にするより、雑でいいから10回回して、1回あたりの学びが20%でも、掛け算すると実質2倍になる。理解の密度は薄い。でも総量で勝てる。

だから基本は結果が出るまではザックリでした。コードの中身は読まない。エラーはコピペ。AIの説明も、腑に落ちるまで読み込まずに次へ進む。

ただし、いい結果が出たときだけ立ち止まる。PFが改善した、勝率が上がった、何か面白い数字が出た——そういう「引っかかり」があったときだけ、手を止めて検証する。AIにセカンドオピニオンを求める。コードの該当箇所を説明してもらう。数字に違和感があったら、その違和感を大事にして慎重に確かめる。

結果が出るまでは雑に、結果が出たら丁寧に。このメリハリが、2週間で仕様書まで到達できた理由のひとつだったと思います。


PF1.5——「削られたのに、まだこれだけ残ってる」

2週間の試行錯誤の結果は、1枚の仕様書にまとまりました。三者(私・Claude・Gemini)で合意した運用プロトコル。エントリー条件、エグジット条件、定性フィルター、日次バッチの処理フロー。すべてが確定値で書かれている。

仕様書のバックテスト確定値。暴落除外期間を適用してPF1.69
仕様書のバックテスト確定値。暴落除外期間を適用してPF1.69

この仕様書は、AIに作らせました。作業がとんでもないスピードで回るので、自分の頭が追いつかなくなるんです。「今どういう状態なんだっけ」が分からなくなる。だから適宜、それまでの議論と決定事項をAIにまとめさせて、ドキュメントとしてストックしていく。思い出したくなったら、そのまとめをAIに投げて解説してもらう。これは結構使えるコツで、私は今でも多用しています。

仕様書に記載されたPFは1.69。暴落期間を除外した確定値です。

そしてさらに厳しい条件で検証すると、PFは1.5前後まで落ちました。

最初のPF2.38から見ると、かなり削られています。PF4超の記憶(曖昧ですが)から見れば、3分の1以下。

でも、このときの感覚はネガティブではなかったんです

むしろ逆でした。「これだけ厳しく制約を入れていったのに、まだ1.5残ってる」。

しかもこのバックテストには、定性フィルター(業績悪化やTOB進行中の銘柄を弾く処理)が一切入っていません。本来なら絶対に買ってはいけない銘柄まで全部買い付けた前提で、この数字。定性フィルターで地雷を弾けば、もう少し良くなるはずです。

「……いける。」

この確信が生まれた瞬間が、PF2.38が出た瞬間ではなく、PF1.5が出た瞬間だったというのが、この回のオチです。

最初の「すごい数字」は夢でした。正確には、現実の制約を織り込んでいない「まだ正直ではない数字」。それが指摘のたびに正直になっていき、正直になり切った数字がPF1.5。削られたのではなく、本当の実力が見えた。

第2回で「あれ?こんなもんなの?」と書いた感覚。あれは「期待が裏切られた」のではなく、「正直な数字を受け入れた」瞬間だったんだと、今なら思います。


データ期間の話——なぜ4年前後か

第3回の予告を回収しておきます。

バックテストのデータ期間を「4年前後」とした理由は、2つあります。

短すぎると、局面が偏る。たとえば2年分のデータがたまたま上げ相場だけだった場合、逆張り戦略のシグナルがほとんど出ません。暴落が来たときにシステムがどう振る舞うかが検証できないまま本番を迎えることになる。それは怖い。

長すぎると、昔の相場は別のゲーム。10年前の市場環境は、アルゴリズム取引の普及度も、参加者の構成も、規制も今とは違います。古すぎるデータで最適化しても、その「最適」は今の相場に通用しない可能性がある。

4年前後なら、上げも下げもショックもある程度含まれ、かつ市場環境が今と大きく乖離していない。完璧な期間はありませんが、バランスとしてはここが落としどころです。

ただ、先ほど書いたとおり、暴落期間(植田ショック・トランプ関税ショック)はPFを歪めるので、込みと除外の両方で検証するのがポイントです。私の仕様書では暴落除外のPFを確定値として採用しつつ、暴落込みの数字も把握しています。


今回のまとめ

  1. バックテストは「過去データで答え合わせ」。AIにコードをもらい、コピペで実行するだけ
  2. 最初に出る数字は良すぎることがある。セカンドオピニオンと、自分の違和感を大事に
  3. 数字は制約を入れるたびに「正直」になる。削られることは悪いことではない
  4. 「雑に10倍回す→いい結果が出たら立ち止まって検証」のメリハリで進む
  5. データ期間は4年前後がバランス。暴落込みと除外の両方を見る

ここまでが「戦略を作って、検証して、数字を確認する」の一連の流れです。PF1.5で「いける」と確信した——と書くと順調に聞こえますが、実はこの裏で、私は他の手法もいくつか試しています。

高値ブレイクの順張り。ペアトレード、つまり統計的アービトラージ。名前だけは聞いたことのある、夢のある戦略たち。

全部、死にました。

次回はその話をします。夢の戦略が過去データの上で先に死んでくれることの、ありがたさについて。


次回・第5回:夢の戦略は机の上で死んでくれる——高値ブレイクとペアトレード(統計的アービトラージ)が教えてくれたこと


免責事項:本記事は筆者の実体験に基づく情報提供を目的としたものであり、特定の銘柄・手法・サービスへの投資や購入を推奨するものではありません。過去の検証結果は将来の成果を保証しません。記載のPF・期待値等はバックテスト上の参考値であり、実運用の成績を約束するものではありません。投資判断はご自身の責任でお願いします。