Source confidence: high

Polymarket Weather Trading — Ensemble Forecasts as Edge

In short: Test whether a calibrated multi-model ensemble forecast of the exact resolution station beats Polymarket's prices on daily temperature and precipitation buckets after fees and fill costs.

Key fact Detail
What it covers data science, finance/trading, prediction markets
Tools Polymarket
Posts covered 1 post · top: Polymarket weather edge — dorm weather…
Creators @flockblocked
Sources dated Apr 2026
Prompt system Run-it-yourself prompts
Last verified 2026-10-22

One of the most-repeated Polymarket folk stories of 2025 is "a student built a six-figure portfolio trading weather contracts from his dorm with a DIY sensor rig." The sensor-rig version of the story is mostly myth — the actual edge is more boring, more reproducible, and more interesting: multi-model ensemble forecasting against a retail-priced order book. The weather station is optional flavor. The ensemble is the alpha.

This guide covers the strategy, the real infrastructure the top traders use, why weather was the perfect market to build this on, and what's replicable.


1. What it is

Polymarket runs hundreds of daily/weekly weather contracts: "High temperature in NYC on March 15 between 42°F and 45°F," "Will it rain tomorrow in London," "Max temp in Buenos Aires above X." Each bucketed range is a separate binary contract. Dozens of top wallets have made $20k–$2M+ trading these markets, and several of the top 10 Polymarket wallets by PnL are weather-only.

Named traders:

The edge isn't knowing the weather better than NOAA. The edge is knowing it better than the order book, which is a much lower bar.


2. How it works — the actual strategy

Core thesis

Weather forecasts from professional models (GFS, ECMWF, UKMO, NWS, ICON, GEM, HRRR) are extremely good 12-72 hours out. Trained 4-model ensembles hit ~70-75% accuracy on daily-high temperature buckets and daily precipitation. Polymarket contracts on those same events trade on retail sentiment, copy trading, and stale prices — often for hours after a new model run has materially shifted the forecast.

That gap is the edge. You're arbitraging retail prediction market prices against publicly available, free, scientifically rigorous physical models.

The ensemble

No single model is reliable. The top bot (WeatherBot) uses a 4-model ensemble weighted as:

Model Weight
ECMWF (European) 35%
GFS (US global) 25%
UKMO (UK Met Office) 20%
NWS (US, bias-corrected MOS) 20%

With outlier penalization — if one model disagrees sharply, its weight gets cut. Degen Doppler runs a much larger 13-model ensemble (Tomorrow.io, Pirate, Visual Crossing, etc.) and dynamically reweights by recent accuracy per region and time-of-day.

For each Polymarket bucket [T_lo, T_hi] on day D, you compute:

P_ensemble(T_lo ≤ T_actual ≤ T_hi) = Σ_m w_m · P_m(T_lo ≤ T ≤ T_hi)

