0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AIは賭けに勝てるか【検証編】——6万試合の実データ、ポーカーAI、本物のLLMで勝因と敗因を分解する

0
Posted at

「AIは賭けに勝てるか」というテーマで、理論編を2本公開しました。

理論編では、先行研究と公的資料をもとに、次のような主張をしました。

  • 勝敗はAIの賢さより先に「誰を相手にするか」で決まる。
  • 市場並みの予測精度では、控除率の分だけ負ける。
  • 実力の証明には数万回の賭けが要る。
  • 勝つ客は胴元に制限される。

本記事は、その検証編です。8つの実験をPythonで実装し、AIを実際にさまざまな相手と戦わせました。損益、勝率、期待値を測り、勝因と敗因を分解しています。

  • 実データ:欧州サッカー約6万試合のオッズと、米国株100年分の日次リターン
  • 本物のAI:Anthropic API 経由の Claude Haiku 5.5
  • シミュレーション:真の確率がわかるルーレット、ポーカー、競馬、口座制限

コードはすべて GitHub で公開しています。

本記事は、賭け事や投資・トレードを推奨するものでも、否定するものでもありません。掲載した数値は仕組みを確かめるための検証結果であり、賭けや投資に関する助言ではありません。日本では、法律で認められたものを除き、お金を賭ける行為は原則として賭博罪の対象となります。

この記事でわかること

相手 検証の結果
数学(ルーレット) 同じ学習AIが、認証された乱数には理論どおり負け(ROI −2.6%)、欠陥のある乱数には勝った(+6.0%、+2,265%)。勝因は相手の欠陥
人(ポーカー) CFRで学習した均衡AIは、慎重な相手からはほぼ稼げない。癖を突くAIの利益の大半は、相手の2〜4個の判断ミスから来る
胴元・市場(サッカー実データ) 機械学習モデルは市場より不正確。モデルが見込んだ期待値 +22% に対し、実際のROIは −12%(約2万回)
胴元(口座制限) 優位の証明に約1万回かかる客を、胴元は数十回で制限する(模擬)
市場(競馬・控除率20%) 最強のAIでも情報優位は 0.021 ナッツで、必要な 0.223 ナッツの1割未満
市場(米国株) 機械学習のシグナルは片道0.1%のコストで負けに転じ、2000年以降はコスト前でも消えた
本物のLLM 予測は市場より不正確(log-loss で +0.042 ナッツ)。同じ質問を2回すると、8割の試合で答えが変わった

相手別のROIと95%信頼区間

検証の設計

相手の分類と「勝てる」の3つの水準

理論編と同じく、相手を次の5種類に分けます。

相手 例 期待値を決めるもの
数学 宝くじ、スロット、ルーレット 乱数と固定の控除
人 ポーカー、麻雀 対戦相手との判断の質の差
胴元 ブックメーカー 胴元が付ける価格(マージン込み)
市場 競馬、取引所、株価 参加者の判断を集約した価格と、控除・手数料
リスクプレミアム 株式の長期保有 リスクを負う対価

「勝てる」も、次の3つの水準に分けて測ります。

  • 期待値:期待値や期待成長率がプラスか。
  • 検証:優位を偶然と区別できるだけの標本があるか。
  • 執行:想定した価格で約定し、継続できるか。

8つの実験

研究 相手 データ 「AI」
1 数学:ルーレット・スロット 模擬 出目を学習するモデル(頻度、2次マルコフ)
2 人:ポーカー・麻雀 厳密計算・模擬 CFRの均衡戦略、最善応答、プレイ中に学ぶ搾取AI
3 胴元・市場:サッカー football-data.co.uk の欧州18リーグ 60,829試合 ロジスティック回帰、勾配ブースティング、Benter型ブレンド
4 胴元:口座制限 模擬(研究3の実測値を使用) —
5 市場:競馬(控除率20%) 模擬(真の確率が既知) 精度の異なるAI、市場を写すAI、ブレンド
6 市場:米国株 Kenneth R. French Data Library(1926〜2026年) リッジ回帰、勾配ブースティング
7 市場:サッカー プレミアリーグ460試合 Claude Haiku 5.5
8 まとめ 研究1〜7の出力 —

技術スタックは Python 3.13、numpy、scipy、pandas、scikit-learn、matplotlib、anthropic です。uv で依存関係を管理し、ruff と isort で整形し、pytest でテストしています。

