nashidos’s diary

アルゴリズムとか機械学習とか色々

モンテカルロ法【カジノ】は負けるのかシミュレートしてみた

本記事では、モンテカルロ法と呼ばれるカジノにおける攻略法についてシミュレーションを行います。

行ったシミュレーション結果から長期的にモンテカルロ法を使った場合にどうなるのか分析していこうと思います。



モンテカルロ法とは

この攻略法は以下のような流れで進められます。

  1. 数列を用意する(例 [1, 2, 3])
  2. 端同士を足した金額を賭ける(例 1+3=4)
  3. 勝敗結果に応じて数列を操作
    1. 負けた場合は賭けた金額を数列に追加(例 [1, 2, 3, 4])
    2. 勝った場合は両端の数字を数列から削除(例 [1, 2, 3])
  4. 数字が1つ、もしくは無くなるまで2, 3を繰り返す

この攻略法は「負けにくい戦略」というのが特徴です。

負けた場合、前回のベット金額以上のお金をベットすることで多少の負けでは破産しません。

じゃあモンテカルロ法を使って億万長者になれるのかというと話はまた変わってきます。

それをシミュレーションを通して確認していきましょう。

シミュレーション

今回は以下の設定でシミュレーションを行いました。

  • 初期資産:100000円
  • ベースのベット金額:100円
  • ラウンド数(ループの終了で1ラウンド):100
  • 勝ったら賭けた金額が倍、負ければ0

実際に書いたソースコードも載せておきます。

ソースコード

import random
from matplotlib import pyplot as plt
%matplotlib inline

# 初期資産
balance = 100000
# 賭ける金額
bet = 100
# ラウンド数
rounds = 100

record = []

for i in range(rounds):
    monte = [1,2,3]
    while len(monte) > 1 and balance > 0:
        record.append(balance)
        
        # 50%の確率で勝つ/負ける
        result = random.choice(['win', 'lose'])
        
        if result == 'lose':# 負けの場合
            balance -= (monte[0]+monte[-1])*bet
            # 足したものを追加
            monte.append(monte[0]+monte[-1])
            
        elif result == 'win':# 勝ちの場合
            balance += (monte[0]+monte[-1])*bet
            # 端の数字を消す
            del monte[0]
            del monte[-1]
            
# グラフ出力
plt.xlabel("game")
plt.ylabel("balance")
plt.plot(record)

シミュレーション結果

シミュレーションを回した結果が以下のグラフです。

f:id:nashidos:20210501204144p:plain

あれ、儲かってる?

一度200ゲーム目付近で落ち込んではいますが、最終的には140000円ほどに成長しています。

これはもしかして億万長者になる方法を見つけてしまったかもしれません。

念のためラウンドを1000に増やしてもう一度実行してみます。

f:id:nashidos:20210501204546p:plain

はい、死にました。

残金が0になり強制終了です。

このようにモンテカルロ法はすぐには負けないけど、長期的にみると負けてしまう戦法のようです。

ただ、これだけしかシミュレーションを回していないと偶然という可能性もあります。

ということで、一気に10回ぐらいシミュレーションを回してどうなるのか見てみようと思います。

複数のシミュレーション

複数回シミュレーションを回すためにソースコードを以下のように変更しました。

for文で囲むだけです。

ソースコード

import random
from matplotlib import pyplot as plt
%matplotlib inline

count = 10

for j in range(count):
    # 初期資産
    balance = 100000
    # 賭ける金額
    bet = 100
    # ラウンド数
    rounds = 100

    record = []

    for i in range(rounds):
        monte = [1,2,3]
        while len(monte) > 1 and balance > 0:
            record.append(balance)

            # 50%の確率で勝つ/負ける
            result = random.choice(['win', 'lose'])

            if result == 'lose':# 負けの場合
                balance -= (monte[0]+monte[-1])*bet
                # 足したものを追加
                monte.append(monte[0]+monte[-1])

            elif result == 'win':# 勝ちの場合
                balance += (monte[0]+monte[-1])*bet
                # 端の数字を消す
                del monte[0]
                del monte[-1]
            
    # グラフ出力
    plt.xlabel("game")
    plt.ylabel("balance")
    plt.plot(record)

