見出し画像

【コード公開】競馬馬券の最適化を考える。〜利益を最大化させる馬券購入方法〜


こんにちは。
競馬ばびぃです。

この記事では、競馬AI が予測した結果をもとに、利益を最大化するための馬券購入法を考えてみたいと思います。

競馬AI のコードは、以下の記事で全公開しています。
誰でもAIを動かせるようになるので、ぜひご覧ください。


更新情報

・24.04.07 記事を公開しました。

・予定:オッズの数値を事前に予想するプログラム→これによって、レース前日などに購入金額を決めることができます(ぜひ フォロー & いいね をしてお待ちください!)


はじめに

競馬では、着内に入る馬を予想することと同じくらい、どんな馬券を、どういった金額配分で購入するかが、収支において重要になります。

「予想は当たったのに、収支はマイナスになってしまった…。」
「割と穴馬を当てたと思ったのに、プラスでみるとこんなものか…。」

競馬を楽しむほとんどの人が、一度は経験したことがあるでしょう。

当たる確率の高い馬券に金額をかけるのか、オッズが高く、より大きな配当が期待できるものに金額をかけるのか。
例え軸馬の予想が当たっても、ここでの判断によって収支は大きく変わってきます。

予測結果に基づいて、利益とリスクのバランスを適切に考慮した馬券購入を行うことができた時、利益を最大化することができるはずです。


馬券購入最適化

予算を適切に分配し、利益を最大化するためには、何をどのように考えたら良いでしょうか?

条件を整理しましょう。

・オッズの異なる複数の馬券を購入する。
・利益が最大になるように、予算金額を分配する。

これをみると、株の分散投資とほとんど同じであることがわかります。
株の投資は、

・収益率の異なる株を複数購入する。
・リスクを分散し利益を最大化するために、資産を分配する。

投資の世界には、どの株をどういった比率で保有しているかを表す「ポートフォリオ」という言葉があり、その最適化を考える有名な「ポートフォリオ最適化問題」というものがあります。

この最適化問題を競馬の馬券バージョンに置き換えて考えれば、うまくいくのではないでしょうか。

「収益率の異なる投資先(馬券)に、手持ちの資産(賭け金)を、適切に分散投資(馬券の購入)する」 といった感じに置き換えると、全く違和感がありません。


ポートフォリオの最適化手法

以下の論文で紹介されている「Sharpe Strategy」をというものを使って、最適化を考えます。
Optimal sports betting strategies in practice: an experimental review

最適化手法の詳しい説明は、結構難しい感じになるので、すっ飛ばしてしまいますが、簡単にいうとこんな感じです。

① どの馬券にいくら賭けるかという戦略を、最適化パラメータに設定する。
② その馬券が的中する確率と、その馬券のオッズから、戦略のパラメータを決定していく。

Pythonの線形計画問題の最適化記述ライブラリであるscipy.optimizeを使って実装していきます。


コード

まず、必要なライブラリをインストールします。
numpyやpandasはもちろん、scipyも事前にインストールしておきます。

pip install scipy

いつもと同様、以下のコードをコピペして実行しましょう。
コピペが面倒な方のために、ダウンロードファイルも置いておきます。

◆ bet_optimization.ipynb

import numpy as np
import pandas as pd
import scipy.optimize as sco
from IPython.display import display

# オッズ、的中確率、馬券の名前を定義
odds = np.array([5.0, 10.0, 20.0])  # 3つの馬券のオッズを入力
pred = np.array([0.2, 0.1, 0.05])  # 馬券の的中確率を入力
index = ["馬券A", "馬券B", "馬券C"]  # 馬券の名前を入力

def sharpe_optimize(odds, pred, index, budget=1000): # Sharpe Strategyによる最適化を行う
    def problem_func(weights, odds_matrix, pred):
        """目的関数"""
        return -(pred * np.dot(odds_matrix, weights)).mean() / np.sqrt(np.cov(np.dot(odds_matrix, weights)))

    odds_matrix = np.concatenate((np.diag(odds), np.ones((len(odds), 1))), axis=1) - 1
    odds = np.concatenate((odds, np.ones(1)), axis=0)
    # 初期解
    x0 = np.ones(len(odds)) / len(odds)

    # 制約条件
    constraints = [{"type": "eq", "fun": lambda x: np.sum(x) - 1}]

    # 上下制約
    bounds = [(0, None)] * len(odds)

    # 最適化
    opts = sco.minimize(fun=problem_func, x0=x0, args=(odds_matrix, pred), method="SLSQP", bounds=bounds, constraints=constraints)
    
    # 表示用のデータフレームを作成
    df = pd.DataFrame([], index=list(index) + ["Not bet"])
    pred = np.concatenate((pred, np.ones(1)), axis=0)
    df["odds"] = odds  # オッズ
    df["pred"] = pred  # 馬券的中確率
    df["fraction"] = opts["x"]  # 最適化によって得られた投資配分
    df["bet"] = np.round(opts["x"] * budget / 100) * 100  # 購入馬券の金額
    df["return"] = df["bet"] * odds  # 払い戻し金額
    
    return opts["success"], df

# 関数の呼び出しと結果の表示
success, df = sharpe_optimize(odds, pred, index, budget=1000)
if success:
    print("最適化に成功しました。")
    display(df)
else:
    print("最適化に失敗しました。")

※ 以下の部分を、実際のレース情報などに合わせて変更してから実行します。

# オッズ、的中確率、馬券の名前を定義
odds = np.array([5.0, 10.0, 20.0])  # 3つの馬券のオッズを入力
pred = np.array([0.2, 0.1, 0.05])  # 馬券の的中確率を入力
index = ["馬券A", "馬券B", "馬券C"]  # 馬券の名前を入力

的中確率は予測結果の値で代替するか、値を参考にしながら自分で設定してください。


◆ 実行結果
コードを実行すると、以下のように表示されます。

bet の欄が馬券ごとに最適化された金額

予算1000円、オッズが 馬券Aが5.0、馬券Bが10.0、馬券Cが20.0 の場合

馬券A:600円
馬券B:300円
馬券C:100円

このように金額を配分して購入するのが、最も適しているという結果になりました。


ここで大きな問題になってくるのは、オッズでしょう。
数値として確定する最終オッズは、レースの数分前までわかりません。
しかも、レース直前まで大きく変わっていくので厄介です。

馬ごとの最終オッズを事前にある程度予測することができれば、レース前日などに賭け金を最適化して馬券を購入することができます。

最終オッズ予測プログラムを近いうちに追記したいと思いますので、今しばらくお待ちください。


競馬AI について

冒頭で紹介した通り、競馬AI のコードを全公開しています。

コードをコピペするだけで、簡単に競馬AIを使って予想ができるようになります。(ダウンロードファイルも用意しています。)

また、自分の予想ロジックなどを加えながら自由にコードを変えていき、オリジナルの競馬AIに育てていくことができるよう想定しています。

一部有料にはなりますが、自信を持ってお届けしておりますので、ぜひぜひご覧ください!


この記事が参加している募集

自己紹介

この記事が気に入ったらサポートをしてみませんか?