動かし方

git clone https://github.com/shibuiwilliam/bet-with-ai.git
cd bet-with-ai
uv sync
./run_all.sh          # 全研究を実行(初回はデータのダウンロードで数分、2回目以降は約1分)
uv run pytest         # 単体テスト+結果の回帰テスト(約1分)

各研究の結果は outputs/ にMarkdownとJSONで書き出し、考察は report.md にまとめています。乱数の種、ライブラリのバージョン(uv.lock)、データのハッシュ(data/MANIFEST.json)、LLMの回答(data/llm_cache/)は、すべて固定しています。そのため、何度実行しても、すべての出力がバイト単位で一致します。


研究1 相手が「数学」:学習AIはルーレットに勝てるか

同じ学習AIを3つの乱数源に当てました。

  • 認証された乱数(numpy の PCG64)
  • 3つのポケットが10%出やすい、偏ったホイール
  • 12ビットの線形合同法で作った、弱い疑似乱数
betai/s1_chance.py
def weak_prng(seed: int, n: int) -> np.ndarray:
    """A 12-bit linear congruential generator (period 4,096) mapped to 0..36."""
    m, a, c = 4096, 1665, 1013
    x = seed % m
    out = np.empty(n, dtype=np.int64)
    for i in range(n):
        x = (a * x + c) % m
        out[i] = (x * N_POCKETS) >> 12
    return out

AIは、直前のk回から次の出目の頻度を学習し、最も多かった出目に1点を賭けます(的中すれば36倍、期待値 −2.70%)。各条件で20万回転を試しました。

乱数源 AI ROI [95%CI]
認証された乱数 2次マルコフ −2.62% [−5.19%, +0.01%]
偏ったホイール 頻度モデル +5.98% [+3.45%, +8.68%]
偏ったホイール 2次マルコフ −3.90% [−6.42%, −1.38%]
弱い疑似乱数 2次マルコフ +2,265%(的中率65.7%)
弱い疑似乱数 頻度モデル −39.4%

学習曲線

  • 勝因はAIではなく相手の欠陥にあります。 認証された乱数では、過去の出目が次の出目について持つ情報量(相互情報量)がゼロと区別できず(置換検定 p=0.75)、AIは理論値どおり負けました。
  • 欠陥があっても、モデルの構造が合わなければ負けます。 偏ったホイールは出現率の偏りなので、頻度モデルで捉えられます。2次マルコフでは、データが1,369通りの文脈に分散して捉えられませんでした。逆に、弱い疑似乱数は系列の規則なので、頻度モデルでは捉えられません。
  • 複雑なモデルほど、存在しないパターンを見いだして賭けてしまいます。 「99%の確度で損益分岐点を超えるときだけ賭ける」という慎重なAIを、認証された乱数に当てました。頻度モデルが賭けたのは316回だけでしたが、2次マルコフは16,872回も賭けました。大量の候補から最大値を選ぶため、偶然の偏りを優位性と誤認してしまうのです。

ほかに2点を確かめました。

  • マーチンゲール(負けるたびに賭け金を倍にする方法): 90.8%のセッションで勝ちましたが、賭け金1単位あたりの損益は −2.63% で、均等に賭けた場合と同じでした。勝率と期待値は別物です。
  • 期待値 −10% のスロット(Lee et al. 2025 と同じ設計):20回賭ける場合、負けるたびに賭け金を倍にすると、破産率は固定額で賭けた場合の16.1%から78.6%に上がりました。

研究2 相手が「人」:CFRでポーカーAIを作り、勝因を分解する

クーン・ポーカー(J・Q・Kの3枚で行う最小のポーカー)では、すべての期待値を数え上げによって厳密に計算できます。LibratusやPluribusと同系統のアルゴリズムであるCFR(反実仮想後悔最小化)を使い、均衡戦略を学習させました。核心部分は次の20行ほどです。

betai/s2_skill.py
    def walk(h, c1, c2, reach):
        if h in TERMINAL:
            return np.array(payoffs(h, c1, c2, 0.0))
        player = OWNER[h]
        k = (h, c1 if player == 0 else c2)
        sigma = current(k)  # regret matching
        values = np.zeros((2, 2))
        node = np.zeros(2)
        for ai, a in enumerate("pb"):
            new_reach = reach.copy()
            new_reach[player] *= sigma[ai]
            values[ai] = walk(h + a, c1, c2, new_reach)
            node += sigma[ai] * values[ai]
        regret[k] += reach[1 - player] * (values[:, player] - node[player])
        strat_sum[k] += reach[player] * sigma
        return node