where P_m is derived from the ensemble-member spread (or from raw ensemble members in the case of GFS's 31-member GEFS).

The trade

Why this works

  1. Polymarket weather markets are liquid but not efficient. There's enough volume to trade, but retail traders drive prices with gut feel, not NWS MOS output.
  2. Model runs update every 6 hours. When GFS 12z drops and shows NYC 5°F warmer than the 06z run, the probability stack for the daily high buckets shifts instantly. Polymarket lags this by 30-90 minutes. That lag is a free option.
  3. Bucketed contracts enable laddering. Instead of one bet, you buy a probability-weighted basket across 3-5 adjacent buckets around the ensemble mode, which dramatically reduces variance.
  4. Weather is a mean-reverting, well-understood physical process. Unlike political or sports markets, there are no hidden catalysts, no insider info, no interpretation risk.

3. Key mechanics

Data sources (all free):

Resolution source matters. Polymarket weather markets resolve against specific weather station reports (usually the "official" NWS observation for the city). Your model needs to predict that station, not the city average. This is where NWS MOS (station-specific bias-corrected output) dominates raw GFS.

Position lifecycle:

  1. Pull new model runs every 6 hours (00z, 06z, 12z, 18z UTC).
  2. Recompute ensemble PDF for each open market's resolution variable.
  3. Diff against current Polymarket CLOB best-bid/best-ask.
  4. Size positions with Kelly or fixed fraction. Most successful bots cap per-position risk at $1-$100.
  5. Post limit orders (not market orders — slippage kills the edge on thin markets).
  6. On the next model run, recompute and either scale up, reverse, or hold.

Fee structure quirk: Polymarket fees scale by min(price, 1−price), so extreme-price contracts (near $0.01 or $0.99) have the lowest effective fees. This is also what enables the 99c limit arbitrage strategy (see polymarket-99c-limit-arbitrage.md).


4. The infrastructure — what's actually running

Three public references exist:

suislanchez/polymarket-kalshi-weather-bot

Full-stack reference implementation. Trades both Kalshi (KXHIGH series) and Polymarket. Uses GFS 31-member ensemble (GEFS) forecasts plus — notably — BTC 5-minute microstructure as an auxiliary signal. Kelly sizing, signal calibration, React dashboard. Claimed max profit ~$1.8k. Best starting point for a working codebase.

hcharper/polyBot-Weather

Simpler single-model bot. Educational.

WeatherBot (weatherbot.finance) & Degen Doppler

Commercial tools. Closed source. WeatherBot publishes its 4-model weighting scheme as marketing; Degen Doppler publishes its 13-model list. You can replicate both from public APIs.

The "dorm / weather station" angle

The viral story about a student using a rooftop weather station for edge doesn't hold up: a single-point sensor can't beat a continental-scale numerical weather model for even 12-hour forecasts, because the model already ingests tens of thousands of station observations. Where a local sensor helps is arbitraging the last-hour resolution print — detecting whether the NWS station has already recorded the high for the day, which Polymarket prices don't always reflect until it's official. That's a nowcasting edge, not a forecasting edge, and it requires co-location near (or API access to) the specific resolution station. Short range, narrow edge, real but overstated.


5. How to replicate

Minimal viable weather trader (1 weekend):

pip install polymarket-py open-meteo-requests requests numpy
  1. Use Open-Meteo's free ensemble API (GFS + ECMWF + ICON + GEM) — skip grib2 parsing entirely. Returns raw ensemble members.
  2. Pull current Polymarket weather markets via the CLOB REST API.
  3. For each market, compute P_ensemble(bucket) as the fraction of ensemble members falling in the bucket.
  4. Buy any bucket where P_ensemble − ask > 0.10 with $1-10 per position.
  5. Hold to resolution.

This is enough to learn the edge. Scaling to $10k+ requires real-time order management, slippage control, and a watchdog that can cut positions on model disagreement.

Data path to productionize:


6. How this plugs into your trading-agent-team

The trading-agent-team is built around crypto perps. Polymarket weather is an uncorrelated PnL source — not a single tick of correlation with BTC, HYPE, or anything in the existing portfolio. That alone is worth a subproject, especially for Unicron which is meant to be a multi-strategy platform.

Concrete integration ideas:

  1. New "environmental" arena in Unicron. Add a Polymarket connector alongside the Hyperliquid one. Run a weather ensemble bot as a sub-strategy. Its PnL curve will be orthogonal to the crypto strategies, which smooths the aggregate Sharpe.

  2. Pure-rules execution, AI-only for ensemble weighting. Per your rule (feedback_rules_vs_agents.md: pure rules for trade execution, AI only for the research/optimization layer), the weather bot is an ideal fit. Rules: "if P_ensemble > ask + 10pp, buy." AI layer: nightly reweighting of ensemble members by recent accuracy per city — that's a small regression problem an LLM or classical ML can own without touching live orders.

  3. Challenge-game parameter sweep. Parameters: ensemble weights, edge threshold, Kelly fraction, per-market cap, laddering width. Fitness: out-of-sample Sharpe on a replay of historical Polymarket weather data (available via their Subgraph). Exactly the shape /challenge-game was built for.

  4. Beads-tracked subproject. Create a polymarket-weather bead and scaffold under /unicron/strategies/weather/. Data pull, backtest harness, paper-trading mode, promotion criteria to live.

  5. Kalshi parallel. Kalshi has the same market category (KXHIGH, KXPRECIP), often with tighter spreads and US-regulated. The same codebase services both — double the venues, same edge. suislanchez/polymarket-kalshi-weather-bot already shows the multi-venue shape.

Why this is a good you project specifically: low capital requirement (can validate live with $100), low correlation to existing strategies, uses the Unicron watchdog pattern naturally (model disagreement = pause), and the research layer (ensemble weighting) is genuine alpha you can keep improving for years.


7. Risk and gotchas


Sources


Prompt system — run this yourself

Everything below is pasteable into Claude Code, Claude, or any agent. Use the one-shot when you want the whole result in one run; use the step prompts when you want to steer. Every step carries its own audit, and the gap audit at the end makes the agent find and fill what it missed.

Mission. Test whether a calibrated multi-model ensemble forecast of the exact resolution station beats Polymarket's prices on daily temperature and precipitation buckets after fees and fill costs. Running this produces a point-in-time forecast archive, a probability engine scored with Brier and reliability against both the market and climatology, a model-run lag study, a backtest with a control, and a read-only paper trader. No real money moves until the model beats the market's own probabilities out of sample and 30 days of paper trading beat the control.

1 · Deeper, not bigger

Before running anything, make the task deeper rather than larger. Ask: what would a top professional do here that I am not asking for; what is the rawest material; which methods and tools; what, other than the model or me, proves it right. Then ask for exactly that.

Rewritten prompt — ask for exactly that:

Do not build me a weather bot that trades yet. Prove there is an edge against Polymarket prices first.

1. Pull every resolved Polymarket weather market for the past 12 months. From each market's rules, record the exact resolution station and data source. Pull official observations for those stations from NWS CLI reports or the Iowa Environmental Mesonet.
2. Build a point-in-time forecast archive: for each market and each hour before resolution, the most recent ensemble members from Open-Meteo (GEFS, ECMWF IFS ensemble, ICON-EPS, GEM) that were actually available at that hour. No reanalysis.
3. Compute bucket probabilities from members with per-station bias correction and kernel dressing. Compare the guide's fixed weights (ECMWF 35, GFS 25, UKMO 20, NWS 20) against weights fit on a training period. Score with Brier and reliability versus the market's implied probability and climatology on a held-out period.
4. Test the claimed 30-90 minute price lag after each model run.
5. Backtest the rule buy when model probability minus ask exceeds 0.10 with limit-order fills, fees, 0.25 Kelly, and a $10 cap per position, against a control.
6. Run a read-only paper trader for 30 days.

Gate: no real money until the model's Brier beats the market's out of sample and paper beats the control. Any pilot afterward: $300 total, $10 per position, halt after a 20% drawdown. Never promise returns.

2 · One-shot prompt

ROLE: You are a forecast-verification scientist and prediction-market researcher. You treat the order book as a competing forecaster and require your model to beat it on proper scoring rules out of sample before any trade. No real orders are placed in this run.

CONTEXT:
- Strategy from the guide: compute P_ensemble for each Polymarket weather bucket from multi-model ensembles; buy YES when P_ensemble exceeds ask plus an edge threshold, buy NO when it is below bid minus the threshold; size with fractional Kelly; exit at resolution or on convergence.
- Claims to test: trained 4-model ensembles hit 70-75% on daily-high buckets; WeatherBot weights ECMWF 35%, GFS 25%, UKMO 20%, NWS 20% with outlier penalization; Polymarket lags new model runs by 30-90 minutes; gopfan2 made $2M+ with rules like buy YES under $0.15 and NO over $0.45 at about $1 risk per position; neobrother ladders adjacent buckets; the rooftop-sensor story is mostly myth and the real local edge is nowcasting the last-hour print at the resolution station.
- Data: Open-Meteo Ensemble and Previous Runs APIs, ECMWF Open Data, NOAA NOMADS GEFS, NWS API and MOS, NWS CLI reports and Iowa Environmental Mesonet ASOS archives, Polymarket Gamma and CLOB prices-history.
- Reference code: suislanchez/polymarket-kalshi-weather-bot (GEFS 31 members, Kelly sizing), hcharper/polyBot-Weather.

HARD CONSTRAINTS:
- Point-in-time only: a forecast is usable at time t only if its run was published before t.
- Outcomes come from the station and product named in each market's rules.
- Split time: fit weights and bias corrections on the first 60% of months, report on the last 40%.
- No private key loaded, no order signed. Check key presence with a boolean only.
- Read Polymarket's Terms of Service for the user's jurisdiction; stop live-path work if excluded.
- Never project returns. Any later pilot: $300 total, $10 per position, halt at 20% drawdown or 10 consecutive losing days.

DELIVERABLES, in order:
1. markets.md and stations.csv: every resolved weather market, bucket bounds, resolution station id and source, outcome from official observation.
2. forecast_archive.parquet: per market, per hour, the latest available ensemble members by model with run time.
3. probability engine: bucket probabilities with bias correction and kernel dressing; fixed guide weights versus fitted weights.
4. scores.md: Brier, Brier skill score versus market and versus climatology, reliability diagrams, by city and lead time, held-out period only, paired bootstrap CIs.
5. lag_study.md: price change distribution in the 0-180 minutes after each model run's availability versus matched non-run windows.
6. backtest.md: limit-order fills, fees, 0.25 Kelly, $10 cap, edge threshold 0.10, laddering variant, versus a control (the gopfan2-style price rule, and random entry at the same exposure).
7. paper trader running read-only, and gate.md.

GAP ANALYSIS (built in): keep gaps.md. Record missing model archives (UKMO may not be in the free ensemble feed), stations whose source product differs from the archive you used, markets with ambiguous rules, and how each gap biases scores. Fill what you can; state the rest with the next action.

SELF-QUESTIONS before finishing:
- Am I forecasting the exact station and product in the rules, including rounding and the reporting day boundary?
- Was every forecast available before the price it is compared with?
- Does my model beat the market's Brier, or only climatology?
- Are the guide's fixed weights better or worse than fitted ones out of sample?
- Does the 30-90 minute lag exist, and is the move large enough to cover spread and fees?
- Can limit orders actually fill at the prices my backtest assumes, given book depth?
- Do the named traders' public histories match their claimed rules?
- Which cities or seasons carry the edge, and is that selection post hoc?

STOP CONDITIONS: stop at the gate. Stop early if fewer than 500 resolved buckets exist in the held-out period, if the model does not beat climatology, or if ToS excludes the jurisdiction.

RETURN FORMAT: markdown report: Verdict (one line), Data coverage, Scores table, Lag study, Backtest vs control, Paper status, Gate, Gaps ranked, file paths.

3 · Step-by-step prompts

Step 1 — Ground truth: markets, stations, data feeds

Goal: Know exactly what each market resolves on and which forecasts were available when.

Pull all closed Polymarket weather markets for the past 12 months from the Gamma API. For each, parse the rules text and record: city, variable (daily high, low, precipitation), bucket bounds and units, rounding rule, reporting day boundary (local midnight or otherwise), and the exact resolution source (station id such as an airport ASOS code, and the website or product). Save stations.csv and markets.parquet.

For each station, confirm an official observation archive: NWS CLI daily reports or Iowa Environmental Mesonet ASOS. Pull observations and compute each market's true outcome; compare to the on-chain resolution.

Document the forecast feeds: Open-Meteo Ensemble API model list and member counts, the Previous Runs or Historical Forecast endpoint and how far back it goes, whether UKMO ensemble members are available free, ECMWF Open Data run times, NWS MOS availability. Also read Polymarket fees for weather markets and the Terms of Service jurisdiction list. Write ground_truth.md.

Expect: markets.parquet, stations.csv, observations.parquet, ground_truth.md with feed availability table, fee row, jurisdiction finding, and a resolution-match rate.

Audit before moving on: Resolution match between your observation-derived outcome and the on-chain outcome must be 98% or higher; investigate every mismatch (rounding, day boundary, station). Fail if any market lacks a named station; mark it excluded. Flag any model in the guide's weighting (UKMO, NWS) you cannot obtain point-in-time.

Step 2 — Point-in-time forecast archive

Goal: Reconstruct what every model said at every hour before each market resolved.

For every market in markets.parquet, build forecast_archive.parquet: for each hour from 72 hours before resolution to resolution, the most recent run of each model whose publication time is before that hour, with all ensemble members for the station's coordinates and the target variable aggregated over the market's reporting day (daily max of hourly 2 m temperature, or daily precipitation sum). Use Open-Meteo Previous Runs or Historical Forecast endpoints for GEFS, ECMWF IFS ensemble, ICON-EPS, and GEM; add NWS MOS where archived.

Record run initialization time and an assumed publication delay per model (for example GFS available about 3.5-5 hours after init; verify from NOMADS timestamps or Open-Meteo update times). Cache raw API responses by request hash so reruns are free.

Expect: forecast_archive.parquet keyed by market, hour, model, run time, member, value; a coverage table by model and month; raw response cache.

Audit before moving on: For 10 random rows, confirm the run's publication time precedes the archive hour; any violation is look-ahead and fails the step. Check daily-max aggregation uses the market's local reporting day, not UTC. Report member counts per model; a model with zero members for a month is a gap, not a zero.

Step 3 — Probability engine and scoring versus the market

Goal: Turn members into calibrated bucket probabilities and test them against the order book.

Implement bucket probabilities: per model, apply a per-station linear bias correction fit on the training months; kernel-dress members with a Gaussian of width fit to minimize CRPS on training; integrate over each bucket with the rules' rounding. Combine models two ways: the guide's fixed weights (ECMWF 35, GFS 25, UKMO 20, NWS 20, renormalized over available models) and weights fit by minimizing CRPS on training. Add isotonic recalibration on training.

On held-out months only, at lead times 48 h, 24 h, 12 h, and 3 h before resolution, compute Brier score for: fixed-weight ensemble, fitted ensemble, the market's mid-price as a probability, and climatology (station's historical frequency for that bucket and date window). Compute Brier skill scores with paired bootstrap 95% CIs, reliability diagrams, and results by city. Test the guide's 70-75% bucket accuracy claim by stating the top-bucket hit rate.

