Inspiration: The theme was time, and HRT asked for data used to predict and decide. A prediction-market price is a probability with a clock attached: how long until it resolves. Published research (arXiv 2602.19520, 292M trades on Kalshi and Polymarket) shows these prices are miscalibrated depending on that clock. A paper measuring a bias is not a trader making money from it, so we asked the trader's question: does the edge survive costs and an honest out-of-sample test, and how close to resolution should you act?
What it does: Collects 34,677 resolved yes/no Polymarket markets and the price each had 30 days, 7 days, 3 days, 1 day and 12 hours before its scheduled end. Learns a calibration model: the real probability a contract resolves YES, given its price and the time left. Turns that into a decision for every open market: buy YES, buy NO, or no trade (costs eat the edge), with a quarter-Kelly stake. Seals predictions on open markets with a hash before they resolve, then scores them afterwards, so the forward test can't be edited after the fact. A Chrome extension shows Horizon's call on any Polymarket page and fills in the order; a Gemini agent finds tonight's best bets and sets them up. A human always presses Trade. Shows all the evidence on one page: the correction by time-to-resolution, the out-of-time backtest after fees, the models we compared and rejected, and a panel saying where Horizon does not work. How we built it Data: Python against Polymarket's Gamma and CLOB APIs. Each horizon is measured from the scheduled end date (what a trader knows in advance). The price is the last trade at or before that moment, and a row exists only if the market was still open. Cancelled and 50-50 resolutions are dropped. Model: logistic recalibration of the market price, with time-to-resolution terms: logit(q) = β0 + β1·logit(p) + β2·log h + β3·logit(p)·log h
Here p is the market price, h the hours to resolution and q our probability. The fitted slope on logit(p) is about 0.85: prices are too extreme. Uncertainty intervals come from bootstrapping whole events. For multi-outcome events, probabilities are rescaled so the legs sum to one ("event coherence").
Model tournament: we compared about a dozen alternatives on validation data: domain-specific and hierarchical models, beta calibration, isotonic regression, Shin (1993), the power method, ensembles, and early-exit rules. The simple model plus event coherence won, and the rest are on the site. Decision: trade only within 24 hours of the end, only if the edge clears the half-spread (1¢ floor) + Polymarket's taker fee and the model's own uncertainty, and at most one bet per event. Stake = ¼ Kelly, capped at 5%, never more than one bankroll at risk. App: FastAPI backend, Next.js + Tailwind front end, a browser extension, and an MCP server so an AI agent can query Horizon's calls. Team workflow: three roles (model/backend, front end, data/pitch), each running Claude Code agents. Agents talk through per-role inbox files in the repo and review each other's pull requests. Results (out of time, after fees) We trained on events that ended before 18 May 2026 (23,838 markets) and tested on the 10,579 markets after. Legs of one event never straddle the split.
Prediction: the model beats the market price. Brier 0.1297 vs 0.1305, log loss 0.3917 vs 0.3940. Decision: 1,827 trades, +30¢ per $1 staked (90% CI 22¢–39¢, event bootstrap). As a bankroll: +4.27 starting bankrolls (CI 3.05–5.53), max drawdown 22%, hit rate 31%. Hit rates are low because it mostly buys longshots. Baseline: "always back the favourite" on the same markets loses 8.7 bankrolls. When: a month out there is no edge left after costs. It grows toward the end, so we only trade in the last 24 hours. Where: most of the profit is sports. Culture loses money and crypto is about break-even, and we say so on the page. Robustness: profitable in 15 of 17 months in a month-by-month walk-forward; survives double fees. Sealed forecast: on 150 markets that resolved after we posted the hash, the model was slightly more accurate than the market overall and on sports, as pre-registered, but within noise; outside sports and crypto it was worse, the same place it lost in the backtest. Challenges we ran into Our first result was wrong, and we caught it. A 3,100-market sample said the bias was biggest in politics, a month out. On 11× more data it didn't replicate, because the small sample was top-volume and politics-heavy. We kept the story in the pitch. Look-ahead traps everywhere: markets that close early, actual vs scheduled close times, correlated legs of one event leaking across the split, and legs that resolved before the cutoff. No historical order book: Polymarket has no past spreads, so costs use a 1¢ floor plus fees. We state this as a limitation. Choosing without peeking: with many model variants it's easy to fool yourself, so we picked on validation only, ran placebo tests, and reported a deflated Sharpe ratio. Accomplishments that we're proud of An end-to-end pipeline from 34k real markets to a live "buy / don't buy" call, evaluated out of time with real fees. Saying "no trade" most of the time, and showing exactly where the model fails. Placebo tests: if prices were exactly right, our strategy loses money. The edge is real, not a backtest artifact. What we learned: A tiny Brier improvement can still be worth money if you only act where the edge clears costs. Every fancy model we tried makes almost the same errors as the simple one (error correlation about 0.99). The bias is the signal, not the model, and most of the job is knowing when to stay out.
What's next for Horizon: Real historical spreads from on-chain fills for exact costs, Kalshi as a second venue, measuring capacity (how much you can trade before moving the price), and scoring our sealed live predictions as they resolve.
Built With
- chrome
- claude-code
- fastapi
- gemini-api
- git
- github
- github-actions
- katex
- model-context-protocol
- next.js
- numpy
- pandas
- polymarket-api
- py-clob-client
- python
- railway
- react
- recharts
- scikit-learn
- sha-256
- tailwind
- tailwind-css
- typescript
- uvicorn
- zed-delta
Log in or sign up for Devpost to join the conversation.