This project began with a machine-learning model that works alongside two chess engines, Lc0 and
Stockfish, to predict the probability of outcomes in a chess game.
Polymarket runs a market on the winner of the Chess Olympiad, a two-week team tournament between countries.
For this market, I model the tournament as a whole, based on the live position of the underlying games throughout the
tournament.
This dashboard shows our model's underlying probabilities per team, and compares them against Polymarket's
prices. Those prices are thin enough that my own trades move them — see Polymarket below.
Teams, not players. 206 national teams. Each team fields four players per round out of a squad of five.
A round = one match per team. In a match the two teams' players pair off on four boards, board 1 being
each side's strongest. Each board is one game.
A game scores 1 for a win, ½ for a draw, 0 for a loss. Add up the four boards; the team with more wins the
match.
A match scores match points (MP): win = 2, draw = 1, loss = 0. The team with the most MP after 11 rounds wins
the Olympiad. Game points only matter as a tie-break.
Swiss system. Nobody is knocked out. Each round, teams are paired against teams on the same score, with stronger
teams paired against weaker. Early rounds are unequal; the leaders meet each other at the end.
An early draw is consequential. In the simulations, the leaders finish level on match points about half the
time, and are separated by Sonneborn-Berger — a score built from the match points of the teams you beat. Beating
strong teams is worth more, so a draw dropped against a weak team early is still costing you in the last round.
Timing. One round a day at 15:00 in Samarkand, 16–27 September. Games are classical, often lasting four to
six hours.
The live-game model
What it does. Give it a game in progress between two strong players and, after every move, it returns the WDL:
Win Draw Lose probability from White's perspective. It runs live, move by move, on the Olympiad's top boards, with
2-3s latency from the public broadcast.
Two engines answer two different questions; the model adds what neither of them sees — the clocks and the players.
Why it is harder than "ask a chess engine"
Stockfish is superhuman at judging a position, but it answers a different question: who is better with perfect play
from here. Lc0 can be configured to play at a certain rating — which establishes a baseline any model must beat.
Neither engine can be effectively configured to account for non-positional variables, such as changing clock pressure, or
the psychological impact of a blunder.
A worked example. Round 5, board 2: Nguyen, Thai Dai Van (2633, Czech Republic) v
Vachier-Lagrave (2718, France). At move 37 the engine liked White: 58% White, 39% draw. The model said
19% White, 79% draw. Three things the engine does not price:
The clock
White had about 8 minutes left; Vachier-Lagrave had 21.
No way through
The engine's best move and its second best were worth the same — an edge with no forcing
line is an edge that strong defenders hold.
A repetition
The position had already repeated once. Players who are repeating are usually on their way to
agreeing a draw.
Drawn on move 45.
Open the game and step through it: the model's line sits below the engine's
from move 31 to the end.
The mirror image is Caruana v Ivanchuk in round 4 — the engine called it nearly level around move 30, but Ivanchuk had
39 seconds left to Caruana's seven minutes, so the model gave White 49% against the engine's 29%. Caruana won.
Open that one.
In trading terms, the engine is fair value under perfect execution and the model adds execution risk. It
starts from the engine's number (the anchor) and learns how human games actually finish from:
The clocks: how much time each player has left and how fast they have been spending it. This is the strongest
signal.
How hard the position is: whether a player has many good moves, or only one pathway.
Positional volatility: how the engine's evaluation changes as it looks deeper into the position.
Draw tendency: while exceedingly common in high-level chess, playstyle matters. In games above 2600 rated
opponents, Anish Giri (aka the Draw King) holds a draw rate of 67%, while Alireza Firouzja (known for dynamics and
aggression) holds a draw rate of 49%.
Repetition and momentum: repeated positions (a draw signal) and how far the evaluation has already swung.
What the live-game model does not know
In the 2008 World Chess Championship, up 6-4, Viswanathan Anand (White) famously only needed a draw to secure the title
against Vladimir Kramnik. Abandoning his usual sharp, tactical style, Anand chose a highly-researched symmetric variation
of the solid Queen's Pawn opening, easily liquidating the board into a dead draw.
Tournament and match state may influence a player's intentions, and opening choice may indicate them. I
was not able to model any significant effect here — I believe a human has an advantage over the model in certain such
situations.
Psychological impact. A blunder changes the player as well as the position, and the model has no direct measure
of that. It sees the shadow of it: how far the evaluation has just swung, how much time the player burns afterwards, and
whether the position has turned sharp — which is some of what a spectator would call momentum.
Form and preparation: a player in great shape, tired, ill, opening preparation.
Young players on the rise, whose ratings trail their real strength. The tournament model adjusts ratings by
age — fitted on the results of thousands of elite games and checked against the last five Olympiads. The live-game model
does not use it at all, which is where it belongs and where it will move.
Data
Data: about 80,000 over-the-board games harvested from Lichess. Supplementary data was sourced from FIDE,
Lichess and others. Training used the games between players rated 2600 and above.
Engine analysis: every position of those elite games (375,681 of them) was analysed by Leela Chess Zero, a
neural-network engine, plus Stockfish for position difficulty.
The evidence
Against the market. Polymarket has listed markets on single games at the World Championship 2024 and the
Candidates 2026. Across those 59 markets, the engine anchor that the model is built on forecast the results better than
the market's own price (about 19% lower log loss overall, and better in 76% of the games). That held even when the
model's price was taken 60 seconds late.
Model against engine. On 487 held-back games, the full model (v1.3) beat the engine anchor alone: about 3%
lower log loss, with a lower confidence bound above zero. The gain measured during development and the gain on the
untouched data came out almost identical.
Beyond this tournament
Nothing in the model is specific to the Olympiad. Any elite classical game on a live broadcast can be priced the same
way: World Championship matches, the Candidates, the big invitational events. The Olympiad dashboard is one application,
where the model feeds a tournament simulation. The direct use is the per-game markets Polymarket lists for the biggest
matches, where this model is the forecast.
The tournament model
The market price is never an input. It sits at the end, beside the answer, for comparison.
Starting from the real standings, the model runs a Monte Carlo simulation. It plays every remaining round with weighted
dice: it pairs the teams by the official Olympiad rules, rolls each of the four boards, scores the match, and moves on. At
the end it breaks ties the official way and records who won. That is repeated tens of thousands of times.
P(win) is the share of those simulated tournaments that a team won.
What it costs to run
Lc0 analysis is heavy on the GPU, so the full live model runs on a selected 48 boards. A lighter Stockfish-only pricer
covers the matches of lower consequence, so that the simulation still reflects likely future pairings in real time. The
full simulation runs on a timer and whenever a board finishes; individual moves re-weight the standing simulation rather
than starting a new one.
What the model does not know
A gap between the model and the market is a question, not a trade. The model only knows ratings, results and the
pairing rules. The market also prices things the model cannot see:
Lineups: each team rests one of its five players each round. The model uses the published lineup when it
exists and otherwise assumes the strongest four.
Tested on the last five Olympiads, the model gave its top four favourites about 80% between them, and they won three of
the five. Its single favourite won none of them. In a field this close a 30% favourite loses most of the time, and five
events are too few to show whether the model leans too hard on favourites.
Polymarket
Polymarket prices should be taken with the understanding that they are influenced by my own small trades and
liquidity — ie, apparent rapid price reaction to live state changes is in part driven by my own trades.
By day 4 of the tournament, the market had $100k in total traded volume — illiquid and stale. The market is
predominantly operated on by market making bots, which are unreactive to changes throughout the tournament. I know of two
other sharp participants, whom I have encountered in other chess markets. At early stages in the tournament, prices are
relatively insensitive to changes in board state, though model swings of up to 7% were observed and unreflected in the
market.
Uzbekistan appears overpriced — the model had 18% against a market price of 30% before the tournament started — with
the United States and India correspondingly cheaper. I explored multiple theories:
The squad is young, and young players are under-rated. An age adjustment of this kind is included in the
tournament model, fitted on results rather than on rating history, and it is worth two or three points of P(win) here —
a minor calibration, and one that moves the model towards the market on Uzbekistan rather than away. A future
version should apply it inside the live-game model rather than to the team.
Home advantage, common in other sports — but I found no significant effect in past Olympiads.
The market might simply be mispriced. The largest holder of Uzbekistan is running a favourite parlay, and the
next largest holders are all lifetime losers, which makes genuine mispricing more plausible.
Therefore I took a mild short starting position in Uzbekistan, and focussed my attention on the gap between the model
and the market.
How the market itself works
Polymarket lists one YES/NO contract per country (about 40 of them), plus one for "another country". A YES share pays
$1 if that team wins, $0 otherwise, so a price in cents reads as a probability in percent.
On low liquidity markets, execution cost can be significant. On this market, the asks of all countries add up to some
~110%: that 10% is the round trip you pay for crossing the spread, and it is why a small model-versus-market gap is not
a trade.
The state bar picks a point in time: Pre-tournament, After round N, and Live while a round is being played.
Everything on the page is "as of" that state.
The line chart is each team's P(win) over time. The top panel shows the leaders on their own scale; the lower
panel shows the chasing pack on a fixed 0–10% scale, so a move from 1% to 4% is visible.
Time window: 15 min · 1 h · 3 h · round · tournament. During a round, the short windows default
to delta: the change in percentage points since the window started, which makes small moves visible. probability shows the level instead.
Click a line (or a team's name) to focus it. The chart then fits to that team and draws its Polymarket bid and ask as dashed lines,
so you see model against market directly. Click again to clear.
The table below lists every team: P(win), the market's bid – ask and mid, and model − mid
(green = the model is higher than the market, red = lower), followed by match-point statistics. Click a row to focus that team.
The small grey line at the bottom of the page reports whether the live updater is running, when it last ticked, how many boards are
finished, and whether the Polymarket feed is connected.
Round buttons along the top: any past round, the live one, or the next. A dot on a button means the live-game model has prices for that round
(filled = priced live, half-filled = priced afterwards by replaying the games).
By default only the matches of the top contenders are shown. show all matches lists every one.
Each match: the two teams with their P(win) (on a past round: before → after it), the match score, and the odds of
the match itself. The higher-rated team is always on top.
Each board: the position, the players (country, title, rating) and their clocks; the dark clock is the player to move.
The bar beside the board is the game's win / draw / loss chance: top section = the top player wins, grey = draw,
bottom = the bottom player wins. A faded bar means it comes from ratings only, not the live-game model.
Click a board to open that game.
A single game (opened from Key boards)
The board with its moves on the left. Arrow keys step through the game, and every chart on the right follows the move you are on.
Game Probability: the live-game model's win / draw / loss at the selected move. v1.3 is the price;
Lc0 anchor is the chess engine's own estimate, which v1.3 starts from, shown alongside for comparison.
Game Probability over the game: how that number moved, move by move. Click anywhere to jump there.
MultiPV: how many good moves the position offers. A big gap between the best and second-best move means one precise
move is required, and that is where mistakes, and swings, happen.
Clocks: time left for each side. Time pressure (often near move 40) is where upsets cluster.
Pick a team; every chart follows it. The page uses the same state bar as Probabilities.
Threshold probabilities: the chance of finishing with at least N match points. The winning total at recent Olympiads has been 18–21 MP.
Final MP distribution: every possible final score for the team and how likely each is.
Round trajectory: the team's expected MP round by round, with the likely range shaded.
Team × final MP: the same distribution for the leading teams at once, as a heat map.
Dark mode: the button at the top right of every page. All times are shown in your local time.
Glossary
P(win)
Share of simulated tournaments the team won outright, with ties broken the official way. This is the number to compare with the market.
P(top on MP, shared)
Chance of finishing on the top score, including ties. It is always higher than P(win) and does not match how the market settles.
MP / match points
2 for a match win, 1 for a draw, 0 for a loss. The standings are ranked on these.
GP / game points
The sum of board results (1 / ½ / 0). A secondary tie-break.
E[MP], median
Average and middle final match-point total across the simulations.
N+ MP
Chance of finishing on at least N match points.
Sonneborn-Berger (SB)
The Olympiad's first tie-break: roughly, the sum of the scores of the teams you beat. Beating strong teams is worth more.
Bid – ask, mid
Best buy and sell prices on Polymarket, in cents. The mid is the average of the two.
model − mid
The model's P(win) minus the market mid, in percentage points. A positive value means the model rates the team higher than the market does.
Overround
How far the market's prices sum past 100%. It is the market's margin.
Elo / rating
A player's strength number. A 100-point edge ≈ 64% expected score.
GM, IM, FM
Chess titles: Grandmaster, International Master, FIDE Master.
W / D / L
Win / draw / loss probabilities for a single game.
Live-game model (chess_model, v1.3)
The machine-learning model that prices one game in progress from the engine's view of the position, the clocks, the position's difficulty and the players.
Anchor
The engine's own win / draw / loss estimate, which the live-game model starts from and corrects.
Log loss
The standard score for probability forecasts. Lower is better, and confident wrong calls are punished hard.
Shadow
Running live and logging every price, without trading on it. This is how a model earns trust before money is put on it.
Lc0
Leela Chess Zero, a neural-network chess engine. Its view of the position is the live-game model's main input.
From ratings
A board priced only on the two players' ratings, because the live-game model is not following it.
Replay
A past round priced after the fact by re-running the live-game model over the finished games. It is labelled so it is never mistaken for a price made at the time.
Ply
One move by one side (a full "move" in chess notation is two plies).
Monte Carlo
Estimating probabilities by simulating the uncertain future many times and counting outcomes.
What I checked
Pairings. The model's copy of the official pairing rules reproduced the real round-3 pairings exactly (102 of 102 matches).
If the simulated pairings are wrong, every probability downstream is wrong, so this is the key check.
Tie-breaks. The model's tie-break calculation matched the official one for every team (202 of 202).
Game model. It was refitted on real Olympiad games after the first version under-rated elite favourites. I also tested
whether the four boards of a match move together, for example a team having a bad day; they are close to independent.
History. The model was run on five past Olympiads (2014–2024) from the start of each. Its final-score forecasts were accurate to within half a match point on average.
Sources: official results and pairings from Chess-Results; live moves and clocks from the Lichess broadcast; prices from Polymarket's public feed. All read-only.