Scale matters – how to not track your betting results

This blog post is one of the half-done follow-ups to the staking post I did back in 2017. I wrote most of it at the same time as the original post but busy with work and other projects I never got to finishing it until now. What prompted me to finally publish was an interesting discussion on Twitter on how to best track your bets. The discussion fit well with what I had intended to say with the post so here you go, my first (and last) blog post of 2019.

Ok, so we start out with the same situation as last time: a punter has set out to bet on 10,000 coin flips. The big difference here is that he doesn’t know if the coin is fair or not, i.e. if he has an edge or not. He can choose to quit at any time though, so if he suspect he’s getting the worst of it he can just call it quits and save his time (and money). Speaking of time, manually flipping 10,000 coins is some task and as our punter has other things to do on most days, he’ll limit his betting to 10 flips a day. This will make the total series of 10,000 flips take 1,000 days, or roughly 2.7 years.

And now to the main point of this exercise. The result of each coin flip is recorded by a trustworthy third party and made available to all parties only when time for settlement. The bets should be settled on a regular basis but exactly how often is up to the punter: every day, week, month or year?

Now remember that our punter doesn’t know what his edge is, or even if he has one. What time frame should he choose to settle his bets on? In the real world, there’s probably no correct answer as this is mostly down to individual factors like total net worth, appetite for risk, tolerance of variance etc etc.

But, we can try to gain some insights by simulation. Using the coin flipping code from last time (ignoring the bankruptcy part) and adding on a function to compare the different settlement intervals we can run a simulation of the punter’s 10,000 coin flips to see how the results would look if he were to settle the score by each day, week, month or year.

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns


def coin_flips(n=10000,odds=1.97,bankroll=100,stake=1,bankrupt=False):
    Simulates 10000 coinflips for a single punter, betting at 1.97 odds,
    also calculates net winnings
    NEW: default bankroll and stake set at 100 and 1, respectively
    now also calculates if player went bankrupt or not
    # create a pandas dataframe for storing coin flip results 
    # and calculate net winnings
    df = pd.DataFrame()
    # insert n number of coinflips, 0=loss, 1=win
    df['result'] = np.random.randint(2,size=n)
    # calculate net winnings
    df['net'] = np.where(df['result']==1,stake*odds-stake,-stake)
    # calculate cumulative net winnings
    df['cum_net'] = df['net'].cumsum()
    # calculate total bankroll
    df['bankroll'] = df['cum_net'] + bankroll

    # if bankroll goes below the default stake, punter will stop betting
    # count times bankroll < stake
    df['bankrupt'] = np.where(df['bankroll']<stake,1,0)
    # count cumulative bankruptcies, with column shifted one step down
    df['bankruptcies'] = df['bankrupt'].cumsum().shift(1)
    # in case first flip is a loss, bankruptcies will be NaN, replace with 0
    # drop all flips after first bankruptcy
    if bankrupt:
        df = df[df['bankruptcies']==0]
    return df

def compare_scales(n=10000,odds=2.03,n_day=10,df=False):
    Puts coinflips on a timeline to
    10/flips per day, 30 days/month
    # if no df specified, create a new one
    if not df:
        # create df of a single punter's coinflips
        df = coin_flips(n,odds)
    # calc number of days
    days = n / n_day
    # ...weeks
    weeks = n / (n_day*7)
    # ...months
    months = n / (n_day*30)
    # and years needed
    years = n / (n_day*365)
    # insert days
    df['days'] = np.repeat(np.arange(1,days+1),n_day)
    # ...weeks
    df['weeks'] = np.repeat(np.arange(1,weeks+2),n_day*7)[:n]
    # and months
    df['months'] = np.repeat(np.arange(1,months+2),n_day*30)[:n]
    # and years
    df['years'] = np.repeat(np.arange(1,years+2),n_day*365)[:n]
    # list of scales
    scales = ['days','weeks','months','years']
    # figure, subplots
    f, axes = plt.subplots(2,len(scales),gridspec_kw={'height_ratios':[len(scales),1]},
                           sharey='row', figsize=(12,6))
    # reorder axes
    day_axes = [axes[0][0],axes[1][0]]
    week_axes = [axes[0][1],axes[1][1]]
    month_axes = [axes[0][2],axes[1][2]]
    year_axes = [axes[0][3],axes[1][3]]

    axes = [day_axes, week_axes, month_axes, year_axes]
    # loop through views, groupby and calc cum net,
    # plot cum net and 'view' net
    for s, ax in zip(scales,axes):
        # groupby, recalc cumnet
        group = df.groupby(s).sum()
        group['cum_net'] = group['net'].cumsum()
        # plot total cumulative net as line
        # and daily/weekly/monthly net as bar
        # clean up lower plot x axis

        # insert horizontal line at breakeven on both plots,
        # add label
        for i in ax:
            i.set_ylabel('Net profit')

    # fix the yearly y-tick labels to show whole years only

    # 'fix' layout
    # show plot

Running the compare_scales() function returns a graph of the simulation results. With the default 2.03 odds (an 1.5% edge on a fair coin) it could look like this (though this particular results graph was chosen to prove my point):


So the above graph is the results of the same 10,000 coin flips settled on different time frames, or scales. We can see that our punter ended up a clear winner, making a stable profit every year. But what if he’d been settling his bets by the end of every day? Would he, not sure whether he really had an edge, resist the urge to quit and do something else with his time (and money) after being roughly breakeven sometime after 100 days? We can never know of course, but by settling the bets every day our punter exposed himself to a lot of randomness, opening up for a very bumpy mental ride as he had to face many losing days. We know he had an edge, but he didn’t, and having to pay up again and again he might just had called it quits then and there. The same goes for the huge downswing leading up to 400 days. Would he have weathered the storm?

My point here is that if he’d chosen a longer time frame to settle on, he wouldn’t even know about his losing days. Settling by the end of each week would see him exposed to a lot more winning than losing settlements, and even more so if he’d chosen months or years. This would of course increase the likeliness of our punter staying in the game to eventually profit from his edge. On the other hand, it could have prevented him from realizing he was losing badly, having to face a very expensive settlement he could have avoided by settling more often.

Keeping track of your results is of course crucial to betting success as you want to know how, when, where and why you win or lose to be able to improve your underlying process, but if you expose yourself to too much randomness you risk clouding your judgment and make changes to what could be a profitable betting process, or maybe even quit – not realizing you actually had an edge.

I’m not saying you shouldn’t track your bets at all, and I’m not saying you should only look at your betting results once a year – what I am saying is that you should try to avoid making decisions based on randomness. It’s an easy mistake to make and I see it all the time on Twitter, from people touting their daily betting ROI to discussions about the Expected Goals score of an individual football match. It’s human nature, but you should still try to avoid falling into the trap.

Even if you have an edge, the results of any football match or betting day, week or month will likely be due to a lot of randomness and are most often irrelevant. What matters are the decisions behind the results.

Scale matters – how to not track your betting results

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s