flowchart TB entry["ENTRY<br/>experience Eᵢ · Eⱼ<br/>τ₀ · γₑ"] --> initial["entry strengths<br/>xᵢ,1 · xⱼ,1"] initial --> history["previous strengths<br/>xᵢ,t−1 · xⱼ,t−1"] history --> strength["current strengths<br/>xᵢ,t · xⱼ,t"] evolution["EVOLUTION<br/>age Aᵢ,t · Aⱼ,t · Δt<br/>β_g · β_d · q"] --> strength strength --> matchup["MATCH<br/>matchup mean ηₘ"] effects["surface effects<br/>uᵢ,s · uⱼ,s"] --> matchup surface["SURFACE<br/>τₛ"] -.-> effects matchup --> price["market log-odds<br/>yₘ"] observation["OBSERVATION<br/>margin Vₘ<br/>√r · γᵥ"] --> noise["observation SD<br/>√rₘ"] noise --> price class entry,evolution,surface,observation phase
WTA Rankings
Purpose
This model estimates WTA player strength over time and across surfaces, with uncertainty, by treating historical market probabilities as noisy observations of latent player strength. The aim of this model is not to beat the market, but to use public pricing history to create an accurate, holistic ranking of tour players available at any time. Current estimates are published on the WTA Rankings page.
System
The system consists of a single generative model, run in two stages.
- In the off-season, the model learns the shared parameters while integrating over the player states.
- During the season, the model fixes the learned global parameters and estimates latent player strengths before each day’s matches.
The player-state model retains 85.4% of the market’s signal, compared with 57.7% for standard Elo, without using the predicted match’s de-vigged probability or outcome.
The model does not separately represent injuries, rest, player-specific matchups or variation in court speed within a surface. Because it observes only the resulting price, it cannot distinguish these effects cleanly from strength: some may bleed into the latent player states, while the rest appears as observation noise.
Data
One observation per match: date \(t\), surface \(s\), players \(i\) and \(j\), their ages and prior experience, and decimal odds \(o_{i,m}\) and \(o_{j,m}\). These data were acquired for nearly every WTA match from 2019 to 2026. The database stores the source’s first listed bookmaker but not its identity; in practice, this was usually bet365.
The market odds are converted into implied log-odds using proportional de-vigging:
\[ \pi_{i,m}=\frac{1}{o_{i,m}}, \qquad p_{i,m}=\frac{\pi_{i,m}}{\pi_{i,m}+\pi_{j,m}}, \qquad y_m=\log\frac{p_{i,m}}{1-p_{i,m}}. \]
The raw bookmaker margin is \(v_m=\pi_{i,m}+\pi_{j,m}-1\). The model standardizes the margin using the mean and SD from its training seasons:
\[ V_m=\frac{v_m-\bar v_{\mathrm{train}}}{s_{v,\mathrm{train}}}. \]
All matches on a date are predicted before that date’s prices update the player states. Match outcomes are used only for evaluation.
Parameters
Player states
| \(x_{i,t}\) | = | player \(i\)’s overall strength at time \(t\) |
| \(\mathbf u_i\) | = | player \(i\)’s hard, clay and grass effects |
| \(z\) | = | all player states and surface effects |
Global parameters
Normal distributions are written as \(\operatorname{Normal}(\text{mean},\text{SD})\); \(\operatorname{Normal}_2\) uses a covariance matrix, and LogNormal priors use median and log-scale SD.
| \(\theta\) | = | all shared system parameters |
| \(\tau_0\) | = | population entry SD, in log-odds; \(\tau_0\sim\operatorname{LogNormal}(1.5,0.75)\) |
| \(\sqrt q\) | = | process SD, in log-odds per square-root year; \(\sqrt q\sim\operatorname{LogNormal}(0.5,1)\) |
| \(\sqrt r\) | = | base observation SD, in log-odds; \(\sqrt r\sim\operatorname{LogNormal}(0.25,0.75)\) |
| \(\tau_s\) | = | scale of between-player surface variation, in log-odds; \(\tau_s\sim\operatorname{LogNormal}(0.35,0.75)\) |
| \(\beta_g\) | = | annual pre-peak growth, in log-odds; \(\beta_g\sim\operatorname{LogNormal}(0.4,0.75)\) |
| \(\beta_d\) | = | annual post-peak decline, in log-odds; \(\beta_d\sim\operatorname{LogNormal}(0.15,1)\) |
| \(\gamma_e\) | = | change in log entry SD per standardized unit of prior experience; \(\gamma_e\sim\operatorname{Normal}(0,0.5)\) |
| \(\gamma_v\) | = | change in log observation SD per standardized unit of bookmaker margin; \(\gamma_v\sim\operatorname{Normal}(0,0.5)\) |
Model
Player evolution
A player enters the model as a draw from the tour population, where \(E_i\) is the training-standardized value of \(\log(1+n_i)\), and \(n_i\) is player \(i\)’s number of WTA appearances before entering the modeled panel:
\[ \log \tau_i=\log\tau_0+\gamma_e E_i, \qquad x_{i,1} \sim \operatorname{Normal}(0,\tau_i). \]
Because predictions are made one match ahead, fixed peak ages from 24 through 28 produced functionally identical out-of-sample loss. The live model fixes peak age at 24 and uses the piecewise-linear age path:
\[ a(A;\beta)= \begin{cases} \beta_g(A-24), & A<24,\\ -\beta_d(A-24), & A\geq24. \end{cases} \]
Player strength then evolves as:
\[ x_{i,t} \mid x_{i,t-1} \sim \operatorname{Normal}\!\left( x_{i,t-1}+a(A_{i,t};\beta)-a(A_{i,t-1};\beta), \sqrt{q\Delta t} \right). \]
Here, \(\Delta t\) is elapsed calendar time in years.
Each player has zero-sum random effects for hard, clay and grass, represented using two orthonormal Helmert contrasts.
\[ \mathbf c_i\sim\operatorname{Normal}_2(\mathbf 0,\tau_s^2\mathbf I_2), \qquad \mathbf u_i=\mathbf C\mathbf c_i, \]
\[ \mathbf C= \begin{pmatrix} 1/\sqrt 2 & 1/\sqrt 6\\ -1/\sqrt 2 & 1/\sqrt 6\\ 0 & -2/\sqrt 6 \end{pmatrix}, \qquad \mathbf 1^\mathsf T\mathbf u_i=0. \]
Match observations
For match \(m\), the expected market log-odds are the difference between the players’ overall strengths plus the difference between their surface effects:
\[ \eta_m = x_{i,t}-x_{j,t}+u_{i,s}-u_{j,s}, \]
Observation SD changes with bookmaker margin:
\[ \log\sqrt{r_m}=\log\sqrt r+\gamma_v V_m, \qquad y_m \mid z,\theta \sim \operatorname{Normal}(\eta_m,\sqrt{r_m}). \]
\(r_m\) determines how strongly the observed price updates the player states.
Estimation
Off-season global fit
Let \(y_{\mathrm{train}}\) contain the eligible market log-odds from the preceding seasons in a ten-season window. The 2026 fit uses every available season from 2019 through 2025. The shared parameters are estimated by maximum a posteriori probability while the player states are integrated out:
\[ \hat\theta = \underset{\theta}{\arg\max} \left\{ \log\int p(y_{\mathrm{train}}\mid z,\theta) p(z\mid\theta)\,dz +\log p(\theta) \right\}. \]
During the global fit, the likelihood averages over the player states; only the shared parameters are optimized.
In-season online fit
Given fitted parameters \(\hat\theta\), estimate the player states from prices observed before date \(t\):
\[ p(z_t\mid y_{<t},\hat\theta). \]
Carry the state distributions forward, predict a given set of matches, then condition on the new prices. This is implemented as an information-form Kalman update.
Results
The evaluation contains 6,381 matches from the 2024 and 2025 seasons. There are two benchmarks.
- Market: de-vigged price for the match being predicted.
- Elo: initializes every player at 1500, uses the conventional 400-point logistic scale with a fixed \(K=32\), and warms up on matches from 2021 through 2023. It maintains one rating across surfaces and uses only outcomes observed before that day.
The fraction of market signal retained is defined against a coin flip forecast:
\[ S = \frac{\operatorname{LL}(0.5)-\operatorname{LL}(\text{model})} {\operatorname{LL}(0.5)-\operatorname{LL}(\text{market})}. \]
| Surface | N | Market | Player-state | Elo |
|---|---|---|---|---|
| Log loss | ||||
| Overall | 6,381 | 0.581 | 0.597 | 0.628 |
| Hard | 3,951 | 0.586 | 0.600 | 0.633 |
| Clay | 1,663 | 0.561 | 0.579 | 0.617 |
| Grass | 767 | 0.596 | 0.620 | 0.630 |
| Brier score | ||||
| Overall | 6,381 | 0.199 | 0.206 | 0.220 |
| Hard | 3,951 | 0.202 | 0.207 | 0.222 |
| Clay | 1,663 | 0.191 | 0.199 | 0.215 |
| Grass | 767 | 0.206 | 0.216 | 0.220 |
| Signal retained | ||||
| Overall | 6,381 | 100.0% | 85.4% | 57.7% |
| Hard | 3,951 | 100.0% | 86.8% | 56.3% |
| Clay | 1,663 | 100.0% | 86.0% | 57.8% |
| Grass | 767 | 100.0% | 76.1% | 64.9% |
In a day-clustered bootstrap, the model’s mean log loss was 0.016 above the market [95% interval: 0.012, 0.021] and 0.031 below Elo [0.025, 0.038].
Surface effects are small next to overall player strength. Among the current top 500, their posterior means vary between players by roughly one-tenth as much as overall strength.
Validation
Win probabilities
Before each match, the model produces a win probability \(\hat p_m\). Outcome calibration is checked by regressing the observed result \(W_m\) on the model log-odds:
\[ W_m \sim \operatorname{Bernoulli}\!\left( \operatorname{logit}^{-1}\!\left[ \alpha+\lambda\operatorname{logit}(\hat p_m) \right] \right). \]
The intercept \(\alpha\) tests whether predictions are systematically high or low. The slope \(\lambda\) tests whether their spread is right: one is calibrated, above one means the model is too conservative, and below one means it is too extreme.
| Subset | Matches | Intercept [95% interval] | Slope [95% interval] |
|---|---|---|---|
| Overall | 6,381 | −0.01 [−0.07, 0.05] | 1.05 [0.98, 1.12] |
| 2024 | 3,167 | −0.02 [−0.10, 0.05] | 1.08 [0.99, 1.18] |
| 2025 | 3,214 | +0.01 [−0.07, 0.08] | 1.01 [0.91, 1.11] |
| Hard | 3,951 | −0.02 [−0.08, 0.05] | 1.02 [0.93, 1.11] |
| Clay | 1,663 | +0.02 [−0.08, 0.12] | 1.18 [1.05, 1.34] |
| Grass | 767 | −0.02 [−0.18, 0.14] | 0.91 [0.75, 1.07] |
The model’s win probabilities are well calibrated overall and within both seasons. Clay is the clearest departure: its slope above one means those predictions are somewhat too conservative. The grass interval is wider and still includes one.
Prediction standard deviations
Before each match, the model produces a distribution for the market log-odds rather than a point estimate. Its predictive variance is the sum of uncertainty in the latent matchup and fitted observation variance:
\[ s_m^2=\mathbf h_m^{\mathsf T}\mathbf P_t\mathbf h_m+r_m. \]
\(\mathbf P_t\) is the covariance of the current player states, while \(\mathbf h_m\) selects the two players and the surface for match \(m\). If the predictive SD \(s_m\) is calibrated, the standardized innovations
\[ e_m=\frac{y_m-\eta_m}{s_m} \]
have SD one and the prediction intervals attain their stated coverage.
| Surface | Innovation SD | 50% interval | 80% interval | 95% interval |
|---|---|---|---|---|
| Hard | 0.953 | 53.0% | 83.4% | 96.3% |
| Clay | 0.976 | 52.1% | 81.5% | 95.6% |
| Grass | 1.121 | 48.1% | 77.4% | 91.9% |
| Overall | 0.981 | 52.2% | 82.2% | 95.6% |
The pooled standardized innovations have mean +0.018. Overall, the predictive SD is close to calibrated. Hard and clay intervals are slightly too wide. Grass is the clearest failure: an innovation SD of 1.121 means prices moved farther than the model allowed, even though this is the surface with the smallest sample and weakest predictive performance.
Player-state uncertainty
Uncertainty in the live ratings was checked against the states obtained after seeing the rest of the season. The later revisions should fall within their expected 95% range about 95% of the time.
| Quantity | Observations | 95% coverage |
|---|---|---|
| Overall player state | 1,990 | 95.3% |
| Played-surface player state | 1,990 | 94.4% |
| Matchup contrast | 3,167 | 94.5% |
All three coverage rates are close to 95%.
Next steps
- Split drift states into chronic and acute, to capture correlated residuals on short-term windows.
- Evaluate the aging curve using multi-year forecasts without intermediate market updates.
- Revisit clay and grass calibration as more seasons accumulate.
- Split player strength into serve and return states using point-level data, then measure what they add to match prediction.