Martingale strategies don’t work, but we knew that – Simulation analysis in R

[This article was first published on R – Daniel Oehm | Gradient Descending, and kindly contributed to R-bloggers]. (You can report issue about the content on this page here)
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

It’s generally accepted that Martingale betting strategies don’t work. But people still gravitate towards them because they are intuitive. I was curious to find out how they actually perform.

Disclaimer: I do not encourage gambling, nor do I gamble myself but the games are good examples of stochastic processes.

At a glance

  • The classic and Reverse Martingale strategies don’t work. They will almost certainly have you leaving with less money than what you started with, or more often than not no money at all.
  • The reverse strategy is generally less risky, higher potential to win big but lower returns on average.
  • Going all in on the first bet is the best way to double your money and save your time.

Classic Martingale

The Classic Martingale strategy is as follows. Make an initial bet $x. If you win, bet $x on the next round. If you lose, double your previous bet. In a nutshell you bet $2^{n}x where n is the number of losses in a row. The intention is to make your money back on the next win.

Assume we start with $100 and our initial bet is $1. We keep playing until there is not enough money in the cash pool to make the next bet. Also assume we are playing roulette on an American table and place bets on red or black which both have the probability 18/38. It only takes a streak of 6 losses before the game is over because we don’t have enough cash to double our bet for a 7th time. If we see a streak of 10 or more it really starts to get out of control.

trials bet cumulative_loss
1 1 1
2 2 3
3 4 7
4 8 15
5 16 31
6 32 63
7 64 127
8 128 255
9 256 511
10 512 1023

The probability of losing 6 in a row is P(\text{Streak of 6 losses}) = (1-p)^6 = 0.011. Sounds unlikely, but it will occur more often than you think. With each win we will win $1, so once we have won 27 times we’ll have enough cash in order to afford a losing streak of 6 and bet on the 7th.

It’s more likely we’ll have a few wins and losses before observing a long losing streak that takes us out of the game. The question is how many trials (spins of the roulette wheel) will we place bets on before we lose our money and play stops? A slight variation I’ve applied is, if there is not enough money left to double the bet, we will simply bet the remainder in the cash pool, in other words go all-in. More in line with what someone might do.

This simulation was a relatively lucky one, winning over $170 and almost 400 trials, however one bad streak and it’s all over. You can plot as many simulations as you like, some are shorter and some are longer but they all end the same way.

This is a typical pattern for the classic strategy. If you wish to see more try running the code at the end of this post or view this set.

Reverse Martingale

Instead of doubling the bet upon a loss, double the bet upon a win. Not surprisingly this ends the same way as the classic strategy.

The players cash amount slowly decreases by $1 on each loss. Occasionally there is a big win, rather than a big loss. With this strategy you can watch your money dwindle away rather than vanish in front of your eyes.

This plot is using the same win-lose sequence as the one above. In this case the maximum cash held throughout the game is higher with the classic strategy than the reverse.

Click here to see more simulations.

Number of trials for each strategy

These strategies was simulated 20,000 times. The distribution of the number of trials shows how long a typical game will last until bankruptcy. The classic strategy has a very long tail, so potentially could be playing for a very long time. The maximum number of trials is this simulation was 64254. But you could also be playing for a very short time.

The reverse strategy has a slightly higher median number of trials but much less variable than the classic strategy meaning you can be sure to play between 166 and 217 spins.

  min 2.5% 10% 50% 90% 97.5% max
classic 7 10 22 170 1132 2759 64254
reverse 152 167 172 191 207 213 226

Doubling your money

Assume the goal is to double your money. What is the probability you’ll double your money before going bust? After 20,000 simulations for both strategies, the probability you will double your money using…

  • The Classic Martingale strategy is 0.35
  • The Reverse Martingale strategy is 0.28

The Classic Martingale strategy tends to do better on average, but only slightly. Neither of these strategies are better than simply playing once and going all-in which is 0.47

Maximum cash

The distribution of the maximum amount of cash held by the player at any given time during the game shows the classic strategy has the slight edge over the reverse strategy on average. Although the reverse strategy has the potential for massive wins if you score a good winning streak.

  min 2.5% 10% 50% 90% 97.5% max
classic 100 101 107 158 425 926 19894
reverse 100 100 102 133 534 2062 131163

However, keep in mind these simulations all resulted in total loss at the end of the game. Perhaps the key is to know when to stop?

Stopping conditions

Rather than stopping once you reach a specified amount which may not happen, stop when the bet reaches a specified amount.

We could specify a streak length, however a better idea is to specify a ratio of bet to total cash. This way the is stopping condition is dynamic. For example, if there is a winning streak we’ll have more money in which to bet.

Essentially by using this ratio we are fixing a certain level risk rather than betting amount. The ratio is calculated as

    \[\text{stopping ratio} = \frac{\text{bet amount}}{\text{total cash amount}}\]