2万回反復すると、相手が最善応答によって得られる利益(搾取可能性)は、0.0016チップ/手まで下がりました。先手の期待値も理論値の −1/18 に一致しました。この均衡AIと、相手の癖を完全に把握して弱点を突く「搾取AI」を、人間らしい癖を持つ4種類の相手と戦わせました。

相手の癖 均衡AI(チップ/手) 搾取AI(チップ/手) 優位の証明に必要な手数
何でもコールする +0.137 +0.417 74
強い手以外は降りる −0.001 +0.250 118
常にベット・コール +0.114 +0.333 161
Jで頻繁にブラフ +0.001 +0.117 1,063
  • 均衡戦略(GTO)は「負けない」だけです。 相手の明らかな悪手(Jでのコールなど)からは稼ぎますが、慎重な相手からはほぼ稼げませんでした。
  • 勝因は相手の癖です。 相手の12個の判断それぞれについて「癖のある戦略」と「均衡戦略」のどちらかを選ぶ、全4,096通りの組み合わせで期待値を計算し、シャープレイ値を使って寄与を分解しました。何でもコールする相手から得た利益の59%は、「Jでベットにコールする」という2つの判断だけで説明できました。降りすぎる相手から得た利益も、その65%を「Qで降りる」という2つの判断が占めました。
  • 場代が小さな優位を消します。 レーキ(場代)が10%なら、均衡AIどうしは双方が −0.145 チップ/手で負けました。ブラフの多い相手を搾取するAIも、負けに転じました(−0.052)。

麻雀AIのSuphxについては、論文で報告された順位率(1位29.3%、4位18.7%)に正規分布モデルを当てはめました。Suphxの優位性は、平均得点の高さだけでなく、得点のばらつきが小さいこと、つまり4位を避ける力にも表れました。それでも、Suphxの安定段位の推定値がトップクラスの人間を上回る確率は、1,000局で86%、2,000局で93%でした。

研究3 相手が「胴元」と「市場」:サッカー6万試合でAIを賭けさせる

football-data.co.ukから、欧州18リーグ(2017/18〜2026/27)のCSVを取得しました。分析には、各社が提示した始値と終値のオッズを使います。

オッズからマージンを除く方法で、結論が変わる

オッズの逆数の合計は、胴元のマージンが含まれるため1を超えます。これを確率に直すため、当初は合計が1になるよう単純に正規化する「乗法」を使いました。しかし、この方法では大穴の確率を過大に見積もってしまいます。そこで、$\sum_i (1/o_i)^k = 1$ となる $k$ を求める「べき乗法」に切り替えました。

betai/data.py
def devig(o: np.ndarray, method: str = "power") -> np.ndarray:
    inv = 1.0 / o
    if method == "multiplicative":
        return inv / inv.sum(axis=1, keepdims=True)
    lo, hi = np.full(len(o), 0.5), np.full(len(o), 3.0)
    for _ in range(60):  # bisection; sum((1/o)^k) decreases in k
        k = (lo + hi) / 2
        over = (inv ** k[:, None]).sum(axis=1) > 1
        lo, hi = np.where(over, k, lo), np.where(over, hi, k)
    p = inv ** ((lo + hi) / 2)[:, None]
    return p / p.sum(axis=1, keepdims=True)
オッズ帯(平均終値) 実際の勝率 乗法 べき乗法 全結果に賭けたROI
1.0〜1.5 75.47% 72.04% 74.55% −0.89%
2.0〜3.0 38.65% 38.28% 38.57% −5.00%
5.0〜10.0 13.56% 15.07% 13.95% −15.90%
10以上 5.29% 7.08% 5.75% −30.34%

べき乗法でマージンを除いた終値の確率は、実際の出現頻度と重み付き R² = 0.9985 で一致しました。本命–大穴バイアスも明確に見られますが、どのオッズ帯でもROIはマイナスです。価格の歪みは、マージンを覆すほど大きくありません。

機械学習モデルは市場に勝てない