Expect: scores.md with a table (forecaster x lead time: Brier, BSS vs market, BSS vs climatology, CI), reliability plots, per-city breakdown, top-bucket hit rate.

Audit before moving on: Confirm no parameter was fit on held-out months. If the market's Brier is equal or better than the ensemble at the lead times you would trade, the gate is already failing; say so rather than searching subsets. Count how many city x lead cells you examined before naming winners.

Step 4 — Lag study and backtest with control

Goal: Check the model-run lag claim and simulate trading with real costs.

Lag study: for each model run's publication time, measure the change in model probability and the change in market mid-price over 0-30, 30-90, and 90-180 minutes afterward; compare with matched windows with no new run. Report whether the market moves toward the model with delay and how much of the gap remains after spread.

Backtest on held-out months: entry when fitted-ensemble probability minus best ask is at least 0.10 (and the NO-side mirror); limit orders at or inside the touch that fill only if subsequent trades cross your price; fees from ground_truth.md; 0.25 Kelly with a $10 cap per position and $300 strategy cap; variant with neobrother-style laddering across 3 adjacent buckets. Controls: the gopfan2 price rule (buy YES under 0.15, NO over 0.45, $1 per position) and random entry at matched exposure. Report per arm: trades, fill rate, net PnL, PnL per dollar risked with bootstrap CI, max drawdown, worst day.

