A while ago I simulated Martingale strategies and some variations. This is the strategy where you double your bet on each loss in order to win your money back. I simulated a number of different strategies to see if it gave you the edge or at least minimised your risk of losing.

TL;DR in the long run you will experience a big loss or incremental smaller losses, but you can minimise your losses by setting limits. It’s not a strategy that ensures you’ll always win your money back.

One thing I didn’t address was the Gambler’s Fallacy and it has come up more than once since the post. This is the perception that if one outcome has turned up many times in a row, such as black on a roulette wheel, then red must be ‘overdue’ to turn up and believed to be more likely to occur on the next spin. The strategy is to wait until black or red has come up a set number of times in a row and on the next spin place a bet on the other colour, in a sense ‘hacking’ the probability.

## Why it doesn’t work

In roulette each spin is completely independent of the last meaning all previous spins have absolutely no influence on the next. Mathematically the property of independence is . Independence holds for most typical mechanical chance processes such as flipping a coin. The probability of an outcome is static.

Consider flipping a coin. A strategy may be to wait for 3 heads in a row then place a bet on tails, because tails is ‘overdue’. Let’s look at the probabilities. The probability of flipping a head is

and so the probability of 3 heads in a row is

What’s the probability the next flip is tails? Given each flip is independent the probability the next flip is tails is simply

Therefore the probability of 3 heads followed by a tails is

So, what’s the probability of observing 4 heads in a row?

Exactly the same. In other words, waiting for 3 heads to turn up doesn’t affect the chances of either heads or tails turning up next.

## Simulation

Let’s simulate the Gambler’s Fallacy just to convince ourselves that waiting for a high occurrence of one outcome doesn’t result in a higher probability of an alternative outcome.

A coin is flipped 40 times. The strategy we’ll test is waiting until 10 heads are observed in a row. The probability of this occurring is 0.00098. In the remaining 30 flips we’ll observe the proportion of tails. If the mean proportion of tails is greater than 0.5 then tails was ‘overdue’.

```
library(purrr)
n_sequences <- 1e6
n_flips <- 40
watching_window <- 1:10
bet_window <- (1:n_flips)[-watching_window]
n_heads <- 10
sequences <- map(1:n_sequences, ~sample(coin, n_flips, replace = TRUE))
heads <- sequences[map_lgl(sequences, function(sequence) sum(sequence[watching_window] == "heads") >= n_heads)]
tails_tally <- map_dbl(heads, function(sequence) sum(sequence[bet_window] == "tails"))
tibble(p_tails = tails_tally/30)
```

Did we hack the probability of tails being flipped? Nah. The mean proportion of tails observed in the remaining 30 flips is 0.493, very close to the expectation 0.5. In other words, tails was not ‘overdue’ to turn up. If we did hack the probability, the proportion would be something >0.5.

## Order is important

Our brains are funny and not random. If we saw 10 heads turn up in a row we would perceive that as a pretty remarkable event given the probability of that occurring is 0.00098. But, if we saw HTTTHHTTHT, we wouldn’t see that as anything special. Even though observing this exact sequence has the same probability as 10 heads in a row, at 0.00098.

Our brains are good at recognising patterns and 10 heads in a row is an easy pattern to recognise. Although, some combination of heads and tails, less so. In the above case I suspect (given my unqualified opinion on how brains work) we see 4 heads and 6 tails as a summary of the 10 flips. It’s not exactly a conscious thing, rather just how we summarise information. Observing 4 heads and 6 tails in any order has a probability of 0.21, which is much more likely to occur and so don’t see it as anything special.

## The Hot-hand Fallacy

The ‘Hot-hand’ fallacy is related the Gambler’s Fallacy where bets are placed on the same outcome as the last when a streak is expected. This arose in basketball where players could be considered ‘hot’ if they are having a good game. This has some logical basis since human performance is not entirely a stochastic process. If a player is having a cracker of a game it’s reasonable to expect higher scores / more scoring shots.

In the case of mechanical chance games like flipping a coin or roulette, this does not hold for the same reasons as discussed. Independence.

## The takeaway

If you’re playing Roulette, flipping a coin, or something similar, don’t bother with waiting for a run to get an edge. You may as well just start betting straight away. The best strategy you can have is to go all in and walk away on your first bet. Not exactly fun. The next best is to set a limit and stick to it. It’s also worthwhile keeping a record of your profit / loss for each session so you are aware of your global profit / loss. It’s easy to remember the wins and forget about the losses. Personally, I opt for video games instead.

## Code bits

```
# density of tails outcomes
tibble(p_tails = tails_tally/30) %>%
ggplot(aes(x = p_tails)) +
geom_density(fill = "purple2", alpha = 0.8, colour = "purple2") +
geom_vline(xintercept = 0.5, linetype = 1) +
geom_vline(xintercept = 0.493, linetype = 2) +
annotate("segment", x = 0.493, xend = 0.64, y = 3, yend = 3, linetype = 2) +
annotate("segment", x = 0.5, xend = 0.64, y = 2.7, yend = 2.7, linetype = 1) +
annotate("text", x = 0.67, y = 3, label = "Mean: 0.493", size = 12, hjust = 0, family = "userfont") +
annotate("text", x = 0.67, y = 2.7, label = "p = 0.5", size = 12, hjust = 0, family = "userfont") +
theme_minimal() +
theme(
plot.title = element_blank(),
axis.title = element_blank(),
axis.text.y = element_blank(),
axis.text.x = element_text(margin = margin(0.5, 0, 0.5, 0)),
plot.subtitle = element_text(lineheight = 0.3, margin = margin(0, 0, 0, 50), hjust = 0)
) +
scale_x_continuous(breaks = round(seq(5, 25, 5)/30, 1), labels = round(seq(5, 25, 5)/30, 1))
```