DEV Community

Russell Yapp
Russell Yapp

Posted on

Six months, 6,314 real bets, +1.2%: what a betting bot taught me about data

I spent six months building a bot that placed bets on the Betfair Exchange. On 29 October 2026 I stopped live betting, paused development and switched the bot off. This is what I learned, and it is mostly not about betting.

The short version: the bot's results looked good in testing, did not follow in live running, and almost every reason I found was a data or measurement error. The models were rarely the problem.

What I built

A Betfair Exchange bot across many sports: tennis, horse racing, football, darts, cricket, golf, basketball and more. It had paper trading, an optimiser that generated thousands of model variants, and live execution at small stakes (£1 to £5). I built it with AI coding agents (Claude Code).

What happened

From 22 April to 29 October 2026 the live book settled 6,314 bets with £16,792 staked, for a net +£205 (+1.2%).

By month: April −£99 (−16.7%), May +£487 (+5.8%), June −£221 (−4.3%), July −£11 (−1.0%), August +£60 (+8.7%), September −£36 (−11.5%), October +£26 (+5.5%).

All of the profit came from May. Without May the total is about −£280. After I reset to small flat stakes in July, the result was about +£38 on roughly £2,600 staked. That is inside one standard deviation of luck, about ±£144, so it is indistinguishable from zero. The last 60 days came to about −£23, and tennis, the core of the book, ran −7.6%.

I did not find a live edge. So I stopped.

The lessons

1. Paper beats live by a lot, and it is not commission

For the same lane, the gap between paper and live return on stake (ROI) measured 6 to 19 points. Commission explained only about 0 to 1 point. Almost all of the rest was adverse selection: you get filled when you are wrong. Paper ROI also shrank by 60% or more out of sample.

2. Execution was the edge, not prediction

Across the book, only 18.5% of live orders were filled. For tennis, crossing the spread lifted the fill rate from 37.8% to 92.5%. The price advantage vanished: median closing-line value went to 0.00%, and live P&L ran −£61 in six days. The apparent edge had been queue position, not selection.

3. Phantom settlements

Bets that never matched on the exchange were settled anyway, using the market result. That created fake live P&L. I excluded 25 of them in July. It came back in October through a different code path: 31 bets that lapsed on Betfair were settled (−£9.38).

4. Survivor bias from a clock race

12.3k bets got stuck because settlement compared against an event clock that raced the market closing. The bets that did settle were a biased sample. One Formula 1 lane showed +242% on 6 bets. Its true figure was +1% on 52, and I had already put it live on the strength of the inflated one.

5. Counting the same bet many times

Hundreds of model variants placed the same bet on the same selection, and I counted each result as independent evidence. When I de-duplicated by market, selection and direction, apparently significant results collapsed. One "strong" cell fell to 48 bets with a confidence interval that spanned zero.

6. Optimisers find lucky days, not edges

71% of the high-ROI lanes that had a live record lost money live. Their backtest profit was concentrated in a handful of days. Screening by how concentrated the profit was across days worked better than screening by ROI or t-statistics.

7. Closing-line value did not predict profit

The usual rule says that if you beat the closing price, profit follows. Across my whole book the correlation between closing-line value and ROI was about −0.10. The one lane that made money live did not beat the sharp close. It was harvesting a market inefficiency.

8. A config save silently deleted 1,306 lanes

A configuration save removed 1,306 strategy lanes, including 12 of the 20 live ones, and left no log trail. I found it weeks later because performance had changed.

9. Growing stakes on winning streaks buys high

Raising stakes during winning runs meant the drawdown arrived at peak stake size. Flat stakes were safer.

10. A horse's name broke the API client

A runner with "ssl" in its name made a parse error look like a network error. That triggered bursts of "API paused" back-off.

11. The tests wrote to the live database

Running the test suite in the production environment leaked test bets into the real ledger.

12. Nearly everything tested negative

I tested 12 conditioning filters (surface, time of day, fatigue, venue and others): 11 were dead and 1 was untestable. I tried 25 more sports and markets, and every one was refuted. An LLM "advisor" that picked bets came out significantly negative (t = −2.91), and it simply copied the favourite 99.35% of the time. Switching venue was not an option either: Polymarket and Kalshi are blocked in the UK.

What it was really about: what was known when

Look back over that list. Most of it is a timing or provenance failure. Using information the bot could not have had at decision time. Clocks racing each other. UTC against BST. Dead heats. Partial updates. Duplicates counted as independent evidence.

Results that look like an edge are very often a data artefact. Whatever you are modelling, whether it is prices, property or sport, you need data that records what was known when, not just what is true now.

That is why I publish dated, point-in-time data at data.yappman.com: UK and Australian shelf prices (daily and weekly snapshots, corrected only for errors), plus property, hotel and public-contract data through Apify.

The bot is switched off; the code and data are archived.

Nothing here is betting advice.

Top comments (0)