Sports forecasting
Almanac prices any fixture, and answers questions about it.
Six football leagues and the NFL, priced from twenty-six years of results: moneyline, spread and totals ladders with both sides quoted, first-half projections, and the reasons behind each number. A question about a game can be asked in plain English, and Almanac shows what it understood before it answers.
What it prices
Every line off one distribution, so none of them disagree
Trained heads exist only at the standard total and spread. Reading every other line off its own classifier produces contradictions, where a −1.5 head claims the home side covers 33% while the moneyline says it wins 26%. Almanac solves for a single distribution that matches the calibrated moneyline and total, then reads every line off that. The ladders agree with each other by construction.
The agent
A question in plain English, resolved into parameters
The rule the agent is built around is that it produces parameters, never numbers. A question is parsed into a scenario — two teams, a date, wind, rain, rest, venue — and that scenario goes to the same predictor the fixture picker uses. Every probability on screen comes out of the measured model, so nothing a language layer says can change a price.
The parse is returned beside the answer, so a reader can see what was understood and correct it. The parser is deterministic and needs no API key, which means the same question always returns the same reading.
SEA at NE · week resolved against the schedule · wind applied as a measured points adjustment
KC vs DEN · rest read from the gap between consecutive games rather than guessed
No player-level input exists, and no injury data to validate an invented mapping against.
Temperature is not an input. Answering would mean quietly pricing the game as a dry, calm day.
How it is built
Three layers, and each one is boring on purpose
There is no framework anywhere in this. The server is
ThreadingHTTPServer from the Python standard library, the
front end is one script and one stylesheet, and the whole thing runs on a
single small virtual machine.
- One bundle per competition: a three-seed XGBoost ensemble for the outcome, blended with an Elo-only logistic at a weight tuned on validation.
- Four binary heads on top, for the full-game and first-half totals and spreads.
- 73 inputs, built strictly causally: matches are walked in date order and team state updates only after a row is recorded.
- Probabilities are calibrated per competition with Platt scaling on a season the model never trained on.
- Margins use a Skellam distribution for football and a Normal for the NFL, because drives are neither rare nor memoryless.
- Resolves a sentence into a scenario and hands it to the predictor. It never states a number itself.
- Grounds wind, rain, rest, venue and date against the real schedule and a measured points adjustment.
- Refuses anything with no channel into the model, and says which and why.
- No API key and no model call in the request path, so a question costs nothing and cannot hallucinate a source.
- A DigitalOcean droplet running Ubuntu, with the app under a systemd unit as a dedicated non-login user, sandboxed with
ProtectSystemandNoNewPrivileges. - The app binds loopback only. Caddy sits in front on the same host, terminates TLS and renews the certificate on its own.
- Security headers come from the app and never from the proxy. A browser intersects duplicate policies, so two sources for one header is a bug that looks like a broken page.
- 38MB of artifacts load into memory before the socket opens, so no visitor ever pays the load. A warm prediction takes milliseconds.
- On boot it re-prices six fixtures against a fingerprint recorded at training time, and reports itself unhealthy if the served model has drifted from the measured one.
- Requests are rate limited per visitor, and the forwarded address is believed only when it comes from the proxy.
- Zero external requests: no CDN, no web font, nothing that a stranger's outage can break.
Measured
Calibrated, and published either way
A forecast is calibrated when the things it calls 70% happen about 70% of the time, which is the property that makes a price usable. Almanac is scored against the hardest benchmark available, the closing line, and the result is published whichever way it falls. On the most recent NFL season the market is ahead.