本文旨在通过简单的数学和计算机模拟,解释为何在赌博中倍投毫无意义

(假如你觉得在某处看过此文章,没必要惊讶,那很可能也是我写的,只不过被我转移到了这边)

倍投法(马丁格尔策略,Martingale Strategy)是一种赌博策略,该策略的核心思想是在每次输钱之后增加下一次赌注,以期望在赢得一局后能够弥补之前的损失,从而实现盈利。它基于一种假设,即输钱的次数越多,最终赢回来的可能性就越大。

倍投只存在于理论中,只有在赌资、赌注、时间无限的情况下有意义,三个要素只要有一个不满足就是无意义的,显然,现实世界中这三个条件中任意一个都不能被满足。赌博是反直觉的,倍投也是反直觉的,倍投其实并不会让你赚更多,但是同样的,也不会让你亏更多。你的赢钱期望一开始就决定了,所以不需要说什么倍投必死,试试反倍投,任何稀奇古怪的策略都是无意义的。

倍投法存在两个心理骗局,让你觉得这个方法好像可行。

概率很大,但是期望仍然是负的

单纯的概率是没有意义的,赌博是为了赢钱,必须加上收益期望才有意义。

拿抛硬币为例,胜率1/2,玩6轮,从1开始投注。学过小学数学的人会知道,连输6场的概率是1/64,也就是1.5625%。在倍投法中,只要赢一次就能获得收益,因此获得收益的概率为1-1/64,约为98.4375%。看上去是稳赚的,但是这没有意义,因为期望仍然是非正数。

在上面这个简单例子中,假如你赢了一次就跑,你有1/64的几率输掉63元,然后有63/64的几率赚1元。计算期望为1x63/64-63x1/64,结果为0元。

如果你赢了不停,继续下注1元,结果相同。这个也是反直觉的,并不会像赌客所想的那样赢更多,也不会像普通人那样见好不收会亏更多。公式证明有点麻烦,出于篇幅问题,借用一张图片,把规模缩小到3轮,这是轮盘赌红蓝球用倍投法的排列组合。把最右边的期望加起来,其实还是0。

期望为0是50%胜率的公平赌局,现实中赌场的概率都是小于50%的,期望必然为负数。倍投相比均注,会让你从等概率的不赚不赔,变成大概率小赚,小概率大赔。其实还是一样的。除了节省时间以外没有什么意义。

但是在完全理想的环境下,倍投法确实是必赢的,因为你的赌资、时间和下注上限都是正无穷,赢的概率就是必然100%。但是只要条件不是无限,直接把上面的例子等比放大一亿倍也是同样的期望。

黑天鹅其实很常见

倍投基于一个假设,连输的概率很低,但是只要赢一次就能翻本。因此在交替输赢的局面下,倍投可以有较稳定的收益,直到遇到连输才会爆仓离场。但是连输的概率在多轮赌局后,就会非常大。这个很反直觉,但是确实是这样的。比如在上面的抛硬币赌局里,6场里连输6场概率是1.5625%,这个很容易计算出来。但是如果继续玩下去,玩10场、100场、200场呢?通过程序计算排列组合以及随机模拟,可以得出以下结果。代码在最后边。

为了让结果更有趣味性,我还加了记录模拟过程中出现过的最大连输数,这个最大连输次数主要和模拟次数有关。由于计算排列组合的时间复杂度是按指数增加的,超过20局以上就会耗时非常长,因此后续没有列出。

胜率为0.50,10000000次数模拟中,
每6次赌局中平均至少出现一次连输6次发生概率:1.56%,
出现过的最多次连输:6次
胜率为0.5,通过排列组合, 
每6次赌局中平均至少出现一次连输6次发生概率:1/64,1.56%


胜率为0.50,10000000次数模拟中,
每10次赌局中平均至少出现一次连输6次发生概率:4.68%,
出现过的最多次连输:10次
胜率为0.5,通过排列组合, 
每10次赌局中平均至少出现一次连输6次发生概率:48/1024,4.69%


胜率为0.50,10000000次数模拟中,
每50次赌局中平均至少出现一次连输6次发生概率:31.41%,
出现过的最多次连输:28次


胜率为0.50,10000000次数模拟中,
每100次赌局中平均至少出现一次连输6次发生概率:54.47%,
出现过的最多次连输:29次

胜率为0.50,10000000次数模拟中,
每200次赌局中平均至少出现一次连输6次发生概率:79.93%,
出现过的最多次连输:31次

胜率为0.50,10000000次数模拟中,
每1000次赌局中平均至少出现一次连输6次发生概率:99.97%,
出现过的最多次连输:32次

其实这个也是赌徒谬误的一种,“怎么可能连输10把呢?“,上得山多终遇虎,实际上这很容易,只要玩1000盘,连输10把的概率就已经是38%了,玩2000盘就是62%。只要你玩得够多,那什么都能碰上。而且赌局本质上是毫无联系完全随机的,一年每个月玩100把和一天玩1200把并没有本质区别。

总结

显然,赌博中使用倍投的期望只取决于赌局胜率,也就是说倍投并不能改变任何期望。

