乙Py先生のプログラミング教室
初学者のためのプログラミング学習サイト

破産確率

今回はケリー基準を用いた
破産しないための最適資金配分のシミュレーションです。


解説動画はこちら

 




破産しないための最適な賭け金の割合



・問題
コインを投げて、表が出たら賭け金が2倍、裏が出たら全て失う賭けです
このコインは、55%の確率で表が出るやや有利なコインです

手元には100万円あり、このゲームを250回繰り返すとき
毎回いくら賭けるのが最適でしょうか?






--------------------------------------------------------




・回答
ケリー基準をもとに
最適な賭け金を算出することができます。


ケリー基準 : 
資産運用において
最適な資金配分比率を決定するための数式

割合 = (勝率 × オッズ − (1−勝率) ) / オッズ

ここに
勝率 0.55(55%)
オッズ(2倍-1倍 = 1)
を入れると

0.55 - 0.45 = 0.1

資金の0.1倍を賭けるのが
最適解ということになります。




250回の賭けコイン試行シミュレーション


先ほどの問題をシミュレーションするコードです。

初期資金 : 100万円
勝率 : 55%
回数 : 250回

シミュレーション結果を集計した結果を
出力する関数です。
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
pd.options.display.float_format = '{:.2f}'.format

# 250回のコイントスの賭けシミュレーター
def coin_250(default_assets=1000000,times=250,win_rate=0.55):
  kelly_criterion_percentage = (win_rate - (1 - win_rate))
  data = []
  assets = default_assets
  for i in range(times):
    stakes = int(assets * kelly_criterion_percentage)
    assets -= stakes
    result = np.random.choice([1,0],p=[0.55,0.45])
    if result == 1:
      assets += stakes * 2
    tmp =[assets,stakes, int(result)]
    data.append(tmp)
  
  # 250回の結果をデータフレームで集計
  df = pd.DataFrame(data,columns=["assets","stakes","result"])
  max_assets = df["assets"].max()
  min_assets = df["assets"].min()
  max_stakes = df["stakes"].max()
  min_stakes = df["stakes"].min()
  final_ps = int(df["assets"].tail(1).values[0])
  profit = final_ps - default_assets
  win_times = int(df["result"].sum())
  lose_times = len(df) - win_times

  group_id = (df["result"] != df["result"].shift()).cumsum()
  run_lengths = df.groupby(group_id)["result"].sum()
  run_lengths_0 = df.groupby(group_id).apply(lambda x: (len(x) - x["result"].sum()))
  # 最大連敗回数
  max_lose = run_lengths_0.max()
  # 最大連勝回数
  max_win = run_lengths.max()

  result_250 = [max_assets,min_assets,max_stakes,min_stakes,final_ps,profit,win_times,lose_times,max_win,max_lose]
  return result_250

この関数を使って
1000セット試行を行います。
times = 1000
results = []
for i in range(times):
  data = coin_250()
  results.append(data)

columns = ["最大資産","最小資産","最大掛金","最小掛金","最終資産","最終利益","勝利回数","敗北回数","最大連勝","最大連敗"]
df = pd.DataFrame(results,columns=columns)
df.describe()
desc最大資産最小資産最大掛金最小掛金最終資産最終利益勝利回数敗北回数最大連勝最大連敗
count1000.001000.001000.001000.001000.001000.001000.001000.001000.001000.00
mean16066691.73576608.611588961.9557127.3511146821.0310146821.03137.19112.818.496.45
std33581089.69289491.313311346.2928006.3827692950.8927692950.897.917.912.271.56
min900000.007130.00100000.00713.007687.00-992313.00107.0089.004.003.00
25%2515432.75346220.75248966.5034622.001159975.00159975.00132.00108.007.005.00
50%6327419.00575743.50632741.5057574.003163743.502163743.50137.00113.008.006.00
75%15386038.00801900.001515707.5080274.008628829.007628829.00142.00118.0010.007.00
max541305769.001100000.0054130576.00100000.00390665788.00389665788.00161.00143.0026.0014.00


こんな感じの結果になりました

勝利回数の分布をプロットしてみると
download-1

おおよそ勝率55%の回数で正規分布に近似しますね

最終利益はこんな感じです
download

0以上になっていれば、利益が出ている
0未満は負け
ということになります。

今回は1000セットやって
利益が出た回数が762回
0未満は238回でした




まとめ

勝率とオッズが分かっているならケリー基準を元に
資金調整すれば、資金が0になることはほぼ無いです。

ただし、勝率とオッズ次第では
元の資金より減る事もあるので注意が必要です。

より負けたく無い場合は
ケリー基準の半分の割合でかけるなど
保守的な割合にすればもっと負けづらくなります。

株式などにも応用できるため
色々シミュレーションに使うと面白そうです。


今回はここまでです
それでは

ルーレットなどのギャンブル
元手が倍になる確率はいくらになるでしょうか?


解説動画はこちら




問題

カジノのルーレットで元手が倍になる確率はどれくらいでしょうか?

ルール

100ドルを元手に 1ドル 単位で賭け続け
200ドル に到達するか0になったら終了

数字は1-36まであり、赤か黒の色が設定されている
数字0(緑)が1個、ここに当たるとディーラーが勝ち、賭けは没収

赤か黒に賭けると、当たったら2倍の払い戻し

このルールだと、元手が2倍になる確率はどれくらいでしょうか?




回答