特徴量には、Eloレーティングの差(ホーム補正つき)と、得点・失点・シュート・枠内シュート・勝点の指数平滑平均を使います。同じ日の試合結果さえ使わないよう、日付ごとにまとめて特徴量を作り、その日の全試合分を処理してから状態を更新します。

betai/s3_sports.py
    # Group by date so that results from the same day never leak into each other.
    for _, idx in sorted(rows.groupby("date").groups.items()):
        updates = []
        for i in idx:
            ...  # 特徴量を作るだけ
        for i, h, a, diff in updates:
            ...  # その日の全試合の後で Elo と平滑平均を更新

各シーズンを、それ以前のシーズンだけで学習したモデルで予測しました(ウォークフォワード)。評価対象は、2021/22〜2026/27の34,626試合です。

予測 log-loss 終値との差 [95%CI] 的中率
Eloだけのロジスティック回帰 1.0156 +0.024 49.3%
ロジスティック回帰 1.0083 +0.017 [+0.015, +0.018] 49.8%
勾配ブースティング 1.0105 +0.019 [+0.017, +0.021] 49.7%
モデル+市場(Benter型ブレンド) 0.9950 +0.003 50.9%
市場(始値) 0.9950 +0.003 50.9%
市場(終値) 0.9916 0 51.3%

Benter(1994)と同じ形の p ∝ p_model^a × p_market^b でモデルと市場を組み合わせ、a と b を過去のシーズンから推定しました。モデルの重み a は −0.15〜−0.03 と、ほぼゼロでした。過去の試合結果やシュート数から得られる情報は、すでにオッズに織り込まれています。

期待値を「価格の比較・時機・マージン」に分解する

「モデルの確率 × オッズ」が1.05を超える結果に1単位ずつ賭け、各賭けの期待値を対数で分解しました。

\begin{aligned}
\ln(o p_{\mathrm{close}})
&= \ln\left(\frac{o}{\bar{o}_{\mathrm{open}}}\right) \\
&\quad + \ln\left(\frac{\bar{o}_{\mathrm{open}}}{\bar{o}_{\mathrm{close}}}\right) \\
&\quad + \ln\left(\bar{o}_{\mathrm{close}} p_{\mathrm{close}}\right)
\end{aligned}

右辺の第1項は「価格の比較」、第2項は「時機」、第3項は「マージン」を表します。ここで $o$ は賭けたオッズ、$\bar{o}_{\mathrm{open}}$ と $\bar{o}_{\mathrm{close}}$ はそれぞれ各社の始値と終値の平均オッズ、$p_{\mathrm{close}}$ は終値からマージンを除いた市場確率です。

モデル・賭けた価格 賭け数 モデルが見込んだ期待値 価格の比較 時機 マージン 実際のROI [95%CI]
勾配ブースティング・平均的な1社 20,357 +21.6% 0 −0.0% −8.6% −11.8% [−14.1%, −9.6%]
勾配ブースティング・Bet365 21,007 +22.2% +1.4% −0.2% −8.7% −10.1%
勾配ブースティング・全社の最高値 27,858 +24.4% +6.5% −0.2% −8.5% −5.2%

累積損益

  • 敗因は、マージンとモデルの過信です。 モデルが選ぶのは市場の予測と食い違う結果であり、その選択は大穴に偏ります。大穴ほどマージンは重く、約8.6%に達しました。モデルが見込んだ +22% は実現せず、賭けた後のオッズの動きによる効果(時機)もほぼゼロでした。市場の評価は、モデルの予測に近づかなかったのです。
  • プラス側の要因は「価格の比較」だけです。 全社の最高値で賭けると +6.5% 有利になりますが、マージンを埋めきれませんでした。

予測モデルを使わず、最高値が各社の平均(コンセンサス)から大きく離れた結果に賭ける Kaunitz et al.(2017)型のルールも試しました。始値では ROI +4.7%(2,860回、t=1.87)、終値では +4.8%(8,862回、t=3.29)と、記録上はプラスでした。

ただし、最高値には逆選択がありました。最高値が平均の1.2倍以上だった結果の実際の発生率は、終値から推定した市場確率の85%にとどまりました。「高すぎる価格」は、それだけ実現しにくい結果に提示されていたのです。

研究4 相手が「胴元」:勝つ客は、実力を証明する前に制限される