不过有些问题仍然萦绕不去。在较短期的赌局中,拥有较大的赌资和较小的赌注,确实可以使得胜率非常高,即使此时期望仍然为非正数。比如上面的例子,有98.4375%的几率赢1元,仅有1.5625%的几率输掉63元。总体胜率如此之高,这很让人迷惑,如何说服我不使用倍投?

在某种程度上,这确实呈现出一种悖论,其中期望为非正数是事实,而总体胜率却异常高。这种情况令人容易受到短期内高胜率的吸引。因此,很多网站提到的“在短期内,使用倍投法以小博大是有意义的”也有其合理之处。不过根据上面的计算我们知道,这个悖论不会持续太久,只要时间久一点,黑天鹅就很容易遇见。

代码

以下是模拟的python代码,你可以通过修改开头那几个为大写的变量来改变模拟目的。其中排列组合计算耗时极长,无法在正常时间内算出20局以上的结果,慎用,可以通过注释最后两行来取消排列组合计算。

# -*-coding:utf-8-*-
import random
from typing import Final, Tuple

# 修改下面的变量可以调整模拟的目的
SIM_ROUNDS: Final[int] = 100000  # 模拟次数
LOSING_STREAK_NUM: Final[int] = 6  # 连输次数
BET_ROUNDS: Final[int] = 10  # 赌局次数
P: Final[float] = 0.5  # 赌局胜率
###


def permuting_betting(bet_rounds: int, losing_streak_num: int) -> Tuple[int, int]:
    """
    通过排列组合计算一系列赌局中出现至少连输特定次数的几率,赌局胜率固定为50%,耗时极长
    Args:
        bet_rounds (int): 赌局次数。
        losing_streak_num (int): 连输次数。
    Returns:
        Tuple[int, int]: 至少特定次数连输的排列数;总排列组合数。这两个值的比值为几率。
    """
    reach_losing_streak_times: int = 0
    for curr_bet in range(0, 1 << bet_rounds):
        losing_streak_count: int = 1
        prev_lowbit: int = 0
        while curr_bet != 0:
            curr_lowbit: int = curr_bet & -curr_bet
            losing_streak_count = losing_streak_count + \
                1 if curr_lowbit == prev_lowbit << 1 else 1
            if losing_streak_count >= losing_streak_num:
                reach_losing_streak_times += 1
                break
            prev_lowbit = curr_lowbit
            curr_bet &= curr_bet-1
    return reach_losing_streak_times, 2**bet_rounds


def simulate_betting(sim_rounds: int, bet_rounds: int, p: float, losing_streak_num: int) -> Tuple[float, int]:
    """
    通过模拟计算一系列赌局中出现至少连输特定次数的几率,赌局胜率可调,耗时正常
    Args:
        sim_rounds (int): 模拟次数,影响精度、耗时、以及最大连输次数。
        bet_rounds (int): 赌局次数。
        p (float): 赌局胜率。
        losing_streak_num (int): 连输次数。
    Returns:
        Tuple[float, int]: 至少连输特定次数的几率;最大连输次数。
    """
    def simulate_betting_helper(bet_rounds: int, p: float, losing_streak_num: int) -> Tuple[bool, int]:
        losing_streak_count: int = 0
        max_losing_streak: int = 0
        reach_losing_streak_num: bool = False
        for _ in range(bet_rounds):
            win: bool = random.random() < p
            losing_streak_count = losing_streak_count+1 if not win else 0
            max_losing_streak = max(max_losing_streak, losing_streak_count)
            reach_losing_streak_num = losing_streak_count >= losing_streak_num or reach_losing_streak_num
        return reach_losing_streak_num, max_losing_streak

    avg_freq_reach_losing_streak: float = 0.0
    max_losing_streak: int = 0
    reached_times: int = 0
    for _ in range(sim_rounds):
        reached, curr_max_losing_streak = simulate_betting_helper(
            bet_rounds, p, losing_streak_num)
        reached_times += 1 if reached else 0
        max_losing_streak = max(curr_max_losing_streak, max_losing_streak)

    avg_freq_reach_losing_streak = reached_times/SIM_ROUNDS
    return avg_freq_reach_losing_streak, max_losing_streak


if __name__ == '__main__':
    avg_freq_reach_losing_streak, max_losing_streak = simulate_betting( SIM_ROUNDS, BET_ROUNDS, P, LOSING_STREAK_NUM)
    print(f"胜率为{P},{SIM_ROUNDS}次数模拟中, \n每{BET_ROUNDS}次赌局中平均至少出现一次连输{LOSING_STREAK_NUM}次发生概率:{avg_freq_reach_losing_streak*100:.2f}% \n出现过的最多次连输:{max_losing_streak}次")
    # 计算排列组合,耗时极长
    reached_times, all_permutations = permuting_betting( BET_ROUNDS, LOSING_STREAK_NUM)
    print( f"胜率为0.5,通过排列组合, \n每{BET_ROUNDS}次赌局中平均至少出现一次连输{LOSING_STREAK_NUM}次发生概率:{reached_times}/{all_permutations},{reached_times/all_permutations*100:.2f}%")

参考

Martingale (betting system))
The Martingale system paradox


rwxe
91 声望5 粉丝

no tengo trabajo.


引用和评论

0 条评论