The Geometry Hiding Inside Your Betfair Screen

Every set of odds on Betfair describes a point in space. If that point is inside a particular shape — a polytope — the prices are consistent with reality. If the point is outside, someone is offering you free money.

This post explains the shape, why it matters, and how to tell whether the prices you're looking at live inside it or not.


The Problem

You open Betfair and see two markets for Arsenal vs Chelsea:

Market Selection Implied probability
Match Odds Arsenal 0.45
Match Odds Draw 0.27
Match Odds Chelsea 0.28
Both Teams to Score Yes 0.55
Both Teams to Score No 0.45

Each market sums to 1.00. Everything looks fine. But are these two markets consistent with each other?

Could there actually exist a world where Arsenal win 45% of the time, draws happen 27% of the time, and both teams score 55% of the time? Or is there a hidden contradiction — and therefore a guaranteed profit — lurking in the combination?

To answer this, you need to understand the geometry of valid outcomes.


The Idea: Valid Outcomes Form a Shape

Convex sets — the simplest version

Start with a single horse race. Three runners: Altior, Buveur d'Air, and Coneygree. Any valid probability assignment looks like this:

$$ (p_A, p_B, p_C), \quad p_i \geq 0, \quad p_A + p_B + p_C = 1 $$

This is a triangle in three-dimensional space — the probability simplex. Every point inside the triangle represents a valid set of beliefs about who will win. Every point outside it is nonsense (negative probabilities, or probabilities that don't add up).

This triangle is a convex set. A set is convex if, whenever you pick two points inside it and draw a straight line between them, every point on that line is also inside. In betting terms: if you take two valid probability distributions and average them, you get another valid probability distribution. You can't "mix" two coherent views of a race and accidentally produce an incoherent one.

Vertices — the corners of the shape

The triangle has three corners:

These corners are called extreme points or vertices. They represent the most extreme possible beliefs — absolute certainty about one outcome. Every other probability distribution is a mixture of these extremes. If you believe Altior has a 50% chance and Buveur d'Air has a 30% chance, your belief is a weighted blend of the three corner scenarios.

A convex hull is the smallest convex set containing a given collection of points — like stretching a rubber band around a set of nails on a board. The probability simplex is the convex hull of the three deterministic outcomes.

From triangles to polytopes

A polytope is a convex set with flat sides and sharp corners — a higher-dimensional version of a triangle, square, or cube. The key property: it can be described in two equivalent ways.

From the corners outward (V-representation): list all the vertices and take their convex hull. "These are the extreme scenarios; everything valid is a mixture of them."

From the walls inward (H-representation): list a set of linear inequalities (flat walls) and intersect them. "These are the rules; everything valid satisfies all of them."

Both descriptions give you the same shape. The corners tell you what the extreme outcomes are. The walls tell you what constraints the prices must satisfy.

Faces and facets — the walls that matter

A polytope has a hierarchy of boundary structure:

Dimension Name What it is in betting
0 Vertex A deterministic outcome (one horse wins for certain)
1 Edge A mixture of exactly two extreme outcomes
$d - 1$ Facet A single no-arbitrage constraint, held exactly tight

Facets are the most important. Each facet is one wall of the polytope — one inequality that valid prices must satisfy. When your prices sit exactly on a facet, one specific no-arbitrage condition is razor-tight. Push past it, and you've crossed the boundary: there's a guaranteed profit available.


The Marginal Polytope: Where Multi-Market Gets Interesting

For a single win market, the shape is just the triangle (or its higher-dimensional analogue). Checking consistency is easy — do the implied probabilities sum to 1?

The real power of this framework appears when you have multiple linked markets. Back to Arsenal vs Chelsea:

Market 1: Match Odds — Home (H), Draw (D), Away (A) Market 2: Both Teams to Score — Yes (Y), No (N)

The joint outcome space has $3 \times 2 = 6$ elements:

Outcome Match result BTTS Feature vector
$\omega_1$ Home win Yes $(1,0,0,1,0)$
$\omega_2$ Home win No $(1,0,0,0,1)$
$\omega_3$ Draw Yes $(0,1,0,1,0)$
$\omega_4$ Draw No $(0,1,0,0,1)$
$\omega_5$ Away win Yes $(0,0,1,1,0)$
$\omega_6$ Away win No $(0,0,1,0,1)$

The marginal polytope $\mathcal{M}$ is the convex hull of these 6 vertices. A vector of implied probabilities $(\mu_H, \mu_D, \mu_A, \mu_Y, \mu_N)$ is consistent — meaning there exists some valid joint probability distribution over match outcomes — if and only if the vector lies inside $\mathcal{M}$.

This matters because checking each market independently is not enough. Consider an extreme example:

Both markets sum correctly. But if the home team wins (99% of the time), there's at least one goal, so "Under 0.5 Goals" is impossible when Home wins. The maximum probability of Under 0.5 Goals is at most $P(\text{Draw}) + P(\text{Away}) = 0.01$. But the market says 0.99. Contradiction. The point is outside the polytope. There is a guaranteed profit.

You would never find this by checking each market in isolation.

Why it explodes

For a single football match with two markets, the polytope has 6 vertices — manageable. But for a Saturday accumulator across 10 matches, each with 3 outcomes, the joint space has $3^{10} = 59{,}049$ vertices. For 15 matches: over 14 million. You cannot list them. You need algorithms — integer programming, Frank–Wolfe methods — that exploit the structure of the polytope without enumerating its corners.


In Practice: The Membership Test

The practical question is: given a vector of exchange prices, is the implied probability vector inside the marginal polytope?

If yes → prices are coherent. No riskless profit. If no → prices are incoherent. A Dutch book (guaranteed profit) exists.

For a single market, the test is trivial: do the implied probabilities sum to 1? If the sum is less than 1 on the back side, you have a back arbitrage. If the sum is greater than 1 on the lay side, that's the bookmaker's margin.

For multiple linked markets, the test requires solving a linear program: can you find non-negative weights over the joint outcomes that reproduce the observed marginal probabilities?

"""
Polytope membership test for two linked markets.
Checks whether implied probabilities from exchange prices
are consistent with any valid joint distribution.
"""

import numpy as np
from scipy.optimize import linprog


def check_consistency(
    market_1_probs: list[float],
    market_2_probs: list[float],
) -> tuple[bool, float]:
    """
    Test whether two markets' implied probabilities
    are jointly consistent.

    Returns (is_consistent, violation_magnitude).
    violation_magnitude > 0 means arbitrage exists.
    """
    n1 = len(market_1_probs)
    n2 = len(market_2_probs)
    n_outcomes = n1 * n2  # joint outcomes

    # Build feature matrix: each column is a joint outcome
    # Rows: market_1 indicators, then market_2 indicators
    A_eq = np.zeros((n1 + n2, n_outcomes))
    for i in range(n1):
        for j in range(n2):
            col = i * n2 + j
            A_eq[i, col] = 1.0           # market 1
            A_eq[n1 + j, col] = 1.0      # market 2

    # Target marginals
    b_eq = np.array(market_1_probs + market_2_probs)

    # Solve: find p >= 0 such that A_eq @ p = b_eq
    # (We also need sum(p) = 1, but if both markets
    #  sum to 1, this is automatically satisfied.)
    result = linprog(
        c=np.zeros(n_outcomes),   # no objective
        A_eq=A_eq,
        b_eq=b_eq,
        bounds=[(0, None)] * n_outcomes,
        method="highs",
    )

    if result.success:
        return True, 0.0
    else:
        # Infeasible — compute violation magnitude
        # (distance from the marginal polytope)
        residual = np.sum(np.abs(b_eq - A_eq @ np.zeros(n_outcomes)))
        return False, residual


# Example: Arsenal vs Chelsea
consistent, violation = check_consistency(
    market_1_probs=[0.45, 0.27, 0.28],  # H, D, A
    market_2_probs=[0.55, 0.45],         # BTTS Yes, No
)
print(f"Consistent: {consistent}")

# Extreme example — should be inconsistent
consistent, violation = check_consistency(
    market_1_probs=[0.99, 0.005, 0.005],  # H, D, A
    market_2_probs=[0.99, 0.01],           # Under 0.5, Over 0.5
)
print(f"Consistent: {consistent}")
# Under 0.5 requires no goals, but Home win (99%) needs ≥1 goal

When the LP is infeasible, its dual solution hands you the arbitrage portfolio directly: a set of bets with guaranteed profit regardless of the outcome. The dual vector is the separating hyperplane — the mathematical proof that the prices are incoherent, expressed as a specific trading strategy.


The Takeaway


References

  1. Rockafellar, R. T. (1970). Convex Analysis. Princeton University Press. — The foundational treatment of convex sets and their properties.

  2. Boyd, S. & Vandenberghe, L. (2004). Convex Optimization. Cambridge University Press. — Chapter 2 on convex sets and the separating hyperplane theorem. Available free online.

  3. Wainwright, M. J. & Jordan, M. I. (2008). "Graphical Models, Exponential Families, and Variational Inference." Foundations and Trends in Machine Learning, 1(1–2), 1–305. — The authoritative reference on marginal polytopes, showing that the membership problem is co-NP complete in general.

  4. Abernethy, J., Chen, Y. & Vaughan, J. W. (2013). "Efficient Market Making via Convex Optimization, and a Connection to Online Learning." ACM Transactions on Economics and Computation, 1(2). — Connects marginal polytopes directly to automated market making and prediction markets.

  5. de Finetti, B. (1931). "Sul significato soggettivo della probabilità." Fundamenta Mathematicae, 17, 298–329. — The founding paper on the Dutch book argument: incoherent probabilities (points outside the polytope) guarantee losses.