5万口座をシミュレーションしました。客の期待値には、研究3で実測した終値に対する期待値を使いました。胴元は、各賭けを終値と比較した成績のt値が2.5を超えるか、利益が40単位を超えた口座を制限します。実際の運用ルールは非公開であるため、ここでは実務を想定してこの規則を設けました。

客の種類 1回の期待値 制限された割合 制限までの回数(中央値) 優位の証明に必要な回数
娯楽の客 −7.0% 6.6% 355 ∞
AIモデルで賭ける客 −6.4% 12.5% 332 ∞
価格を比べる客 +3.7% 100% 38 10,218
鋭い客 +2.0% 100% 112 23,185

胴元はすべての賭けを終値と比較できるため、客自身が利益によって優位性を証明するよりも、はるかに早く勝つ客を見抜けます。予想だけを記録した紙上の成績で ROI +10%以上を示した客のうち、期待値が実際にプラスだった割合は、50回の記録では8%、200回でも19%でした。短期間の好成績は、その大半が偶然によるものです。

研究5 相手が「市場」:控除率20%の競馬と、成長率の恒等式

真の確率がわかるように、6万レースをシミュレーションしました(8〜16頭、JRAの単勝と同じ控除率20%、10円単位の切り捨て)。そして、理論編で導いた次の恒等式を1レースごとに検証しました。これは、全頭に予測確率どおりの割合で賭けた場合の、1レースあたりの対数成長率を表します。

$$
W = \ln(1-t) + D(p|r) - D(p|q)
$$

ここで、$t$ は控除率、$p$ は真の確率、$r$ は市場確率(票数のシェア)、$q$ はAIの予測確率、$D$ はKLダイバージェンスです。

tests/test_parimutuel.py
def test_growth_identity_holds_race_by_race(races):
    q = s5.model_probs(races, 0.4, seed=1)
    p, r, mask = races["p"], races["r"], races["mask"]
    t = s5.TAKEOUT
    o = s5.odds_from_shares(r, t, breakage=False)
    identity = math.log(1 - t) + s5.kl(p, r) - s5.kl(p, q)
    direct = np.where(mask, p * np.log(np.clip(q * o, 1e-300, None)), 0.0).sum(axis=1)
    assert np.allclose(identity, direct, atol=1e-10)

恒等式は、最大誤差 6.7×10⁻¹⁶ で成り立ちました。

AI 情報優位 D(p‖r)−D(p‖q) 全頭に比例して賭けた成長率 W 期待値がプラスに見える馬だけに賭けたROI
強いAI +0.021 −0.202 +10.6% [+7.6%, +13.5%]
中程度のAI −0.052 −0.278 −7.0%
市場を写すAI −0.004 −0.227(≈ ln 0.8) —
中程度のAI+市場(Benter型) +0.015 −0.209 +21.7% [+12.2%, +31.2%]

情報優位と控除率の壁

  • 市場を写すAIは、ちょうど控除率の分だけ負けます(W ≈ ln 0.8)。
  • 全頭への比例賭けでは、どのAIも負けました。 必要な情報優位 0.223 ナッツに対し、最強のAIでも 0.021 ナッツでした。
  • 期待値がプラスの馬だけを選べば、勝てる場合があります。 単独では負ける中程度のAIも、市場と組み合わせることで勝ちました(Benterの手法の再現)。
  • 容量に上限があります。 自分の賭けでオッズが下がる効果を入れると、期待利益は1レースあたり総票数の0.23%でした。Benter が見積もった上限「売上の0.25〜0.5%」と同じ水準です。

ただし、対象を選んで賭けることで勝てるのは、相手となる市場が不正確な場合に限られます。群衆の誤差を変えながら、強いAIが選んだ馬の真の期待値を比較しました。

群衆の誤差(ノイズの大きさ) 市場の誤差 D(p‖r) 強いAIの真の期待値
0.10 0.013 ナッツ −17.0%
0.20 0.022 ナッツ −7.0%
0.35(既定値) 0.046 ナッツ +11.9%
0.50 0.083 ナッツ +33.2%

研究3のサッカーのように市場が正確なら、この優位は成り立ちません。

研究6 市場:米国株100年でAIの売買シグナルを試す

Kenneth R. French Data Libraryから、米国株の日次の市場超過リターン(1926〜2026年)と、49業種のポートフォリオを取得しました。

リスクプレミアム: 株式のリターンが現金を上回った割合は、1日では54.0%、1年では70.9%、20年では100%でした。1日単位で見ると、プラスの期待値はほとんど判別できません。