Expect: lag_study.md with the event-study table; backtest.md with model strategy, laddered variant, and both controls on held-out data.

Audit before moving on: Rerun the backtest assuming fills only at the far side of the spread; if the result flips, the edge is the spread, not the forecast. Verify that no trade uses a forecast published after its timestamp. Fail if the strategy does not beat both controls with CI excluding zero.

Step 5 — Read-only paper trader

Goal: Gather 30 days of forward evidence without risking money.

Build paper_trader/ in Python: every hour, list open weather markets from the Gamma API, map each to its station via stations.csv, pull the latest available ensemble members from Open-Meteo, compute calibrated bucket probabilities with the frozen parameters from step 3, read the CLOB book, and place hypothetical limit orders by the frozen step 4 rule. A hypothetical fill counts only if real trades later cross the price. Run the gopfan2-rule control and a random-entry control in parallel ledgers.

Log every decision with model probability, market prices, run times used, and order details to paper_ledger.parquet. On resolution, pull the official observation and score. Write a daily summary: open exposure, fills, PnL per ledger, running Brier for model and market. No private key loaded. Run under a systemd user timer with a heartbeat file and alert on staleness.

Expect: paper_trader/ code with README, running timer, paper_ledger.parquet growing, daily summaries.

Audit before moving on: Grep for any signing or key-loading call; any hit fails the step. Reconcile 10 hypothetical fills against the public trade tape. Confirm frozen parameters are hashed and unchanged during the 30 days; a mid-run change restarts the clock.

