01The claim
Polymarket trades through a Central Limit Order Book (CLOB). In a thin market, very few shares are available near the current price. Our system trades daily temperature markets, and those books are thin by construction: each city and day is split into narrow temperature ranges, attention is scattered across dozens of cities, and the extreme ranges barely trade at all. Most writing about thin books stops at slippage, the cost of pushing a large order through a shallow book. Our weather book found three other failure modes: resting orders that fill exactly when you are wrong, inventory your own ledger does not know about, and a measurement pipeline that a single unquoted share can switch off.
02What the weather book lost
The weather book's losses were small in dollars and large in information. The figures below come from completed trades and system logs on live temperature markets, not a backtest.
Working notes · from the live weather book
- The book's worst recorded day lost $14.80: six stop-losses totaling −$20.94 (average −$3.49) against eight winners totaling +$6.13 (average +$0.77), a 4.5:1 loss-to-win ratio. Four winners that all eventually resolved to $1 were cut early, leaving about $29 on the table; holding them would have flipped the day to roughly +$15.
- The entry mix leaked from both ends. An expensive favourite, a Seoul range entered at $0.82 that the model priced at 0.91, lost $6.66; a near-coin-flip Istanbul range entered at $0.56 lost $13.09. The note in the log reads "pennies up, dollars down."
- The largest weather inventory incident has no clean headline number because the ledger could not see it: a duplicated entry left 51.7 shares invisible to every exit decision, and they rode a collapsing range into settlement (Case 1 below).
- While all of this ran, the venue's account page showed a $37 loss when the account, across all books, had actually lost $187. The account P&L API lagged by as much as an hour, and our own ledger, the running record of events that change the account balance, trusted the delayed figure.
- The logs also contained 15,639 failed exit attempts, roughly 11,728 of which the remediation notes bucket as venue rejections for insufficient balance or below-minimum order size. We changed cancellation and exit handling so the same operation can be retried safely without duplicating an action or crashing the strategy.
03The weather bleed: adverse selection in a thin book
The slow loss in a thin book comes from resting orders. An order that waits in the book and adds liquidity is the maker; an incoming order that executes immediately against it is the taker. A resting bid does not fill at a random moment. It fills when someone chooses to sell into it, which happens more often when the seller knows more or the price is about to fall. That is adverse selection.
Our first maker model made the classic mistake of booking profit at posting time. It
treated the midpoint between the best buy and sell prices as fair value, our
estimate of what the share should be worth, and recorded
edge = 0.3 × halfSpread + rebate the moment an order was placed, where
the 0.3 multiplier was an unsupported guess and a rebate is a venue payment for
providing liquidity. With fair value pinned to the midpoint, the Kelly criterion, a
formula for choosing position size to maximize long-run capital growth, turns
positive for every non-zero spread, so the model saw opportunity everywhere. What it
never measured was what usually happened after a fill.
In the weather book this failure had a specific shape the logs call the weather bleed. Early box construction bought the cheap side first: a $0.09 long-shot leg resting in the book, to be paired with a $0.83 favourite leg for a guaranteed-profit box. The favourite leg often never filled. The cheap leg did, precisely because selling into a resting bid on a long shot is attractive to whoever knows the outcome is drifting away, and the system was left holding a naked, decaying long shot.
The fixes were structural. Boxes are now built favourite-first, and a cheap leg may only be bought to complete a box whose favourite side is already secured, never led naked. An entry floor (no solo entry below $0.20, no directional entry below $0.50) blocks the bleed at the gate. Section 07 covers the one deliberate, narrow exception we later cut into that floor.
04Case studies from the weather book
The cases below all come from the live weather book during June 2026. Each one led to a specific change in the system.
Case 1: The entry the ledger could not see
On an NYC temperature range, the engine bought 51.7 shares at $0.62, twice. The second order was sized and sent before the first fill had been polled from the venue, so at decision time the first purchase was invisible: not yet a position, no longer a resting order. Both fills were real. The local book recorded roughly half the true inventory.
Every exit decision afterward was sized from that blind local book. When the range crashed, a partial cut of 20 shares went out at $0.05. Rebuilding positions from the venue's own trade records later showed 83.4 shares still held, not the 31.7 the local book believed. The unseen remainder was never offered for sale and rode the collapsing range into settlement.
The failure had three layers. In-flight orders were invisible to the sizing check, so a second entry was sized against headroom the first had already consumed. There was no durable record of fills; the in-memory list died on every restart, so nothing could rebuild the truth. And exits are sized from the local book, so shares the book does not know about are never sold.
Pending entries now reserve exposure the moment they are sent: held shares, resting orders, and in-flight orders are counted together before another entry is sized. Every fill is appended to a persistent, append-only fill ledger, and the positions rebuilt from that ledger are continuously cross-checked against the venue's aggregate; a mismatch is flagged as a possible missed or duplicated fill. After a partial exit the remaining size is confirmed against the exchange, and the confirmation only ever adjusts the local size downward, because adopting a stale higher reading would re-inflate the position and cause an oversell.
Lesson: in a thin book you rarely get a second chance to exit, so inventory errors can be bigger than model errors. The sizing model was not wrong here; the system simply did not know what it held.
Case 2: The stops that cut winners, and the wrong first lesson
Late in June the book kept stopping out of positions that went on to win. Ranges on Chongqing and Hong Kong were stopped at a loss and then resolved as winners; on the worst day, four positions that were cut early all resolved to $1. Our first analysis blamed the stops. An early note computed that holding three stopped positions would have been a $20.60 swing on a book that lost $7.16 that day.
The first lesson was wrong. When the authoritative resolution data came in, most of the stops turned out to be correct; the real problem was that the model was over-confident. One position carrying 0.955 model conviction lost, and across resolved favourites the model was right only about 60% of the time. Cutting losers was not the disease; believing our own probabilities too much was.
That reversal is why the humility gate in section 07 exists: forecast-driven confidence is shrunk until the model demonstrably beats the market on resolved outcomes, and exits give a position extra room only when the supporting evidence is strong.
Lesson: in a small book, one day of resolutions can flip a conclusion. An anomaly is information to log, not a rule to code; we now wait for resolved samples before changing behaviour.
Case 3: The account value that lagged by $150
The dashboard showed a $37 loss while the account's actual value was down $187. The venue's account P&L data lagged by as much as an hour, and our system treated it as current.
We rebuilt the ledger from the venue's confirmed trades: an append-only record of every real fill, with fees and rebates synced from those fills and settlement profit tracked in its own bucket. New entries can be added, but old ones cannot be rewritten, and positions are reconstructed from the recorded trades alone. The system continuously compares its local record with the venue, and a large difference triggers a fresh sync and an incident alert. It tracks closed-trade P&L, open-position P&L, fees, rebates, and resolution separately so one summary number cannot hide the cause of a loss. It also never records "sold" unless an order actually went out.
Lesson: confirmed fills are the source of truth for executions, but a full account ledger must also reconcile every other event that changes the balance. A P&L summary, even the venue's own, is not enough.
05Measuring adverse selection with markout
We needed a number that showed what happened after our orders filled. Markout compares the fill price with the market midpoint after a fixed period. For a buy, a negative markout means the price fell after we bought; for a sell, it means the price rose after we sold. Repeated negative markout is often called toxic flow: the strategy is attracting trades just before the market moves against it.
Working notes · from the live system
- We calculate markout over a configured time window and reverse the sign for sells, so negative always means the market moved against us. If the average loss after a fill is larger than the spread and rebate earned on the trade, the quote is not profitable.
- We keep an exponentially weighted moving average (EWMA) of markout for each market and category. This type of average gives recent fills more weight. The system waits for a minimum number of fills before judging a market; after that, it stops posting orders if the average crosses the adverse threshold. The value persists for the rest of the day, so restarting the process cannot erase the warning.
- Markout uses data we already receive from the live order book and our confirmed fills. It does not require another data source or a faster connection.
The opposite mistake: selling good positions too early
The same measurements confirmed the mirror-image failure from Case 2: we were quick to cut losers and also quick to bank winners. The strongest weather evidence is the four eventual $1 winners cut early on a single June day, about $29 left unclaimed on a book whose entire loss that day was $14.80. An earlier, category-mixed sample from the same account pointed the same way and is worth recording as context: entries priced from $0.35 to $0.50 had been sold an average of $0.319 per share below their eventual value, and 70% of them later won (10 completed positions). We treat that sample as information rather than proof, because it predates the weather-only book, but it shaped the design of the value-underdog exception in section 07.
We now keep quick profit targets for weak, low-priced positions. Positions supported by a strong external reference are allowed more time to reach their expected value.
06Sizing that respects the exit
An entry is only safe if we have a realistic way to sell it later. We now estimate the exit before placing the entry. The system simulates a sale into the buyers already visible in the book and rejects the trade unless at least half the intended position could be sold within the stop's slippage limit. It also subtracts the estimated price impact (the cost of selling through successively worse prices) from the expected profit. If a market is too thin to leave, we do not enter it.
Working notes · from the live system
- The exit check uses the current buy orders to estimate how many shares we could sell and at what average price. It is a gate, not a guarantee: the book may change before the real exit, but a position that fails even this first check is already too large.
- Kelly sizing based on one estimate of fair value can recommend positions that are too large when that estimate is uncertain. We now move our estimate closer to the market midpoint when the external reference is weak. The less confidence we have in our own number, the more weight we give the market price.
- The venue enforces a five-share minimum order. The old code rounded every smaller Kelly size up to five, so a one-share recommendation became a five-share position. The minimum is now a hard configured floor, and the system skips the trade when rounding up to it would inflate the intended size beyond a small tolerance.
- Every adjustment is followed by another position-limit check. The default caps are 10% per outcome, 25% per market, 30% per category, and 20% across all deployed positions; the live weather canary ran tighter still, holding total deployment to 5% and each weather outcome to 5%. The system checks the caps on every update and cancels any additional order that would cross a limit. This prevents several harmless-looking increases from quietly concentrating the book in one outcome.
- Each strategy tracks its average P&L per completed round trip. Once it has enough trades to judge (20 round trips), an average below the loss threshold disables new live entries. The check is recomputed continuously, so a strategy whose average recovers re-enables on its own; only the sticky halt after a catastrophic day requires a human operator to resume trading.
07The loss that placed no trades
In mid-July, thin books found one more way to cost us money, and this time nothing was dumped and no stop fired. On July 17 the live system placed zero new entries for an entire day while its forecasts were healthy and no risk halt was active. The thin end of an order book had quietly switched the strategy off.
The setup needs a paragraph. A temperature market is a set of ranges for one city and day ("24°C", "25°C or higher", and so on); exactly one range pays out, so our probabilities across the set must sum to about 1. After the June whipsaw in Case 2 we began adding a humility gate, completed in early July: the model is treated as unproven until its logged predictions beat the market's own prices on resolved outcomes, judged by proper scoring rules (Brier score and log loss, which reward probabilities that match what actually happened). Until then, every forecast-driven signal has its confidence multiplied by 0.35, which pulls our probability toward a coin flip, and position size is held to a 25% probe. The gate depends on a measurement pipeline: log our probability and the market's price for every range, wait for resolution, score both.
Working notes · from the live system
- Every temperature market has a dead tail: an extreme range nobody quotes from both sides. On the incident day one tail range showed a single $0.001 sell offer and no buyer at all. With only one side of the book quoted, there is no midpoint.
- The logging step required a midpoint for every range, and one dead range voided the whole day's row for that city. Not one forecast row was logged for days.
-
No rows meant the model-versus-market comparison could never accumulate resolved
samples, so the model stayed officially unproven, so the 0.35 confidence
multiplier stayed on permanently, so every candidate entry's shrunken edge came
out at or below zero. The entry log showed the same rejection over and over:
skew-thin-edge. Zero entries all day. - A separate timing bug compounded the silence. The observation feed's validity window was stamped with its 10-minute cache refresh interval instead of the roughly one-hour cadence at which the data actually changes, so a reference built in the last minute of a cache cycle expired between being staged and being committed. 115 updates were withheld in four hours for that reason alone.
The failure is worth naming precisely: it was self-sealing. The gate blocked trading until evidence arrived, and the broken pipeline blocked the evidence. A system in that state does not crash, alarm, or lose money in any visible way. It simply stops, while every component reports that it is doing its job.
The fixes kept every safeguard and unblocked the measurement. A dead-tail range now falls back to the one-sided book, the bid if there is one, otherwise the ask. A $0.001 offer is a perfectly good market estimate for an outcome both the model and the book price near zero, and using it keeps the day's row complete so the liquid ranges get measured; only a range with no orders at all still skips logging. The validity window was re-anchored to the data's real cadence of one hour while the cache still refreshes every 10 minutes, a separate three-minute freshness check on the computed reference remains the binding guard, and every withheld update now logs which condition failed and by how much. Finally, the evidence bar was lowered from 30 resolved events to 15 so the verdict could arm on a realistic sample, with the protections kept: the unlock must survive at least one further resolved event, and suspect resolution data re-locks it.
Buying the band we used to sell too early
The same change set acted on the price-band information from section 05. Entries priced from $0.35 to $0.50 had looked like our best band in the early mixed sample, 70% eventual winners sold well below their value, yet the favourites-only floor still refused any entry below $0.50. The floor now has one narrow exception: an entry priced between $0.35 and $0.50 is admitted only when the model's raw probability, taken before the humility shrink, is at least 0.6. That shape is the book underpricing a model favourite, not a cheap long shot, so it is the opposite of the weather bleed the floor exists to block.
These positions are also managed differently on the way out. They exist to be cashed out: the profit-taking ladder banks the price converging toward our estimate, and the rule that would otherwise hold a winning favourite to resolution on model conviction is suppressed, while the stop still runs first on losers. The handling survives a restart without any saved flag, because the entry price is its own marker: nothing else in the system can open a one-sided position below $0.50. The exception ships disabled by default and was switched on deliberately in the live configuration.
The postscript is honest rather than triumphant. The fixes worked, and the system traded live again over the next two days, slightly positive on a small sample. Then a different gate did the same thing: a circuit breaker that judged strategies by a pessimistic statistical bound locked the live book even though the measured average was profitable, and a locked strategy generates no new trades to prove itself with. It was fixed the same day by cutting only on the measured average. That evening we retired this system entirely and began a ground-up rebuild focused on repricing weather markets, so the mechanisms described in this article are the final state of the first system, preserved in its repository history.
Lesson: a stop-loss needs a buyer, and a measurement loop needs a price. Audit every gate that requires evidence to open: if the gate itself can block that evidence, it will eventually seal shut. We hit that failure twice in three days, in two different gates.
08A thin-book survival checklist
These are the controls we added, or would add, before running this kind of strategy again.
- Measure profit from completed fills, not posted quotes. A waiting order has no proven advantage until its markout shows what normally happens after it trades.
- Track the EWMA for each market and category. Wait for enough fills to make the reading useful, then stop posting orders when it crosses the adverse threshold.
- Before entering, use the live order book to estimate how much of the intended position could be sold within the slippage limit and what that sale would cost.
- Break stop-loss exits into smaller orders and limit them to the demand available near the starting price. If an exit cannot be completed within the budget, alert a human instead of dumping the whole position.
- Freeze matched YES and NO pairs: hold them to resolution or unwind them only together, and keep the matched amount out of all stop-loss and profit-taking logic.
- Recheck every exposure cap after sizing changes, including venue minimums, and cancel additional orders that would push the account over a limit.
- Track average P&L for each strategy and disable live entries after a sustained breach. Judge the breach on measured averages, not on a pessimistic bound that a disabled strategy can never improve.
- Reconcile a full account ledger against the venue continuously. Record an exit only after a confirmed fill, and keep fees, rebates, open positions, closed trades, and balance changes separate enough to explain any discrepancy.
- Treat in-flight orders and unpolled fills as inventory. Reserve them before sizing the next entry, and after a partial exit confirm the remaining size against the venue, adjusting only downward.
- Never let a measurement or safety gate depend on data a thin market cannot provide. Fall back to one-sided prices before skipping measurement entirely, and log the specific condition behind every withheld action.
- Audit every gate that needs evidence to reopen. If the gate blocks the activity that generates that evidence, it is a deadlock waiting to happen.
- Log anomalies as information, but change behaviour only on resolved samples. One day of resolutions can flip a conclusion.
09Open questions
- Which conditions actually change a strategy's average result: the spread, time to resolution, the number of shares available near the current price, or the way the order filled? We need more completed round trips before those comparisons are reliable.
- How much should we reduce Kelly sizes when several positions depend on the same underlying event? Category caps are only a rough substitute for measuring how those positions move together.
- How often would orders that appear to fill in a simulation actually fill live? A useful model has to account for orders already waiting ahead of ours, and the honest answer still needs a small live test.
- After adverse selection and rebates are counted, can a thin market support profitable quoting at all, or is it better to trade only when a specific opportunity appears?
- The value-underdog exception traded for only two days before the rebuild, so its central claim is unmeasured: does cash-out management actually bank the convergence that our earlier exits gave away?