Excel VBAで競馬予想ツールを作った話|期待値の計算と、勝てなかった理由

「お金が勝手に増える仕組みを作れないか」。そんな考えから、Excel VBAで競馬のオッズを比較するツールを作ったことがあります。計算で有利に見える馬券を抽出する仕組みです。結果は、過去500レースの検証で回収率が約83%。勝てませんでした。でも、作ってみたからこそ、計算と予測の違いがよく見えました。

作りたかったのは、オッズの比較を自動化するツール

当時の私はITコンサルタントとして働いており、簡単な数学とプログラミングの知識がありました。一方、馬や騎手について詳しかったわけではありません。競馬の仕組みと数字を使えば、何か作れるのではないかと考えました。

構想は、単勝オッズをもとに各馬の勝つ確率を見積もり、その見積もりから馬単の確率を計算するというものです。馬単は、一着と二着の馬を着順まで当てる買い方です。計算した確率と、実際の馬単オッズを比べることを狙いました。

実際に馬券を購入して試したのではなく、過去のレース結果を使って検証しました。ここで紹介するのも、利益が出る方法ではなく、ツールの発想と、その限界を知った開発の話です。

Excelを選んだ理由

Excelなら、データを一覧で見ながら計算を確かめられます。さらにVBAを使えば、繰り返す処理や表への出力をプログラムにできます。機能の基本はMicrosoftのExcel VBAリファレンスでも確認できます。

当時の記事で使ったExcelのワークシート画面
データと計算結果を同じ表で確認できるExcelの画面。
ExcelのVBAエディターで短いプログラムを表示した画面
VBAエディターの説明用画面。競馬予想の処理全体を写したものではありません。

処理は、大きく二つです。レースのオッズを取り込むことと、取り込んだ数字から比較用の値を計算すること。最も難しかったのは、後者のうち「確率をどう見積もるか」でした。

四頭の例:単勝オッズから重みを作る

説明用に、単勝オッズが2倍、4倍、8倍、8倍の四頭を考えます。オッズの逆数を重みとすると、0.5、0.25、0.125、0.125になります。この例では合計がちょうど1なので、そのまま50%、25%、12.5%、12.5%という見積もりになります。

馬単勝オッズ逆数の重みこのモデルの一着確率
1番2倍0.550%
2番4倍0.2525%
3番8倍0.12512.5%
4番8倍0.12512.5%
単勝オッズ2倍・4倍・8倍・8倍から確率を見積もる図
単勝オッズの逆数を、この例のモデルの重みとして使った計算図。実際の勝率を測定したものではありません。

一般のデータでは逆数の合計が1になるとは限らないので、重みの合計で割って正規化する必要があります。たとえば重みがrで、全頭の合計がSなら、p=r÷Sです。ただし、合計を1に整えたからといって、市場のオッズから本当の勝率が分かったことにはなりません。

一着になった馬を除き、二着を見積もる

次に、1番が一着になった場合を考えます。このモデルでは、1番を除き、残った重みを比例配分し直します。残りの合計は0.5なので、2番は0.25÷0.5=50%、3番と4番はそれぞれ25%です。

1番が一着という条件で、残り三頭の二着確率を比例配分した図
1番を除いて残りの重みを配り直す計算。二着の強さも同じ重みで表せる、という仮定を置いています。

この考え方なら、「1番が一着で2番が二着」の確率は、0.5×0.5=0.25、つまり25%です。一般の組み合わせi→jでは、p(i)×p(j)÷(1−p(i))と計算します。ただしp(i)=1など、残りの確率がない場合はこの式で計算できません。

ここには、一着に関する重みを、ある馬が一着だった条件のもとで二着にも使えるという仮定があります。レースの展開や馬同士の関係を十分に表しているとは限りません。式が動くことと、その仮定が競馬に合うことは別です。

確率とオッズから、計算上の期待回収を求める

確率をp、払戻しの倍率をOとすると、単純化した期待回収倍率はp×Oです。確率25%、オッズ4倍なら0.25×4=1。100円を投じたとき、平均の払戻しは100円という計算になります。費用を引いた期待利益は0円です。

オッズ5倍なら、モデル上は0.25×5=1.25になります。でも、実際の確率が15%なら0.15×5=0.75で、結論は逆転します。有利かどうかを決めるのは、確率の見積もりがどれだけ合っているかです。

確率が低くても払戻しが大きければ、計算上の期待値は高くなり得ます。「利益を得る確率が、損をする確率より大きい」という意味ではありません。期待値については期待値と期待効用の記事でも整理しています。

500レースで試した結果は、回収率約83%

この仕組みを過去500レースで試すと、回収率は約83%でした。検証上の購入額を100とすれば戻りが83ということで、増える仕組みにはなりませんでした。

当時は、単勝オッズを勝率の代わりに扱ったことと、一着の重みから二着まで見積もったことが原因ではないかと考えました。ただ、結果だけで原因を一つに決めることはできません。データの扱い、抽出条件、取得時点、計算の境界条件も確認する必要があります。

JRAの馬券のルールでは、馬単の設定払戻率は75%です。しかし、私の検証の83%がそれを上回ったというだけで、ランダムな購入より安定して優れた予測ができたとは言えません。対象レースや購入方法をそろえた比較と、別のデータでの検証が必要です。

今なら、検証で何を確かめるか

  • 時点をそろえる。判断時に見られたオッズと、締め切り後の情報を混ぜない。
  • 条件を決めるデータと、評価するデータを分ける。結果を見ながら都合よく設定を変えない。
  • 回収率以外も見る。試行数、抽出数、的中率、一部の大きな払戻しへの偏りを確認する。
  • 計算だけを小さく検証する。確率の合計、組み合わせの重複、ゼロや空欄などを確認する。

これらは、当時すべて実施したという話ではなく、この経験から考える検証の工夫です。自動化すると大量に計算できますが、間違った前提も大量に繰り返せてしまいます。

別の入力を使う版と、開発で残った学び

その後は、各馬の勝率を入力し、馬連・馬単・三連複・三連単の比較用オッズを算出する版も作りました。それでも入力した確率や着順モデルが正しいかという問題は残ります。別の予測を入力すれば、必ず利益が出るというものではありません。

金の成る機械にはなりませんでしたが、思いつきを表とプログラムにし、結果を見て考え直す経験は得られました。私にとって、作る面白さはここにあります。計算を速くするだけでなく、その数字が何を意味するかを理解すること。これは、いまアプリの仕組みを考えるときにもつながる視点です。

ほかの制作については、プロフィールや開発ノートでも紹介しています。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です