NullEdge
← back

One Book, No Arbitrage

I pointed my falsification method at Polymarket sports, looking for a quant arbitrage edge a small account could actually trade. The default verdict is REJECT until the numbers survive costs. They didn't — and the most-repeated "edge" turned out to be structurally impossible. Every measurement below you can re-run with the linked scripts; the figures I cite from published work are flagged as such.

The setup

The pitch for prediction-market arbitrage is everywhere: "Polymarket and the sportsbooks disagree by 3–8%, just buy both sides." I wanted to believe it. So I did the thing the marketing never does — I measured the current market against its current costs, live, with read-only scripts that never place an order. Default verdict: REJECT until an edge clears the round-trip cost with margin. Three findings closed the door, in order of how badly.

Finding 1 — the famous "YES + NO < $1" arbitrage does not exist

The single most-cited Polymarket arb is: if the YES ask plus the NO ask sum to less than $1.00, buy both and pocket the difference at resolution. I queried live sports order books and checked it directly.

Across 11 live sports markets: YES ask = 1 − NO bid, exactly, in 11 of 11. Maximum deviation: 0.00e+00. Books with YES ask + NO ask < 1.00: 0 of 11. Median of that sum: 1.01 — one dollar plus the spread.

YES and NO are not two independent books. They are two mirrored views of one book: buying NO at q is filled by a YES bid at 1 − q via minting, so YES ask + NO ask is always 1 + spread. The arbitrage isn't rare or fast — it is arithmetically impossible in consistent data. Anyone selling a bot to hunt it is selling you a search for something that cannot occur.

Reproduce: polymarket_sports_fee_check.py

Finding 2 — the fee that closed the taker door

Polymarket's changelog dates the sports taker-fee increase to 2026-07-10, up from a prior 0.03 — that date and history I take from the changelog, not from my own measurement. What I verified live is the current schedule: the API returns, on every one of 68 live sports markets I sampled, rate: 0.05, takerOnly: true, rebateRate: 0.15.

The fee is C × rate × p × (1−p) per share — a bell curve peaking at a 50/50 price. At p = 0.50 that is 1.25 cents per share, 2.50% of stake. Add the median observed spread — I measured it at exactly 1.0 cent — and a taker needs to be right by:

1.75 probability points just to break even (1.25 fee + 0.50 half-spread).

That is the entire game. To make one taker trade worth doing, the market has to be mispriced against fair value by more than 1.75 points, net, before you've earned a cent — and the published order-book study of Polymarket (cited below) found single-market arbitrage essentially absent even under zero fees. Sports is now a thin maker lane too: in the same run its rebate came back at 0.15, against 0.25 for the other categories I sampled — the lowest of the set, on a category known for adverse selection in-game.

Reproduce: the same script prints the full fee table and the break-even math.

Finding 3 — cross-venue vs Kalshi is dead on the fee alone

"Fine," says the arb seller, "buy YES on Polymarket, buy the other side on Kalshi." I priced it live. Kalshi's fee is quadratic, and I confirmed against their API that its flagship MLB series KXMLBGAME returns fee_type: quadratic_with_maker_fees — it charges maker fees too; Kalshi's own metadata shows the other liquid sports series doing the same. Combined with Polymarket's taker fee, the round trip at a 50/50 price costs:

~3.0 cents per contract. The two venues' asks must sum below $0.97 before the trade is even flat.

Then I ran the feasibility check across live markets — of the Kalshi sports markets quoting with resting depth, matched to a concurrently-quoted Polymarket game, at a tradeable price: zero pairs survived. One caveat I won't hide: Kalshi's public, unauthenticated API reported zero resting depth for every market, which may be an access artifact rather than a true absence of liquidity — so treat this run as suggestive, not conclusive. The ~3.0¢ fee math above is not confounded, and that alone is what kills the trade.

Capital makes it worse, not better: a cross-venue position locks collateral on both venues until resolution, with no netting between them. And for an operator in Switzerland the question is moot before the economics — as of GESPA's 2026-06-11 blocklist, polymarket.com, kalshi.com and pinnacle.com (the one book sharp enough to anchor a fair-value consensus) are all listed. That's public documentation, not legal advice.

Reproduce: crossvenue_check.py

The one honest maybe — and why it still points the wrong way

There is a version of this that isn't taker arbitrage: be faster than the market at reading the game. Score a run, know the win probability moved before the price does, take the stale quote. So I built a probe that polls a public score feed (ESPN) and the Polymarket book in parallel and asks, for each actual scoring play: did the price move before the feed reported it, or after?

The naive version of that test is worthless — prices update every few seconds, so any lookback finds a move. So the probe only counts real score changes in competitive game states (a run in a 14–2 blowout can't move a pinned market), and it scores the hit rate against a permutation null — shuffle the event times and see what random events score against the same price stream.

Honest result: inconclusive. Over several game-hours I gathered only 5 clean competitive events — far below the 20 I pre-registered as the bar for significance, so nothing here is settled.

What little signal there is leans the wrong way: the price tended to move before the public feed, a median lead of roughly 8 seconds — but five events prove nothing, and I'm reporting the direction, not claiming it. It is the shape you'd expect if the public feed sits downstream of the stadium, the broadcast, and the market: on a feed like this you would be reacting late, not early. Confirming that would take far more data; being genuinely first would take a sub-second feed the sportsbooks license exclusively, or someone in the arena.

Reproduce: latency_probe.py — record and analyse are separate steps.

What I did NOT measure myself

NullEdge's whole point is telling you which line is measured and which is cited. So:

Verdict

For a small operator, taker-side quantitative arbitrage on Polymarket sports is REJECT — not because the edge is hard, but because it is closed by construction. The intra-market arb can't exist, the fee exceeds the opportunity, and the cross-venue version is dead on the fee and blocked by jurisdiction. The one path that isn't arbitrage — being faster than the market — my data can't confirm either way, but the direction and the one public autopsy I could find both point to reacting late, not early. The only activity even cited with a positive expected sign is market-making — collecting the fee rather than being right — and in sports that lane now pays the thinnest rebate and eats the worst flow. Even there the one public operator write-up I could find (again, cited, not my own run) describes a sports maker bot whose edge decayed hard within months as faster players arrived. None of this is a green light.

This is what an honest edge hunt usually produces: not a signal to sell, but a door you can stop knocking on. The value here isn't a strategy. It's the three scripts that let you confirm, yourself, that there isn't one — before you fund an account to find out the expensive way.

If you have a trading edge you want falsified this way — walk-forward, net of the real fees, against a random baseline, with the verdict stated plainly — that's what a NullEdge audit is. Get in touch →