シミュレーション結果

まず先ほどと同じ初期設定で、10回シミュレーションした結果が下の画像です。

f:id:nashidos:20210501205622p:plain

お!やはり100ラウンド程度であれば100%利益がでていますね。

次に、ラウンド数を1000にして10回シミュレートしてみます。

f:id:nashidos:20210501205739p:plain

はい、8割ほど死んでいます。

シミュレーション回数を増やしてもやはり長期的にモンテカルロ法のみで勝ち続けることは難しそうです。

まとめ

モンテカルロ法はたしかに負けにくい攻略法で短期間であればかなりの確率で利益を出すことができそうです。

しかし、長期的に見るとこの攻略法だけでは勝ち続けることはできず、ほぼ確実に負けてしまいます。

世の中簡単に億万長者にはなれませんね。

おわり

デプスチャートをPythonで描写してみる

本記事では仮想通貨のデプスチャートをPythonで描写する方法について紹介します。

今回は例としてbitflyerのBTC_JPYのデプスチャートを作成してみたいと思います。

実際にソースコードも載せているのでご自由にお使いください。

デプスチャートとは

デプスチャートはその名の通り注文の深さを視覚的に表したチャートです。

買い、売りのそれぞれの注文がどの価格帯にどれだけの量注文されているかなどがわかるので、買いが強いのか売りが強いのかが判定しやすくなります。

f:id:nashidos:20210406231837p:plain

ただ、もちろんデプスチャートのみでトレンドを見極めるのは難しいのでご注意ください。

bitFlyer API

ビットフライヤーAPIPythonから使えるpybitflyerというパッケージを今回は使用しました。

pipを用いて簡単に使用することが出来ます。

pip install pybitflyer

APIからは板の情報や価格情報、約定履歴などの情報を知ることができます。

詳しくは公式のAPI Documentationをご覧ください。

ソースコード

以下が実際に私が実装したソースコードです。

実行環境はJupyter Notebookです。

import pybitflyer
from datetime import datetime
from time import sleep
from matplotlib import pyplot as plt
%matplotlib inline

# APIクラスの宣言
api = pybitflyer.API()

# BTC/JPYの板情報を取得
board = api.board(product_code="BTC_JPY")

# 各板情報を取得
def get_depth_data(position):
    size = []
    price = []
    for order in board[position]:
        size.append(order['size'])
        price.append(order['price'])

    size_cum = [size[0]]
    for i in range(1, len(size)):
        size_cum.append(size[i]+size_cum[-1])
    
    return size, price, size_cum

# 注文サイズ、注文価格、累積注文サイズを取得
asks_size, asks_price, asks_size_cum = get_depth_data('asks')
bids_size, bids_price, bids_size_cum = get_depth_data('bids')

# 取得する範囲
board_range = 100

# 図のサイズ
plt.figure(figsize=(10,3))

# 図の描写
plt.fill_between(asks_price[0:board_range], asks_size_cum[0:board_range],  color="red", alpha=0.3)
plt.fill_between(bids_price[0:board_range], bids_size_cum[0:board_range],  color="green", alpha=0.3)
plt.plot(asks_price[0:board_range], asks_size_cum[0:board_range], color="red")
plt.plot(bids_price[0:board_range], bids_size_cum[0:board_range], color="green")

# 図の保存
plt.savefig("depthchart.png")

描写したデプスチャート

出力されたデプスチャートの例は以下の通りです。

横軸がBTCの価格、縦軸が累積の注文枚数です。

最も低い位置は現在の価格を示しており、そこから買い注文と売り注文がどのように分布しているのかを見ることができます。
f:id:nashidos:20210406224654p:plain

まとめ

Pythonを用いてデプスチャートを描写してみました。

product_codeを変えることで他の通貨のデプスチャートも簡単に描写することができます。

ご自身でご自由に拡張してみてください。

おわり。