ルーレットの元手が倍になる確率は
ギャンブラーの破産問題の公式に当てはめると解けるようです。

スタート資金を i、目標を N、負けたら破産(0)
勝率 p、負け率 q=1-p のとき
目標に到達する確率は以下で表せます:
スクリーンショット 2025-09-20 17.00.23

この式に代入していくと

•    i = 100 
•   N = 200 
•   p = 18/37  = 0.48648649
•   q = 19/37  = 0.51351351

こんな感じになり
計算式に当てはめると

スクリーンショット 2025-09-20 17.01.19
となります。

最終的な確率を求める部分を
Pythonのコードでやってみましょう。
p =  (1 - (19/18) ** 100) / ( 1 - (19/18) ** 200 )
print(p)
print(f"{p*100:.04}%")
0.004466284539492003
0.4466%


大体、0.45%くらい
1000回挑戦したら、4-5回でしょうか。




ルーレットのシミュレーションコード

これを実際にシミュレーションしてみます。

コードを簡略化するために
赤と黒の代わりに奇数なら当たり
偶数ならハズレにしてやってみます。
import random

def simulate_game(start=100, goal=200, trials=10):
    bankrupt_count, double_count = 0, 0
    for _ in range(trials):
        money = start
        while 0 < money < goal:
            # ルーレットの出目を 0-36 からランダムに選ぶ
            spin = random.randint(0, 36)
            if spin % 2 == 0:  # 偶数 → 負け
                money -= 1
            else:  # 奇数 → 勝ち
                money += 1
        if money == 0:
            bankrupt_count += 1
        elif money == goal:
            double_count += 1

    print(f"シミュレーション回数: {trials}")
    print(f"破産した回数: {bankrupt_count}")
    print(f"200ドルに到達した回数: {double_count}")
    print(f"破産確率: {bankrupt_count/1000:.3f}")
    print(f"成功確率: {double_count/1000:.3f}")

simulate_game(trials=1000)
シミュレーション回数: 1000
破産した回数: 997
200ドルに到達した回数: 3
破産確率: 0.997
成功確率: 0.003


おおよそ、数式の数値を近くはなりますね。

1000人いたら
4-5人は元手を増やしてカジノを出ることができる
そんな確率ですかね。



ルーレット以外の破産確率

1.ブラックジャック(基本戦略でプレイ)
2.パチンコ(一般的な遊技機)
3.競馬(単勝を繰り返す単純モデル)

この破産確率も見てみます。

ここでは計算を簡略化するために
1ゲームあたりの勝率を使って近似確率を求めていきます。

1ゲームあたりの勝率は以下のように設定することとします。
•   ブラックジャック(基本戦略+カジノ側有利)
 → プレイヤー勝率 ≈ 0.49、負け ≈ 0.51

•   パチンコ(通常 0.80〜0.90 程度の還元率)
 → 実質勝率 ≈ 0.45、負け ≈ 0.55

•   競馬(通常 0.70〜0.80 程度の還元率)
 → 実質勝率 ≈ 0.40、負け ≈ 0.50 と仮定


ルーレットにこの3つも加えてシミュレーションするコード
from decimal import Decimal, getcontext
getcontext().prec = 50  

def ruin_probability(s, N, p):
    """
    ギャンブラーの破産確率
    s: 初期資金
    N: 目標資金
    p: 勝率
    """
    q = Decimal(1) - p
    if p == q:
        return Decimal(1) - Decimal(s) / Decimal(N)
    else:
        ratio = q / p
        num = ratio**Decimal(s) - ratio**Decimal(N)
        den = Decimal(1) - ratio**Decimal(N)
        return num / den

# パラメータ
s = Decimal(100)   # 初期資金
N = Decimal(200)   # 目標資金

games = {
    "ブラックジャック": Decimal("0.49"),
    "ルーレット" : Decimal("0.48648649"),
    "パチンコ": Decimal("0.45"),
    "競馬": Decimal("0.40")
}

for game, p in games.items():
    ruin = ruin_probability(s, N, p)
    success = Decimal(1) - ruin
    print(f"{game}:")
    print(f"  破産確率  = {ruin:.20}")
    print(f"  倍化確率  = {success:.20}")
    print()
ブラックジャック:
  破産確率  = 0.98202320998693248326
  倍化確率  = 0.017976790013067516735

ルーレット:
  破産確率  = 0.99553370920702988362
  倍化確率  = 0.0044662907929701163797

パチンコ:
  破産確率  = 0.99999999807255307809
  倍化確率  = 1.9274469219075612712E-9

競馬:
  破産確率  = 0.99999999999999999754
  倍化確率  = 2.4596544265798292632E-18


ルーレットは先ほどと同じなので他を見ると
ブラックジャックは意外と勝てそうですね

競馬とパチンコはもう
勝てる見込みがほぼ無いです。


競馬だと
単勝を同じ金額ずっと買い続けるみたいなものが
この確率に近くなります。

単純な買い方では
競馬で元手を増やすことは出来ないでしょうね。



まとめ

1回あたりのおよその勝率から
破産確率は導き出すことができます。

基本的にギャンブルは元手を倍にできる確率は非常に少ないので
(ブラックジャックだけは、勝てる見込みが0ではない)
同じ100万円を注ぎ込むなら、まだ投資に回したほうがいいでしょう。

ギャンブルは卒業しよう!!!

ギャンブルでお金を減らす人が
一人でもいなくなりますように

それでは。


このページのトップヘ