Step 6 — Validate against oracles, gate, gap report

Goal: Decide go or no-go with evidence and list what remains open.

Evaluate the gate, all must pass: (1) on held-out months, the fitted ensemble's Brier beats the market's implied probability at the traded lead time, paired bootstrap 95% CI excluding zero; (2) it beats climatology; (3) the held-out backtest beats both controls after fees with the far-side-fill assumption; (4) 30 days of paper trading with 100+ reconciled fills beat both paper controls and the running Brier still beats the market; (5) ToS permits the jurisdiction; (6) an independent rerun of scores.md from the cached archive reproduces the Brier numbers.

If all pass, write the pilot spec: $300 total, $10 per position, halt at 20% drawdown or 10 consecutive losing days, daily reconciliation, kill switch. If any fail, verdict is no-go. Write gap_report.md: every guide claim (70-75% accuracy, the four weights, 30-90 minute lag, named trader rules and PnL, sensor myth) and every result, marked verified / unverified / false with evidence, ranked by impact on capital at risk. Fix the top three.

Expect: gate.md with six rows and evidence, one-line verdict, pilot spec only if passed, gap_report.md ranked.

Audit before moving on: Any unverified oracle makes the verdict no-go. Check the report contains no return projection. If a pilot is proposed, confirm caps exist as code constants in the trader.

