Skip to content

Do the bookmakers get Scottish football right?

Twenty-four seasons of Bet365 prices on 9,646 Scottish league matches. The odds are remarkably accurate in the middle, the margin has swung from 12% to 6.5% and back up, and backing outsiders is by far the worst bet.

Intermediate

Contents

The research question

Throughout this site the bookmakers have been the benchmark: in is accuracy the right score? and logistic regression they beat every model. But how good are their prices really? Three questions:

  1. The margin. How much more than 100% do their three prices add up to, and has it changed?
  2. Calibration. When the odds say something has a 30% chance, does it happen 30% of the time?
  3. The favourite–longshot bias. Is some kind of bet consistently worse value than others?

The dataset

Every Scottish Premiership and Championship match from 2002/03 to 2025/26 that has Bet365 prices in the football-data.co.uk files: 9,646 matches, and so 28,938 prices, one each for the home win, draw and away win. The two seasons before 2002/03 have no prices. The prices are those the files record before kick-off; they're not necessarily the final price before the match.

The method

Turning odds into chances. Decimal odds of 4.0 pay £4 for every £1 staked, so they imply a chance of 1 ÷ 4 = 25%. For any match, the three implied chances add up to more than 100%:

$$\begin{aligned} \text{margin} = \;&\frac{1}{\text{home odds}} + \frac{1}{\text{draw odds}} \\ &+ \frac{1}{\text{away odds}} - 1 \end{aligned}$$

In plain football

  • Take 1.80 home, 3.60 draw, 4.50 away. Their implied chances are 55.6%, 27.8% and 22.2%, which add up to 105.6%.
  • The extra 5.6% is the bookmaker's margin, or overround: their built-in edge.
  • To get fair chances that add up to 100%, divide each by 1.056: 52.6%, 26.3% and 21.1%.

Calibration. Group all 28,938 prices by their fair chance (0–10%, 10–20% and so on) and compare the average chance with how often those results actually happened, as in evaluating prediction models.

Returns. Group the prices by the odds themselves and work out what £1 on every one of them would have returned. A perfectly priced book with no margin returns exactly £1 on average; the margin should cost every band about the same. If some bands lose much more than others, that's a bias.

Results

The margin

The average margin on each match's three prices. It halved around 2008, held at about 6.6% for twelve seasons, and has crept back up since 2020.

In the early 2000s the three prices added up to about 112%. From 2008/09 to 2019/20 it was steady at about 106.6%. Since 2020/21 it has risen again, to 109.0% in 2025/26. Over the whole period it averaged 8.1%.

Calibration

Each dot is a group of prices: along, what the odds said; up, how often it happened, with its 95% range. On the diagonal is perfect. The middle is on it; the gold ends are off it, in opposite directions.
The odds said Prices It happened 95% range
7.5% 940 5.1% ±1.4
15.8% 3,350 15.1% ±1.2
26.0% 11,771 26.3% ±0.8
35.1% 5,327 34.6% ±1.3
44.6% 3,454 43.1% ±1.7
54.6% 2,042 56.4% ±2.2
64.6% 989 65.3% ±3.0
74.7% 802 79.7% ±2.8
82.5% 263 86.3% ±4.2

From 10% to 70%, where more than nine prices in ten sit, the odds are remarkably accurate: every group is within about a point and a half of what happened, and inside its range. The exceptions are at the ends, and they point in opposite directions:

  • Longshots happen less often than the odds say. Priced as a 7.5% chance, they came in 5.1% of the time.
  • Heavy favourites win more often than the odds say. Priced at 74.7%, they won 79.7%; priced at 82.5%, they won 86.3%.

The favourite–longshot bias

That pattern has a name, the favourite–longshot bias, and it shows up plainly in what £1 on every price returns:

Every band loses, because of the margin. But the short prices lose least and the long ones lose most: backing outsiders at 8 to 15 lost about 35p in every pound.
Odds Bets Return per £1 95% range
up to 1.5 1,742 −2.9p ±2.6
1.5 to 2 3,212 −7.2p ±3.0
2 to 3 7,131 −9.2p ±2.7
3 to 5 12,978 −6.2p ±2.7
5 to 8 2,524 −15.6p ±8.0
8 to 15 1,059 −34.7p ±14.7

