1 · Target variable and why scoring shots, not points
The response modelled is scoring shots (goals + behinds) per team per game, not total points. Points are a deterministic transform of two count processes — goals (×6) and behinds (×1) — whose ratio (accuracy) is high-variance, weakly autocorrelated, and largely venue/weather driven rather than a stable team skill. Modelling scoring shots isolates the repeatable signal (a team's ability to generate scoring opportunities) from the noisy conversion step, which is reintroduced separately at the conversion stage. Empirically, scoring-shot generation is far more stable across a season than goal accuracy, so a model on shots has a lower out-of-sample variance than a direct points model.
2 · Estimator: time-decayed Poisson GLM
Each team-game scoring-shot count is modelled as conditionally Poisson with a log-linear mean:
Team and opponent enter as fixed effects, giving a Dixon-Coles-style attack/defence decomposition specialised to AFL. The design is deliberately a GLM rather than a mixed model: with ~3,000 games and 18 clubs the fixed-effect estimates are well-identified, partial pooling buys little, and the GLM keeps the walk-forward refit cheap (sub-second), which matters when refitting every game across an 11-season backtest.
Time decay
Observations are weighted by an exponential kernel with a 180-day half-life, truncated at a 730-day window:
This is a soft alternative to a hard recency cutoff. The half-life was selected by grid search over {90, 120, 180, 270, 365} days against walk-forward margin MAE, not by AIC on the training fit — in-sample likelihood monotonically prefers longer windows (more data) while out-of-sample error is minimised at 180 days, the classic bias-variance turning point. The 730-day truncation simply zeroes negligible weights to keep the design matrix small.
3 · Covariates and their justification
Travel — log distance
log_dist = log(km + 1). Log scale because the marginal effect of distance is strongly concave: the difference between 0 and 500 km (interstate vs local) matters far more than 2,500 vs 3,000 km (both long-haul). The +1 handles the home-team zero-distance case. Distances are great-circle (haversine) from each club's home base to the venue; for venues absent from the precomputed table the engine falls back to a live haversine computation so the covariate is never missing.
Venue experience
Rolling proportion of a team's last-2-years games played at the fixture venue. Captures familiarity effects (ground dimensions, surface, interchange positioning) that are not collinear with travel — e.g. a Tasmanian "home" game for Hawthorn carries low travel but also low venue experience.
Season progression and finals
round_frac (continuous) absorbs league-wide scoring drift across a season; is_final flags the lower-scoring, tighter finals environment. Both were retained only because they improved walk-forward error, marginally.
4 · Player-rating differential — the player layer
Player effects enter as a single scalar per game: the differential in aggregated player rating between the two named teams, on a 20-game rolling basis. The construction:
Player-game data (2016–) is decomposed by position group — forward, midfield/ruck, back (bench/sub/emergency excluded) — and ~50 candidate per-player rolling statistics were screened. A LASSO-penalised Poisson regression (cv.glmnet, 10-fold CV) against team scoring shots retained 29 of them, with the heaviest weights on scoreLaunches, contestDefLosses, tacklesInside50, scoreInvolvements, marksOnLead, and f50GroundBallGets — i.e. chain-initiation and forward-half pressure metrics dominate, consistent with the scoring-shot target.
However, in walk-forward testing the bespoke LASSO composite and the official AFL Player Ratings produced identical margin MAE (26.8) despite the composite correlating better with scoring shots in-sample (0.339 vs 0.179). This is a textbook in-sample/out-of-sample divergence: the richer composite overfits the training correlation. The production model therefore uses the simpler, more robust rating-points differential, aggregated over the most recent 20 games of available players and differenced against the opponent. Window length (3/5/10/15/20) and position split (all vs forward/mid/back separately) were both grid-searched; all-positions, 20-game won (MAE 26.7 vs 26.9 baseline). Position-specific splits underperformed — the differencing already nets out positional structure, and splitting just thins each estimate.
5 · Score conversion
Projected scoring shots are mapped to points via a rolling 2-year league conversion rate (goals per scoring shot ≈ 0.527), applied as points = 6·(SS·conv) + 1·(SS·(1−conv)). A binomial conversion model was fitted but added no walk-forward accuracy over the league rate, so the simpler constant is used.
6 · Simulation: Gaussian copula with NB marginals
Point estimates are insufficient for staking — Kelly needs a distribution. Two complications rule out independent Poisson draws: (i) team scores within a game are negatively correlated (ρ ≈ −0.33 empirically — strong defence suppresses the opponent and vice versa), and (ii) scoring-shot counts are overdispersed relative to Poisson.
Both are handled by a Gaussian copula joining two Negative Binomial marginals (dispersion θ ≈ 35.7). The copula imposes the −0.33 rank correlation while each marginal carries the correct overdispersed count shape; 10,000 draws give the full joint score distribution, from which win probability, margin quantiles and cover probabilities are read directly.
Why this and not alternatives
A bivariate Poisson (shared-component) construction can only represent positive correlation, so it cannot capture the observed negative dependence — disqualifying. A full multivariate count model (e.g. copula-GARCH or a hierarchical Bayesian joint model) was tested via brms but produced marginally worse walk-forward error at orders of magnitude more compute. The Gaussian copula is the minimal structure that captures both stylised facts, and its single correlation parameter is stable across seasons.
6b · Iterative ratings: margin-Elo, and why we blend
Alongside the GLM we run a margin-aware Elo. Each team carries a single rating updated after every game by K·mult·(actual − expected margin), with a home-ground constant and a 25% season regression toward the mean to absorb list turnover. The rating difference is mapped to points, then a fitted linear layer adds the same travel, venue-experience and venue-performance signals the GLM uses.
The GLM (batch re-fit, fixed effects) and Elo (incremental, recency-driven) make different errors. Neither dominates across the season, and a paired test finds no phase where one is significantly better. Because their errors are partly independent, a fixed 0.6 GLM / 0.4 Elo blend beats either alone on walk-forward margin MAE — the only configuration that produced a durable improvement across both the full 2016–2026 record and the 2023+ holdout.
7 · Betting edge: cover-probability model
For each fixture the projected margin is compared with each bookmaker's handicap line. Rather than a fixed gap threshold, the historical relationship between the model-market gap and the realised cover outcome is estimated with a logistic regression:
Expected value follows as EV = P(cover)·odds − 1, computed per bookmaker line so the engine backs the genuinely best-value price. A single pooled logistic model maps the model-vs-line gap to a calibrated cover probability. In-sample the data showed a home/away asymmetry (home value bets covering better than away), and we trialled separate side-specific cover models — but on a strict held-out test they failed to generalise (no calibration gain, worse out-of-sample ROI), a classic overfit. The pooled model is retained as the honest, robust choice.
8 · Staking: fractional Kelly
Stake fraction is half-Kelly, capped:
Full Kelly maximises long-run log-growth but assumes the probabilities are exact; with estimated P it is badly over-levered and its drawdowns are intolerable (backtest peak-to-trough ≈ 37%). Half-Kelly captures ~75% of the growth at roughly a quarter of the variance; the 3% hard cap bounds single-bet exposure to model error. Bankroll compounds, so stake scales with realised results. A 5% EV floor suppresses marginal-edge bets where the cover-probability estimate is least reliable.
9 · Validation protocol
All tuning used expanding-window walk-forward evaluation with strict temporal ordering — every prediction uses only data available before that game, refitting as the window advances, after an 810-game burn-in. No k-fold, no random splits: in a time series with drifting team strength, random CV leaks future information and flatters the model. Headline out-of-sample margin error is MAE 26.7, RMSE 33.8.
The betting edge was validated on a held-out 2023–2026 slice never used in tuning: at gap ≥ 6, 176 bets covered at 61.9% against a 52.6% break-even (1.90 odds). A one-sided exact binomial test gives p = 0.008 — the edge is unlikely to be sampling noise. Quarter- and half-Kelly bankroll simulations on the same slice grew a $5,000 base by ~87–119% with max drawdown 17–33% depending on aggressiveness.
Rejected approaches
For completeness, the following were tested and discarded on walk-forward grounds: blowout-capped responses (worse, 27.2+), total/margin decomposition (identical), negative-binomial GLM in place of Poisson (identical MAE — overdispersion matters for the distribution, captured at the copula stage, not the mean), LightGBM and a GLM/GBM ensemble (worse, 28.5), days-rest and short-break flags (no gain), head-to-head history (no gain), and using the market line itself as a predictor (no MAE gain, marginal RMSE). The market-line null result is informative: it indicates the model is not simply re-deriving the bookmaker line, which is necessary for a genuine edge.