In one sentence
A particle filter represents your belief about a hidden quantity as thousands of weighted guesses ("particles"), re-weighting them as evidence arrives and resampling so the cloud follows the truth.
How it works
In-play football is messy. The rate at which goals arrive depends on how open the game is, which you cannot see directly, and it changes with red cards, substitutions and the score. Neat formulas break down; a Kalman filter's assumption of smooth, bell-shaped noise does not fit.
A particle filter handles this by brute force. Scatter many guesses about the hidden state across the plausible range. When something happens, or does not happen, give each guess a weight equal to how well it explains what you saw. Guesses that fit well gain weight; poor ones fade.
Every so often you resample: copy the heavy particles, drop the light ones, and jiggle them slightly so the cloud can follow a state that keeps moving. Averages over the cloud give your estimates and prices.
The maths
At each step, each particle i has a state and a weight. The weight update is:
and any price is a weighted average across particles:
- xₜ⁽ⁱ⁾: particle i's guess at the hidden state, for example the goal rate per 90 minutes.
- wₜ⁽ⁱ⁾: particle i's weight, normalised so all weights add to 1.
- yₜ: what was observed in the latest interval (a goal, no goal, a red card).
- P(yₜ given xₜ⁽ⁱ⁾): how likely that observation was under particle i's guess.
In plain English: guesses that predicted what just happened become more influential, and your price is the influence-weighted average of all of them.
Worked betting example
A match kicks off with the market expecting a lively game. Over 2.5 goals is trading on Betfair; after 30 minutes at 0-0 it is available to lay at 6.60 (implied ≈ 15.2%). For clarity we use only 5 particles; a real filter uses thousands.
- Particles. Total goal rates per 90 minutes of 1.0, 1.5, 2.0, 2.5 and 3.0, each weight 0.20 (mean 2.0).
- Evidence. No goals in 30 minutes. The chance of that under a Poisson model is e to the power of minus (rate × 30 ÷ 90): 0.717, 0.607, 0.513, 0.435, 0.368.
- Re-weight. Multiply and normalise: weights become 0.272, 0.230, 0.195, 0.165, 0.139. The average goal rate falls from 2.0 to about 1.84.
- Price. Over 2.5 now needs 3 or more goals in the remaining 60 minutes (ignoring stoppage time). Averaging each particle's Poisson probability with the new weights gives ≈ 14.0%, fair odds ≈ 7.16. With the old equal weights it would be ≈ 16.4%, fair ≈ 6.11.
- Trade. Lay £10 at 6.60 (liability £56). Expected profit with 2% commission ≈ 0.860 × £10 × 0.98 minus 0.140 × £56 ≈ +£0.59. Thin, and only as good as the particle set and the Poisson assumption.
Where it's good
- In-play goal, point or wicket-rate tracking where the underlying tempo shifts.
- Markets with sudden jumps (goals, breaks of serve, falls in running) that a Kalman filter smooths over.
- Combining very different evidence types, such as traded prices plus live match events.
- Situations where the hidden state has two or more plausible "modes", like a player who may or may not be carrying an injury.
Limitations and pitfalls
- Computationally heavy. Thousands of particles updated every second can be too slow for fast in-play trading without careful coding.
- Particle collapse: after a surprising event almost all weight lands on a few particles, and the estimate becomes unreliable. Resample regularly and add small random jitter.
- The results are only as good as the model linking state to observations. A Poisson goal model misses game-state effects unless you build them in.
- Many settings (how much the state drifts, how many particles, jitter size) invite overfitting to past matches.
- Betfair in-play markets have a delay on bet placement and suspend at key moments, so a fast filter does not guarantee you get matched at the price you saw.
- Market prices already incorporate the same visible events; profitable gaps are small and brief.
How to build it
- filterpy, particles (Python) or custom numpy code; the core loop is short.
- Data: time-stamped match events and in-play prices for many past matches to tune settings.
- Practical tip: track the "effective number of particles" (one divided by the sum of squared weights) and resample when it falls below half your total.
Related methods
- Kalman filter – the fast, exact choice when noise is smooth and normal.
- Bayesian updating – the principle behind every re-weighting step.
- Monte Carlo simulation – the same sampling idea, used to price outcomes.
- Hidden Markov models – exact filtering when the hidden state has a few discrete values.
- Poisson processes – the goal-arrival model used in the example.