4 · Gap analysis and audit

Run this after the build. It makes the agent enumerate its own claims, mark what is verified, rank the gaps and fix the top ones.

You are an independent reviewer of a Polymarket weather-forecast edge study. You did not build it. Read ground_truth.md, stations.csv, the forecast archive coverage table, scores.md, lag_study.md, backtest.md, the paper ledger, gate.md, and gap_report.md.

1. Enumerate every claim: resolution-match rate, archive point-in-time correctness, Brier and skill scores, lag effect, backtest versus controls, paper results, jurisdiction. Mark each verified, unverified, or false. Recompute the held-out Brier for model and market at one lead time from the parquet yourself, and check 10 archive rows for look-ahead.
2. List missing pieces: models in the guide's weighting that were unavailable, stations whose product differs from the archive, ambiguous-rule markets left in, parameters fit on held-out data, fills not reconciled.
3. Rank by impact on capital at risk: look-ahead and station mismatch first, then fill optimism, then sample size.
4. Fix the top three now and show before and after numbers.
5. State what you could not fix and why. If any fix changes the verdict, say so first.
Return a claim table (claim, status, evidence, fix) and the ranked gap list. Never project returns.

Questions the agent must ask itself before it says done:

5 · What proves it right

6 · Failure modes

7 · Agent direction (unattended runs)

Start with rules text and stations: most failures here are resolution mismatches, so step 1 is the most valuable. Cache every API response under data/polymarket_weather/cache/ keyed by request hash and never refetch. Spawn a sub-agent to build the forecast archive (long, rate-limited, self-contained) and a separate one to independently recompute scores as the reproduction oracle. Use Open-Meteo before grib2 parsing; drop to NOMADS or ECMWF Open Data only to fill gaps. Never load or print a private key; the paper trader is read-only. Stop and ask Victor if ToS excludes his jurisdiction, if the held-out sample is under 500 buckets, or before anything that would sign an order. Write outputs to docs/polymarket_weather/: ground_truth.md, scores.md, lag_study.md, backtest.md, gate.md, gap_report.md, and paper_trader/. Return the verdict line first, then the gate table, then gaps. Never project returns.

Prompt system updated 2026-10-22 · all prompt systems · JSON