Backing the heaviest favourites lost less than 3p in the pound; backing outsiders at 8 to 15 lost nearly 35p. The margin isn't spread evenly: it falls far more heavily on the long prices. One common explanation is that punters overrate their chances of a big win, so bookmakers can shorten the outsiders' odds without losing their custom.

A warning about small samples

The long-odds bands are small and noisy. The 8-to-15 band has only 73 winners in 1,059 bets, so its range is ±14.7p; prices longer than 15 (292 bets, 15 winners) are left out of the chart altogether because their range is ±42p. A single long shot coming in moves those numbers a lot. The direction is clear; the exact size is not.

Limitations

  • One bookmaker. These are Bet365's prices; other firms and the betting exchanges differ, often with smaller margins.
  • Not the closing price. The files record prices collected before kick-off, not necessarily the last ones; late team news moves odds.
  • Scaling away the margin is approximate. Dividing each chance by the total assumes the margin is spread evenly, which the favourite–longshot bias shows it isn't.
  • Two divisions, one country. The Championship carries a bigger margin than the Premiership (8.8% against 7.5% on average); results in other leagues may differ.

Conclusion

The bookmakers get Scottish football very nearly right. Across the range where most prices sit, what the odds say happens, to within a point or so, which is why they keep beating the models on this site. Their edge comes from two places: a margin of 6.5% to 12% depending on the era, and pricing it unevenly, so that the outsiders fans love to back are the worst value in the book. If you're going to bet, the data says the favourites cost you least, and nothing on these prices makes a profit.

These figures are for analysis and education, not betting advice.

Reproduce the analysis

The results and odds files are published by football-data.co.uk. Download the Premiership (SC0) and Championship (SC1) files for each season from 2000/01 to 2025/26 and save each under its own name, such as SC0_2425.csv and SC1_2425.csv; they aren't rehosted on this site. Then:

import csv
from collections import defaultdict
from math import sqrt

bets, margins = [], defaultdict(list)  # one bet per outcome per match: (odds, fair probability, won?)
for y in range(2000, 2026):
    s = f"{y % 100:02d}{(y + 1) % 100:02d}"
    for div in ("SC0", "SC1"):  # Premiership and Championship
        with open(f"{div}_{s}.csv", encoding="latin-1") as f:
            for r in csv.DictReader(f):
                try:
                    odds = {k: float(r["B365" + k]) for k in "HDA"}
                except (KeyError, ValueError):
                    continue  # no Bet365 prices for this match
                if r.get("FTR") not in odds or min(odds.values()) <= 1:
                    continue
                book = sum(1 / o for o in odds.values())  # adds up to more than 1: the excess is the margin
                margins[s].append(book - 1)
                for k, o in odds.items():
                    bets.append((o, (1 / o) / book, r["FTR"] == k))

print(f"{len(bets) // 3} matches with odds, {len(bets)} prices")
print("margin by season:", ", ".join(f"20{s[:2]}/{s[2:]} {sum(m) / len(m):.1%}" for s, m in sorted(margins.items())))

print("calibration: what the odds said against what happened")
edges = [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 1.01]
for lo, hi in zip(edges, edges[1:]):
    group = [b for b in bets if lo <= b[1] < hi]
    said = sum(p for _, p, _ in group) / len(group)
    happened = sum(w for _, _, w in group) / len(group)
    print(f"  {lo:.0%}-{min(hi, 1):.0%}: {len(group):5} prices, said {said:.1%}, happened {happened:.1%} (±{1.96 * sqrt(happened * (1 - happened) / len(group)):.1%})")

print("return from £1 on every price in each band")
for lo, hi in [(1, 1.5), (1.5, 2), (2, 3), (3, 5), (5, 8), (8, 15), (15, 1000)]:
    group = [b for b in bets if lo <= b[0] < hi]
    back = [o * w for o, _, w in group]  # what comes back from £1
    mean = sum(back) / len(back)
    margin = 1.96 * sqrt(sum((x - mean) ** 2 for x in back) / len(back) / len(back))
    print(f"  odds {lo} to {hi}: {len(group):5} bets, {mean - 1:+.1%} (±{margin:.1%})")

Further reading

Get new pieces by email

An email when something new is published, and the occasional update. Unsubscribe in one click. How your email is used.