予測力のないデイトレーダー(1990〜2026年、毎日無作為に買いか売りを選択、往復コスト0.1%):買い持ちを上回った人は0%でした。

レバレッジ(毎日L倍になるよう持ち高を調整):成長率は2〜3倍で最大になりました。しかし、1987年10月19日に −17.4% の下落があったため、6倍以上では1日で破綻しました。生き残れる上限は 1/0.174 ≈ 5.7倍です。

AIの売買シグナル: 毎年1月に直前10年のデータで学び直す(ウォークフォワード)モデルで、上位10業種を買い、下位10業種を売りました。

シグナル コスト前シャープ 片道5bp 片道10bp IC(t値)
リッジ回帰・週次 0.48 0.14 −0.19 +0.031(5.8)
勾配ブースティング・週次 0.49 0.04 −0.42 +0.024(5.6)
モメンタム(12−1か月)・月次 0.39 0.36 0.32 +0.057(5.0)
参考:市場の買い持ち 0.52 — — —
時代(週次、コスト前 → 片道10bp後) 1980〜1999 2000〜2012 2013〜2026
リッジ回帰 1.37 → 0.50 0.29 → −0.26 −0.18 → −0.82
勾配ブースティング 1.58 → 0.51 −0.04 → −0.80 −0.15 → −1.09

シグナルと市場

  • 予測可能性は実在しましたが、小さく、時代とともに消えました。 ICは統計的に有意でしたが、週次の売買回転率がコストを膨らませました。1980〜90年代にあった優位は、2000年以降はコスト前でも消えています。
  • 探索の罠があります。 16通りの手法から1980〜1999年の成績が最も良いものを選ぶと、標本内のシャープレシオは0.68でしたが、2000〜2026年には0.13まで下がりました。1通りだけを試したと仮定すれば有意に見える成績(PSR 98.2%)も、16通りから選んだ事実を考慮すると(Deflated Sharpe)、偶然得られた最良値と区別できませんでした。

研究7 本物のLLMに賭けさせる

プレミアリーグの460試合(2022/23〜2026/27)を、10〜20試合ずつClaude Haiku 5.5に渡しました。質問は次の3種類です。

  1. 結果を覚えているか
  2. チーム名と日付だけで予測できるか
  3. オッズを見せたうえで予測できるか

APIは合計161回呼び出しました。LLMの実験は、結果を再現できるよう、回答のキャッシュを前提に設計しています。

betai/s7_llm.py
def ask(prompt: str, tag: str, run: int = 0) -> str:
    key = hashlib.sha256(f"{MODEL}|{run}|{prompt}".encode()).hexdigest()[:24]
    path = CACHE / f"{tag}_{key}.json"
    if path.exists():
        USAGE["cached"] += 1
        return json.loads(path.read_text())["text"]
    ...  # API を呼び、プロンプト・回答・トークン数・日時を path に保存する

キャッシュ(data/llm_cache/)もリポジトリに含めているため、APIキーがなくても同じ回答を再採点できます。

シーズン 結果を答えた割合 LLM(オッズなし) LLM(オッズあり) 市場(終値)
2022/23 31% 0.989 0.970 0.954
2023/24 18% 0.930 0.885 0.869
2024/25 5% 0.947 0.854 0.859
2025/26 0% 1.053 1.061 1.034
2026/27 0% 1.042 1.049 1.056
全体 — 0.988 0.956 0.946

(数値は log-loss。小さいほど良い)

  • LLMは市場より不正確でした(オッズなしで +0.042 ナッツ、95%CI +0.016〜+0.069)。オッズを見せても、市場を上回りませんでした。
  • 今回の条件では、記憶による先読みの利益は見られませんでした。 結果を答えた割合は、モデル自身が回答した学習データの終了時期(2025年初め頃)と整合するように低下しました。ただし、回答したスコアの正答率は16〜40%にとどまり、記憶は不正確でした。勝敗を正しく思い出せた試合でさえ、実際に起きた結果へ割り当てた確率は市場より低いものでした。
  • 賭けの結果: 272回で ROI −17.5%(95%CI −38.6%〜+3.5%)でした。数百回では、優位の有無を判定できません。
  • 再現性がありません。 同じプロンプトを2回送ったところ、予測確率が完全に一致した試合は19.8%にすぎず、最も高い確率を割り当てた結果が入れ替わった試合も8.9%ありました。

