Gambling Problem

The problem is described below:

For the match Limp Stoners vs Exmouth Breathers the two bookmakers A and C offer different odds,

Stoners WinDrawBreathers Win
A4/1 (5.00)3/1 (4.00)2/3 (1.67)
C3/1 (4.00)2/1 (3.00)1/1 (2.00)

You have £100. How do you have to place your bets in order to maximize guaranteed profit no matter what the outcome of the game?

Noticing,

  • One is allowed to put money on different outcomes simultaneously. So, you can bet £50 on Stoners and £20 on Draw at A, and £30 on Breathers at C.
  • The numbers for the odds mean that, for example, if you bet £1 on Stoners at BrokeLads you will get £5.00 back (your own £1 and £4 winning). The fraction format specifies how much you would win if you bet £1, the decimal format specifies how much you would get back if you bet £1 (so, it’s the same as the fraction + 1.

Thought & Solution

Here are my thought and solution.

Given that the requirement in the description, no matter what the outcome, which suggests that no matter Stoners win, Breathers win or ended up in tie, the profit is maximised and the same for them. (If we use mathematical expectation, then the approach will be different.)

Also, if there multiple bookmakers, then for the same outcome, we always choose the bookmaker with highest odds. For example, for the outcome that Stoners win, odds provided by bookmaker A is 5 versus 3 at bookmaker C, thus we choose bookmaker A to put our stake on Stoners win.

Let's use $x_1, x_2, x_3$ to denote the stakes we put on Stoners Win, Draw and Breathers Win respectively. And the total amount of available money is $\mathcal{M}=100$. Then obviously, the first constrain is $\sum_{i=1}^3=x_1+x_2+x_3=\mathcal{M}=100$.

Another two equations we can find are shown below.

$$\begin{align} \left\{ \begin{aligned} 5*x_1 - 4*x_2 + 0*x_3 &= 0\\ 5*x_1 + 0*x_2 - 2*x_3 &= 0 \end{aligned} \right.\\ \end{align} $$

Because no matter what the outcome, our profit is maximised and the same. If Stoners win, our income is $5x_1-100$, if the result is draw, then profit is $4x_2-100$. And them should be equal, thus to say we have the follow equation,

\begin{align} \begin{aligned} &5*x_1-100 = 4*x_2-100\\ &5*x_1 - 4*x_2 + 0*x_3 = 0 \end{aligned} \end{align}

As for $5*x_1+0*x_2-2*x_3=0$, it's basically the same. If Stoners win, our income is $5x_1-100$, if the result is Breathers win, then profit is $2x_3-100$. Then we have the follow equation,

\begin{align} \begin{aligned} &5*x_1-100 = 2*x_3-100\\ &5*x_1 + 0*x_2 - 2*x_3 = 0 \end{aligned} \end{align}

As a matter of fact, there's a third equation, $0*x_1+4*x_2-2*x_3=0$. But if we take these 3 equations to solve this problem with linear algebra, the matrix will be singular matrix.

Now we have 3 equations, we can rewrite them in matrix form.

\[\begin{bmatrix} 1 & 1 & 1\\ 5 & -4 & 0\\ 5 & 0 & -2 \end{bmatrix}\begin{bmatrix}x_1\\ x_2\\ x_3 \end{bmatrix}=\begin{bmatrix}100\\ 0\\ 0 \end{bmatrix}\]

We now have form of $\mathbf{A}\mathbf{x}=\mathbf{B}$, then left multiple $\mathbf{A}^{-1}$ at both sides we get $\mathbf{A}^{-1}\mathbf{A}\mathbf{x}=\mathbf{A}^{-1}\mathbf{B}$, which simplifies to $\mathbf{x}=\mathbf{A}^{-1}\mathbf{B}$.

We can write this solution in Python with numpy. And we can expand the number of choices beyond 3.

#!/usr/bin/python3
# -*- coding: utf-8 -*-

import numpy as np

def solve(odds=np.zeros((0,0)), constraint=0):
    """Solve gamble-like problem
    @param odds: np.array with shape (num_bookmakers, num_choices)
    @param constraint: total amount of money
    
    @return odds_indice,stakes,winnings
    odds_indice: np.array with shape (num_choices,) the value indicates which bookmaker to put stake on
    stakes: np.array with shape (num_choices,) the value indicates the amount of stakes
    winnings: the amount of winnings
    """
    # using float64 type, to get an accurate result when doing matrix inverse
    odds = odds.astype('float64')
    # get number of choices
    _, num_choices = odds.shape
    # find out which bookmaker we should choose for each choice
    odds_indice = np.argmax(odds, axis=0)
    # get the maximum odds among available bookmakers for each choice
    odds = np.max(odds, axis=0)
    
    # Eq. $\sum_{i=1}^nx_i=\mathcal{M}$
    A = np.ones((1, num_choices))
    B = np.array([constraint])
    
    # fill in the rest equations
    for i in range(0, num_choices - 1):
        # prefixed with $i$ zeros
        equation = np.zeros((1, i))
        # just pick 2 consecutive odds
        # positive for the first one, negative for the second one
        equation = np.append(equation, [odds[i], -odds[i+1]])
        # resize to (1, num_choices), filling zeros
        equation.resize((1, num_choices))
        # concatenate this equation to A
        A = np.concatenate((A, equation))
    # the result of all the equations we generate in the for loop are 0s
    B.resize(num_choices, 1)
    # solve $\mathcal{x}=\mathcal{A}^{-1}\mathcal{B}$
    stakes = (np.linalg.inv(A) @ B).flatten()
    
    # compute winnings
    winnings = stakes[0] * odds[0]
    return odds_indice, stakes, winnings

if __name__ == '__main__':
    odds_indice, stakes, winnings = solve(np.array([[5, 4, 1.67], [4, 3, 2]]), 100)
    for i in range(stakes.shape[0]):
        print("Place {:.4f} on {} bookmaker on choice {}, winnings {:.4f}".format(stakes[i], odds_indice[i], i, winnings))

And the script will have the following output,

Place 21.0526 on 0 bookmaker on choice 0, winnings 105.2632
Place 26.3158 on 0 bookmaker on choice 1, winnings 105.2632
Place 52.6316 on 1 bookmaker on choice 2, winnings 105.2632

Leave a Reply

Your email address will not be published. Required fields are marked *

two − one =