Roulette is a simple game. It is luck based — there is no real skill to it. Which makes it a perfect replacement for my day job…?
A friend from university first told me about the Martingale system. He sold it as an unbeatable way to make money — assuming you have enough in the bank.
The premise is simple. You bet on something which offers 50:50 odds. The system is as follows:
- Bet on red (or anything with similar odds)
- If you win, great. You’ve doubled your original stake.
- If you lose, no big deal. Bet again on red but bet twice as much.
- Rinse and repeat.
The theory goes that eventually you will win and get your money back. However in reality there are a few issues. Firstly — the odds in roulette aren’t actually 50:50, which makes it a bit harder. Secondly, it’s easy to hit a losing streak which wipes out your funds entirely.
Despite all of that, I was curious… So naturally, I did a lot of Python modelling to try to understand.
Building the simulator
If I want to crack the Martingale system and start making millions, first I have to understand the odds properly. My ideal scenario would be running over 100,000 different trials, and using them to find the ideal strategy.
However, before I can get fancy, I need to model a single instance of roulette. This is pretty easy. I know the odds of winning and defining the bet size means I know how much I’ve won.
Let’s have a look at some basic Python to do it.
"""
Very simple roulette simulator
"""
import random as rd
win_odds = 0.483
def gamble(win_odds):
""" takes a probability of winning and determines if we've won or not"""
return "win" if rd.random() <= win_odds else "lose"
if __name__ == "__main__":
gamble(win_odds)To be completely honest, the above code works but isn’t really necessary. I just included it above to demonstrate the premise. If you’re not comfortable with Python, the main bits are:
import random as rd— I’m loading in some ready-made code here to create a random number and make my life easierdef gamble(win_odds)— I define a function called gamble, which requires an argument called win_odds (the probability of winning) to work. You can see I’ve already defined what win_odds is on an earlier line.return "win" if ...— this tells the gamble function what to output.rd.random()generates a random number between 0 and 1, and if that number is less than or equal to the win odds, then we’ve won! Otherwise we lose.if __name__ == ...— this is a funny piece of code which tells Python to run the gamble function when I use the code. If you’re familiar with C it’s the equivalent of running main.
What I actually want to do is model somebody playing roulette. This is more complicated than modelling somebody winning one spin.
My roulette tester will follow some simple rules:
- they start the game with a starting balance
- they are told a minimum bet to start with
- they follow the Martingale system
- if their balance hits 0 they are out.
The code to do this looks like:
"""
Modelling somebody actually playing roulette
"""
import random as rd
win_odds = 0.483
def roulette_simulator(starting_amount, minimum_bet):
running_balance = starting_amount
running_bet = minimum_bet
while running_balance >= 0:
result = 1 if rd.random() <= win_odds else 0
if result == 1:
running_balance += (2* running_bet)
running_bet = min_bet
else:
new_bet *= 2
return running_balance
The code is still pretty straightforward. However it isn’t useful. One of the constraints we defined on our test player is they keep playing till they hit zero. This is reflected in the while loop in the code. But there’s no point playing till you hit rock bottom — the point is to play and make a return.
As is, the code needs some changing. We need another way for our player to quit playing. Let’s keep following the Martingale system, but we’ll change some constraints. I can think of two ways to have an early exit: by having a limit on the number of spins which someone can do, or by defining an exit multiple. If you can think of another approach feel free to tell me.
I’ve decided to follow the latter — by defining an exit multiple. The exit multiple tells our test player when to stop playing. An exit multiple of 1.1x means they stop playing once they’ve made 10% of their amount, i.e. their running balance = 1.1 × starting balance. This is easy enough to do, and we can quickly change the code:
"""
Modelling the complete Martingale system
"""
import random as rd
win_odds = 0.483
def roulette_simulator(starting_amount, minimum_bet, exit_mult):
running_balance = starting_amount
running_bet = minimum_bet
exit_balance = exit_mult * starting_amount
outcome = 0
while running_balance >= 0:
result = 1 if rd.random() <= win_odds else 0
if result == 1:
running_balance += (2* running_bet)
running_bet = min_bet
if running_balance >= exit_balance:
outcome = 1
else:
new_bet *= 2
return outcome
The above code runs the Martingale system in a realistic(ish) way. Our test player doubles their bet upon losing, and once they win they reset their minimum bet. They don’t have infinite funds either — if they run out of money they’re out. They also leave the table if they make enough money, and this is user defined.
The function roulette_simulator() returns either 1 or 0. 1 means we have made enough money, and 0 means we’ve run out. I chose this deliberately, as it makes it easier to understand probabilities.
I start with £100, bet £0.50 as the minimum, and define my exit value as £110 (1.1x). I can see if this passes or fails by simply running roulette_simulator(starting_amount=100, minimum_bet=0.50, exit_mult=1.1). This gives me a 1 or a 0, i.e. a pass or a fail. To go from this to a probability, I just need to repeat my code several times and see what happens.
I can do this with Python pretty easily:
def prob_calculator(number_of_trials):
exit_values = [ roulette_simulator(starting_amount, minimum_bet, exit_mult) for i in range(number_of_trials) ]
return sum(exit_values)/number_of_trials
In the above code block, we run the simulator N times. This gives us a list of outcomes, for example [1, 0, 0, 0, 1, 1, 0, ... , 0] (remember this reads as [success, fail, fail, fail …]). The list has N elements (one for each trial). The probability of success is therefore the number of successes divided by the total number of trials.
To sum this up — if I run prob_calculator with 1000 trials, £100 starting, £0.50 minimum and an exit amount of £110, I get a probability of 0.892, i.e. 89%. So there’s a 90% chance of a 10% return — not bad?
Varying the parameters
We’re getting somewhere it seems. We understand the returns we could make, and we know the risk associated with it. Let’s play with the three variables: the exit multiple, the starting value and the minimum bet. I’m going to keep the number of trials consistent and see how the probability of success changes.
| Starting balance | Exit balance | Minimum bet | Returns (%) | Success rate |
|---|---|---|---|---|
| 100 | 110 | 0.50 | 10% | 89.6% |
| 100 | 125 | 0.50 | 25% | 77.3% |
| 100 | 150 | 0.50 | 50% | 68.4% |
| 100 | 200 | 0.50 | 100% | 51.5% |
| 100 | 1000 | 0.50 | 900% | 9.4% |
| 100 | 110 | 1 | 10% | 89.3% |
| 100 | 125 | 1 | 25% | 75.4% |
This all seems to make sense intuitively. As exit value increases, our risk of success decreases. The longer we stay at the table, the more chance we have of going broke. What’s most interesting is the fact that we have a 51.5% chance of doubling our money. In pure roulette, we could double all of our money by betting on a colour (red/black) and then winning. This has odds of ~48%, and this acts as a pretty good control. We can immediately see that the Martingale method is (very slightly) better than pure roulette when it comes to doubling our money.
There’s also some sort of relationship between minimum bet and success, and again this seems to make sense. The minimum bet dictates how many times we can lose before we go broke. The lower the minimum bet, the longer we can play for. However this relationship isn’t linear — it actually scales logarithmically.
Let’s run through it — if we start with £50, a minimum bet of £1, and keep losing then our balance looks like this:
| Attempt | Starting Balance | Bet |
|---|---|---|
| 1 | £50 | £1 |
| 2 | £49 | £2 |
| 3 | £47 | £4 |
| 4 | £43 | £8 |
| 5 | £35 | £16 |
| 6 | £19 | £32 |
| - | £0 | £0 |
So we can lose 5 bets in a row before we run out of money. However, adding an extra pound or two to our starting balance doesn’t actually help. For us to last another bet, we would need to start with £64 rather than £50. It’s linked to powers of 2, and this is because we’re doubling our bet each time. So we can find how many bets we last from the below formula:
bets = log₂(starting amount / minimum bet)
We need to round the answer down to the nearest integer, and then we’ve got it. So we understand the relationship between minimum bet and how many times we can fail.
However the minimum bet also determines the rate at which we grow. Each successful round ends with us winning the minimum bet (and no more). So a lower minimum bet means we can have more attempts, but we need to win a lot more games to exit. Let’s look into this in more detail. Each successful round of roulette wins my minimum bet. I define a round as a series of rolls resulting in a win. This means:
- loss, loss, win
- loss, win
- loss, loss, loss, win
- win
are all rounds. If we start with £50, exit multiplier of 1.1x and minimum bet of £1, we need to win 5 total rounds to exit. If our minimum bet is £0.50 however, we need to win 10 total rounds. It seems like this doesn’t matter: a lower minimum bet is better. Let’s test this further just to be certain. In the below table, I look at the success rate if we start with £50 and aim to make £5 (exit multiplier = 1.1x). I vary the minimum bets:
| Minimum bet | Success rate |
|---|---|
| 0.10 | 92.3% |
| 0.25 | 90.6% |
| 0.50 | 89.5% |
| 0.75 | 93.6% |
| 1 | 88.9% |
| 2 | 89.3% |
| 4 | 86.3% |
At first these results really surprised me — especially the fact that our success rate peaked at £0.75. I’m really not sure why that is. I even increased the number of trials to 10,000 rather than 1,000 just to be certain. My suspicion is that £0.75 is the ideal in terms of number of rounds needed and number of possible losses. As our minimum bet decreases, we can afford to lose more times in a row (remember the log₂ formula), but we have to win many more games. The opposite occurs with a high minimum bet — with a minimum bet of £4 we can only lose 3 bets in a row, but we only need two rounds to exit.
The summary on the original index page was written by ChatGPT and modified by me for readability and formatting.
Related: 🎲 Dice, Catan, and D&D · 🔢 ESOP and dilution maths