横断:AIの勝因と敗因

相手 AIが勝った条件(勝因) AIが負けた理由(敗因)
数学 乱数源の欠陥と、それに合ったモデル構造 情報量ゼロ。控除がそのまま期待値になる
人 相手の癖(利益は少数の判断ミスに集中する) 相手が均衡に近いと稼げない。場代と分散
胴元 各社の価格のばらつき マージン、逆選択、勝つ客の制限
市場(競馬・サッカー) 控除を超える情報優位を持つ対象だけを選ぶこと。市場との組み合わせ 市場が正確。AIの過信。容量の上限
市場(株式) 長期保有でのリスクプレミアム(AIは不要) 回転率×コスト、優位の減衰、探索による過学習
LLM — 市場より不正確。答えが毎回変わる

AIが勝ったのは、相手に欠陥・癖・不正確さがあり、そこから得られる優位が控除やコストを上回るときだけでした。しかも、勝てる状況ほど、口座の制限、市場容量の上限、優位性の消滅によって、勝ち続けることが難しくなります。AIは賭けの数学を変えません。変えるのは、誰が勝ちやすいかです。 この結論は、理論編の主張とおおむね一致しました。

実装で踏んだ落とし穴

1. マージンの除き方で、評価が6σずれた

当初は、乗法でマージンを除いていました。すると、モデルによる賭けの「終値で見た期待値」は +1.1% だったにもかかわらず、実際のROIは −5.2% で、その差は約6σもありました。原因は、乗法が大穴の確率を過大に見積もり、大穴に偏ったモデルの賭けを実態以上に有利に見せていたことです。べき乗法に変えると、較正の R² は0.9938から0.9985に上がりました。オッズを確率に変換する処理は地味ですが、評価の結論を左右します。

2. 時点の管理をテストで固定する

賭けやトレードのモデルで最も注意すべきなのは、未来の情報が混入するリーク(先読み)です。そこで、「ある日の結果を書き換えても、その日以前の特徴量は1ビットも変わらない」ことをテストで保証しています。

tests/test_sports.py
def test_features_do_not_use_results_from_the_same_day():
    df = make_matches()
    base = s3.build_features(df)
    changed = df.copy()
    last = changed["date"] == changed["date"].max()
    changed.loc[last, ["hg", "ag"]] = [9.0, 0.0]
    after = s3.build_features(changed)
    pd.testing.assert_frame_equal(base, after)

株式のモデルについても、ある年以降のリターンを書き換えて、それより前の年の予測が変わらないことを確かめています。

3. 結果そのものを回帰テストにする

研究の結論は数値で示されるため、各研究を一時ディレクトリで再実行し、MarkdownとJSONが公開版と一字一句一致するかをpytestで確かめています(約1分)。整形ツールによる修正の際にも、このテストを使ってロジックが変わっていないことを確認しました。データ提供元は随時更新されるため、読み込み時に公開時点の最終日でデータを切り、取得したファイルのハッシュが記録と異なる場合は警告を出すようにしています。

限界

  • 模擬の研究(1・2・4・5)の数値は、仮定に依存します。特に研究5では、AIと群衆の誤差を独立としたので、現実よりAIに有利です。
  • サッカーの「最高値」で、実際に約定できたとは限りません。また、モデルの特徴量は試合結果とシュート関連の情報に限られます。
  • 株式の業種ポートフォリオは、そのままでは売買できません。コストは仮定で、空売りのコストと税は含めていません。
  • LLMの実験は1モデル、460試合に限られ、サンプリング設定も既定値のままです。他のモデルや検索ツールつきのエージェントに、そのまま一般化することはできません。
  • 日本の競馬の実データは使っていません。

まとめ

  • 理論編で示した主張の多くを、コードで再現できました。具体的には、市場並みの予測精度では控除分だけ負けること、実力の証明には数万回が必要なこと、勝者が制限されること、機械学習の優位がコストと時間によって消えることなどです。
  • AIが勝つのは、相手に欠陥・癖・不正確さがあり、その差が控除やコストを上回るときに限られました。
  • 一方、再現できなかったのは、LLMの記憶による先読みの影響と、実データにおけるモデルと市場の組み合わせの有効性の2点です。

理論的な背景は、理論編の2本で詳しく説明しています。

参考

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?