| City | Date | Predicted | Actual | Error | Std dev | Members |
|---|---|---|---|---|---|---|
Loading⦠| ||||||
| ID | Started | Mode | Cities | Skipped | Markets | Trades | Spent | Duration |
|---|---|---|---|---|---|---|---|---|
Loading⦠| ||||||||
x-dashboard-token header.The bot has one informational edge: an ensemble weather forecast from Open-Meteo β dozens of model variants aggregated into a probability distribution over tomorrow's maximum temperature. Not a single guess, but something like "26Β°C: 15%, 27Β°C: 32%, 28Β°C: 38%, 29Β°C: 12%β¦".
Polymarket lists binary YES/NO markets for each degree bracket. A YES token trading at 38Β’ implies the crowd thinks that temperature has a 38% chance. If our forecast says 52%, there's a gap. The question is whether that gap is real, consistent, and exploitable.
Two fundamentally different theses are being tested: Edge (actively hunt for specific mispricings) and Spread (buy the whole distribution and let calibration do the work). A third approach, Scalp, is a timing variant layered on top of Spread β same entry logic, different exit.
The prediction market crowd β largely individual bettors without access to multi-model ensemble forecasts β tends to misprice temperatures in the 10β40Β’ range. The ensemble is especially accurate for near-mean temperatures, which is also where the market's implied probability is most often off. The bet: systematically buying YES tokens where our forecast probability exceeds the market price by at least 5%, restricted to within Β±2Β°C of the ensemble mean, produces positive expectation.
The metric is the edge multiplier = forecastProb Γ· marketPrice. A 20Β’ YES token where we forecast 25% probability gives 1.25Γ. We only trade at 1.05Γ or higher. Everything else is filtered out.
Not all positive-edge trades are equal. Data from resolved trades shows a hard cliff based on distance from the ensemble mean:
Distance-3+ bets look cheap and show high apparent edge. They don't win. The ensemble doesn't genuinely believe in those temperatures β it's assigning noise-level probability, and the market prices it more accurately than it appears. Cutting this class entirely via maxBucketDistance = 2 was the single biggest improvement from the May 2026 audit.
When a temperature is well above (or below) the ensemble mean, the market sometimes still prices YES too generously. We buy NO instead β betting against the market's overconfidence rather than for the forecast.
Example: ensemble mean is 23Β°C for Madrid. The market has "will it reach 28Β°C?" with YES at 18Β’. Our forecast says 3% chance. We buy NO at 82Β’ β edge multiplier = 0.97 Γ· 0.82 = 1.18Γ.
The distance filter works in both directions (above and below mean), with a minimum of max(2Β°C, 1.5Ο) from the mean. YES must still be β₯ 10Β’ β if the market already agrees the temperature is unreachable, there's nothing to exploit. NO token sweet spot is 72β88Β’; outside that range losses cluster historically.
The post-audit production configuration β our current best-guess at the optimal edge strategy. The May 2026 analysis revealed three fatal flaws in the original setup: (1) distance-3+ bets never win; (2) the 35Β’ price cap was excluding mean-bucket bets which are the most profitable; (3) minEdge=1.30 was too tight, missing good near-mean opportunities. Fixed with a hard 2-bucket distance cap, relaxed edge threshold (1.05Γ), raised price ceiling to 50Β’, 10Β’ floor on YES, and dynamic position sizing that scales with confidence. NO trades enabled.
A frozen snapshot of the May 17 configuration β the "before" picture. Flat $3/trade regardless of confidence, 1.30Γ edge required, 35Β’ price cap, no bucket-distance cap, 35% stop-loss. Running as a clean control group to quantify how much the audit improvements are worth. Started June 12 2026 after a stop-loss bug was patched (the original Baseline, #3, was running with broken stop-losses and has been retired). Expected to underperform Default because without the distance cap it keeps placing distance-3+ bets that empirically never win.
Identical to Baseline v2 β flat $3/trade, 1.30Γ edge, 35Β’ price cap, no bucket-distance cap β but with the 35% stop-loss removed. Analysis of 184 stopped trades in v2 found that 59% of classifiable stopped trades went on to win: the stop was firing on temporary price dips in thin markets (slippage meant exits at 0.1β1Β’ instead of the intended β35%), and the temperature target was still hit regardless. The 10 confirmed wrong stops cost β$414 in missed profits while the 7 correct stops saved only +$5. Baseline v3 lets bets run to resolution to test whether holding is structurally better than cutting.
Edge-hunting requires accurately identifying which markets are mispriced β which is its own source of error. The spread strategy asks: what if we skip that step entirely? If the ensemble forecast is well-calibrated overall, then buying every temperature bucket proportional to its probability mass should work. The correct bucket wins proportionally to how much probability was assigned to it. We capture the calibration advantage without needing to pick winners.
Every city gets a budget distributed across all qualifying buckets. The 38% bucket gets 38% of the bucket-weighted budget. The 12% bucket gets 12%. No edge filter. No proximity cap.
bucketStake = cityBudget Γ (bucketProb Γ· totalQualifyingProb)
The case for Spread: Edge implicitly assumes we can identify which markets are mispriced, but that selection adds noise. If the forecast is the real alpha, buying proportional to the forecast strips out the noise and gets there more directly. Spread also naturally avoids the "lottery ticket" problem β it buys the likely outcomes heavily and the long shots lightly, by design.
The core comparison experiment running against Default. No edge filter, no proximity cap β just the forecast distribution. The central question it's answering: does the edge-hunting in Default add real value, or is the forecast distribution itself the alpha? If Spread v1 approaches Default's risk-adjusted returns, the implication is that the edge filter is mostly filtering signal, not noise β and a simpler approach works just as well. If it significantly underperforms, it validates active price selection as worth the complexity.
Temperature markets go through a price discovery cycle each day. Early in the morning, when little current temperature data exists, uncertainty is high and tokens are cheap. As the day progresses and the actual trajectory becomes clear, the market reprices β the likely outcome's token appreciates toward certainty. By afternoon the winner is often obvious at 70β80Β’.
The scalp thesis: we can capture that intraday repricing without needing to hold to resolution. Buy early when tokens are cheap (below 35β40Β’), take profit when they've moved +30% in our favour, and recycle capital to the next city. The forecast is still doing the work of picking which buckets to buy β but the exit is timing-based, not resolution-based.
Entry is identical to Spread β buy all qualifying buckets proportional to forecast probability. The two additions are:
Entry price cap: only enter tokens below 35β40Β’. This ensures we're buying before the repricing has happened β a token already at 60Β’ has had most of its intraday run. The cap also means we skip the mean bucket if it's already expensive, favouring the Β±1β2Β°C neighbours instead.
Intraday exit: take profit fires at +30% above entry price. The scheduler checks every few minutes via the Gamma API. A 20Β’ entry sells at 26Β’. If neither exit fires, the trade resolves normally at end of day.
The conservative variant. Take-profit at +30%, stop-loss at 50% of entry, higher probability threshold (min 20%), entry capped at 40Β’. The stop-loss is the key variable being tested here β Polymarket CLOB bids are always near-zero, so stop-losses rely on the Gamma API price which can lag. The hypothesis is that the combination of spread entry + intraday exit generates alpha vs holding to resolution. Does cutting losers early via stop-loss actually help, or does it cut positions that would have recovered?
The aggressive variant: no stop-loss, default 8% probability floor (wide net vs v1's 20%), tighter entry cap at 35Β’, wider trading window extended to 19:00 local. Tests two things simultaneously: (a) whether removing the stop-loss improves returns by not cutting positions that would have recovered, and (b) whether casting a wider net β more buckets, lower confidence bar β improves aggregate probability capture. Directly comparable to v1 to isolate the stop-loss effect and probability threshold effect.
Trailing take-profit variant of v1. Same entry (stop-loss at 50%, min prob 20%, entry cap 40Β’) but instead of selling immediately at +30%, the position is held. Once the +30% threshold is crossed, a high-water mark is tracked every 30 seconds β the position rides the move until the price drops 5% below peak, then exits. Directly comparable to v1 to test whether riding the profit wave outperforms locking in a fixed gain.
Trailing take-profit variant of v2. Same entry (no stop-loss, 8% probability floor, entry cap 35Β’, window until 19:00 local) but with trailing exits. The combination of no stop-loss and trailing take-profit maximises upside capture β but without a floor. A sharp intraday reversal between the 30-second checks can turn a winning position negative. Directly comparable to v2 to isolate the trailing effect in the more aggressive setup.
Hybrid trailing stop β the intended design of v4, now correctly implemented. Entry is identical to v2 (spread mode, no stop-loss, 8% probability floor, window until 19:00 local). The exit is a two-part trailing stop: activation triggers at +30% above entry (same threshold as v2's fixed take-profit) using a percentage so cheap tokens can reach it, then the position trails 5Β’ below peak rather than exiting immediately. On winning markets this captures far more upside than v2's fixed +30% exit. v4's flaw was absolute-cents activation (entry + 8Β’) β a 5Β’ token had to reach 13Β’ to arm, which almost never happened. v5 replaces that with entry Γ 1.3, so a 5Β’ token arms at 6.5Β’, same as v2 would have exited. Floor: once armed, stop never falls below activation price β any dip below +30% triggers an exit. This protects cheap-token gains but causes premature exits when price dips briefly below activation then recovers. See v6 for a looser floor.
Hybrid trailing stop with entry-price floor β fixes the over-eager exit problem observed in v5. Entry is identical to v2/v5 (spread mode, no stop-loss, 8% probability floor, window until 19:00 local). Exit: activation at +30% above entry, then trails 5Β’ below peak. The key difference from v5 is the floor: instead of clamping the stop at activation price (which fires on any dip below +30%), the floor is the entry price β the stop can never push the position into a loss. This means a brief dip below +30% does not trigger an exit; only a 5Β’ pullback from the trailing high does. The entry floor still protects cheap tokens where a 5Β’ trailing distance would produce a negative stop (e.g. a 2Β’ token with trailingHigh 3Β’ gives rawStop = β2Β’; the entry floor catches this at 2Β’). On normal tokens the trailing stop runs freely above activation and only exits on a genuine 5Β’ pullback from peak.
Peak-window scalp β systematically exploits the high-certainty temperature window every day. Identical to v6 (entry-price floor hybrid trailing stop: activates at +30%, trails 5Β’, floor at entry) but adds minCityLocalHour: 12: each city is only traded after noon local time. The insight: when a city is 1β5 hours from its temperature peak, the day's outcome is nearly certain β the observed max is already near or above the market threshold β yet Polymarket prices still reflect the uncertainty from when the market opened in the morning. The bot's ensemble forecast confirms the near-certain outcome; participants who set prices overnight had less information. By reserving the city budget until noon, v7 avoids spending it on low-certainty morning trades and concentrates the full budget on the afternoon window where the edge is sharpest. The trailing stop then captures price appreciation as participants discover the near-certain outcome. Unlike v5/v6 which only exploit this window accidentally on their first run (when all city budgets are fresh), v7 does it systematically every day for every city.
For edge YES and NO trades, size scales linearly with forecast confidence:
At the minimum probability threshold you get the base stake ($3). Higher confidence = proportionally larger stake, capped at the maximum ($8). The bot bets bigger when it's most confident.
For Spread and Scalp, position size is pre-calculated by the distribution formula β each bucket's size is cityBudget Γ (bucketProb Γ· totalQualifyingProb). The confidence scaling doesn't apply on top; the proportional allocation does the same job.