If we fix a stopping ratio of 0.1, we could place 4 bets before the ratio exceeds 0.1. If our initial cash pool was $200 we could place 5 bets until the ratio exceeds 0.1.

If we stop as soon as this ratio is reached it means we’re on a losing streak so it makes sense in the case of the classic strategy to bet again until our next win and walk away.

In the case of the reverse it makes sense to leave as soon as the ratio is met since we’re on a winning streak.

There are clear differences and similarities between the two strategies.

  • The median final amount for the low risk stopping condition is actually slightly above 100 for both strategies, meaning it is likely you will break even or take home a couple of bucks.
  • As the risk goes up the median value decreases where the classic strategy tends to have a higher median than the reverse strategy.
  • Higher the risk, the higher potential for bigger wins.
  • The reverse strategy has some interesting features. The ‘bumps’ occur when the risk is great enough to allow the next bet when you’re on a streak. However the chance of this streak is low enough that it doesn’t improve the strategy.

Overall the stopping strategies help to minimise loss rather than lock in wins, so on average you will still lose your money. The Martingales don’t work.

Code bits

The code for the plots in this post can be found on github. The Martingale function is below.

# libraries
library(tidyverse)

# martingale function
martingale <- function(bet, cash, p, stop_condn = Inf, stop_factor = Inf, reverse = FALSE, plot = TRUE, stop_on_next_win = TRUE){

  bet_vec <- vector(mode = "numeric")
  cash_vec <- vector(mode = "numeric")
  outcome <- vector(mode = "numeric")
  winnings <- vector(mode = "numeric")
  total_cash <- vector(mode = "numeric")
  trial <- 0
  total_cash[1] <- cash

  while(total_cash[max(trial, 1)] > 0){

    # iterate through trials
    trial <- trial + 1

    # update cash pool
    if(trial == 1){
      cash_vec[trial] <- cash
    }else{
      cash_vec[trial] <- total_cash[trial-1]
    }

    # set bet
    if(!reverse){
      if(outcome[trial - 1] == 1 || trial == 1){
        bet_vec[trial] <- bet
      }else{
        bet_vec[trial] <- min(2*bet_vec[trial-1], cash_vec[trial]) # if there isn't enough to double the bet just bet what is left
      }      
    }else{
      if(outcome[trial - 1] == 0 || trial == 1){
        bet_vec[trial] <- bet
      }else{
        bet_vec[trial] <- min(2*bet_vec[trial-1], cash_vec[trial]) # if there isn't enough to double the bet just bet what is left
      }
    }

    # stop condition
    if(bet_vec[trial]/cash_vec[trial] > stop_condn){
      if(stop_on_next_win & !reverse){
        stop_trigger <- TRUE
      }else{
        outcome[trial] <- NA
        winnings[trial] <- NA
        total_cash[trial] <- cash_vec[trial]
        break
      }
    }

    outcome[trial] <- sample(c(0,1), 1, prob = c(1-p, p))
    winnings[trial] <- bet_vec[trial]*outcome[trial] - bet_vec[trial]*(1-outcome[trial])
    total_cash[trial] <- cash_vec[trial] + winnings[trial]

    # stop condition
    if(total_cash[trial] >= stop_factor*cash) break
  }

  # make the plot
  g1 <- NULL
  if(plot){
    df <- data.frame(trials = 1:trial, cash = total_cash)
    gg <- ggplot() +
        geom_line(data = df, mapping = aes(x = trials, y = cash), col = "darkmagenta", lty = 1, size = 1) +
        geom_hline(yintercept = cash_vec[1], col = "grey", lty = 2) +
        theme_minimal() +
        labs(
          x = "Number of spins",
          y = "Total cash in hand",
          title = ifelse(reverse, "Reverse Martingale strategy", "Martingale strategy"),
          subtitle = "The growth and decline of the gamblers cash pool - it always ends the same way"
        ) +
        ylim(0, NA)
    print(gg)
  }

  return(list(
    bet = bet_vec, 
    cash = cash_vec, 
    outcome = outcome, 
    total_cash = total_cash, 
    trials = trial, 
    plot = gg))
}

# run the simulation and plot the output
# try different parameters to see the effect
martingale(1, 100, 18/38, reverse = FALSE, plot = TRUE, stop_condn = 1,
    stop_on_next_win = TRUE)

The post Martingale strategies don’t work, but we knew that – Simulation analysis in R appeared first on Daniel Oehm | Gradient Descending.

To leave a comment for the author, please follow the link and comment on their blog: R – Daniel Oehm | Gradient Descending.

R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

Never miss an update!
Subscribe to R-bloggers to receive
e-mails with the latest R posts.
(You will not see this message again.)

Click here to close (This popup will not appear again)