Autonomous Python trading bot for Polymarket US city daily high-temperature bucket markets. Trades on Polygon (chain_id=137) via py-clob-client. Exploits systematic mispricing between NOAA/NWS forecast accuracy (~90% at 5-day, 1-2F short-term) and retail market pricing.
Polymarket hosts daily prediction markets like: "Will the highest temperature in Chicago be between 70-71F on March 26?" Each city/date has ~11 temperature buckets (e.g., 60-61F, 62-63F, ... 80F+), each priced by the market as a probability.
The bot:
- Fetches weather forecasts from NWS/NOAA, METAR (aviation weather), and NOAA station observations
- Blends multiple data sources into a single forecast with uncertainty (ensemble blending)
- Converts the forecast into bucket probabilities using a Gaussian CDF model
- Compares those probabilities against market prices on Polymarket
- Trades when it finds mispricing -- if the bot thinks a bucket has a 25% chance but the market prices it at 7%, that's an edge
- Manages risk with 13 layers of controls (Kelly sizing, exposure caps, loss limits, etc.)
The live loop currently runs every 2 minutes: poll fills -> forecast -> blend -> parse markets -> decide -> execute. That cadence is configurable and should be treated as an operational default, not a permanent truth.
main.py
-> forecasting/
-> scanner.py
-> blender.py
-> metar.py
-> service.py
-> trading/
-> markets.py
-> decision.py
-> execution.py
-> positions.py
-> resolution.py
-> dry_run.py
-> infrastructure/
-> http.py
-> models.py
-> io.py
-> logging.py
-> health.py
-> backtesting/
-> data.py
-> forecast.py
-> pricing.py
-> replay.py
-> scorecard.py
-> tracker.py
-> price_history.py
-> dashboarding/
-> app.py
-> simulate.py
-> tools/
-> analyze_trades.py
| File | Purpose |
|---|---|
main.py |
Async main loop, scan orchestration, graceful shutdown |
config.py |
Loads .env, typed Config singleton |
forecasting/ |
Forecast ingestion, blending, METAR/station observations, orchestration |
trading/ |
Market parsing, EV/Kelly decisioning, execution, fill tracking, dry-run simulation, resolution |
infrastructure/ |
HTTP retry, validation models, background I/O, queue-backed logging, runtime health |
backtesting/ |
Historical data loading, replay engine, synthetic pricing, scorecards, price history |
dashboarding/ |
Dashboard ASGI app plus local state simulator |
tools/ |
Operational helper scripts such as post-trade analysis |
Research and replay tooling now lives in a single backtesting/ package instead of separate root-level backtest_* wrappers.
- Bucket probabilities: Gaussian CDF integration.
P(bucket) = CDF((hi - mu) / sigma) - CDF((lo - mu) / sigma)where mu = forecast high, sigma = horizon + regime + seasonal adjusted - EV Yes:
p_true * (1 - price) * (1 - fee) - (1 - p_true) * price - EV No:
(1 - p_true) * price_yes * (1 - fee) - p_true * (1 - price_yes) - Kelly:
f* = (b*p - q) / bwhereb = (1-price)/price, tempered by confidence and capped - Ensemble sigma:
sqrt(sigma_base^2 + sigma_spread^2)where sigma_spread = std dev across model forecasts - Seasonal sigma: Base sigma * monthly multiplier (Apr=1.35x more volatile, Jul=0.9x tighter)
- Time-decay:
min_ev * sqrt(days_to_resolution)-- demands higher EV for longer-duration trades
| # | Control | Default |
|---|---|---|
| 1 | Capped confidence-adaptive Kelly | 0.25x-1.25x base, hard cap |
| 2 | Dynamic edge threshold | 8-21 cents depending on uncertainty |
| 3 | Time-decay EV threshold | Scales with sqrt(days) |
| 4 | Seasonal sigma adjustment | Spring/fall inflated, summer tighter |
| 5 | Per-market cap | 3% of bankroll |
| 6 | Absolute position cap | $10 default |
| 7 | Correlated exposure caps | NYC+Chicago share 1.5x single-city cap |
| 8 | Daily exposure cap | 30% of bankroll |
| 9 | Daily loss cap | $50 default, auto-shutdown |
| 10 | Cancel-replace cooldown | 3 cycles after stale order cancel |
| 11 | Orderbook depth check | Min liquidity before placing orders |
| 12 | Adverse selection detection | Flags instant fills as informed counter-trading |
| 13 | Maker/taker optimization | Passive limit orders for 0% fees |
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txtOptional developer tooling:
pip install -r requirements-dev.txtIf you prefer uv:
uv venv
source .venv/bin/activate
uv pip install -r requirements.txt
uv pip install -r requirements-dev.txtcp .env.example .env
nano .envKey settings:
MODE=dry-run(default, no real money)PRIVATE_KEY-- leave as dummy for dry-runBANKROLL=500-- simulated bankroll in USDCTELEGRAM_TOKEN+TELEGRAM_CHAT_ID-- optional alertsTELEGRAM_MIN_EV=0.15-- only alert on 15%+ EV trades
python3 main.pyThe bot will:
- Fetch real NWS forecasts and real Polymarket prices
- Compute real probabilities and edge
- Simulate trades against live orderbook depth (partial fills, slippage)
- Log everything to
logs/trades.csvandlogs/dry_run_fills.csv - Send Telegram alerts for high-EV trades (if configured)
No real money is used in dry-run mode.
# Trade decisions
cat logs/trades.csv
# Dry-run fill simulation
cat logs/dry_run_fills.csv
# Check actual temperatures the next day at weather.gov
# Compare against what the bot traded# In .env:
MODE=live
PRIVATE_KEY=0xYOUR_REAL_POLYGON_PRIVATE_KEYYour wallet needs USDC + small amount of MATIC on Polygon network.
For uninterrupted trading, deploy on a VPS (DigitalOcean, Oracle Cloud free tier, etc.):
# Clone/copy code to VPS
cd ~/polymarket-weather-bot
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
# Create .env with your config
cp .env.example .env
nano .env
# Set up systemd for auto-restart
cat > /etc/systemd/system/weatherbot.service << 'EOF'
[Unit]
Description=Polymarket Weather Trading Bot
After=network.target
[Service]
WorkingDirectory=/root/polymarket-weather-bot
ExecStart=/root/polymarket-weather-bot/venv/bin/python3 main.py
Restart=always
RestartSec=30
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable weatherbot
systemctl start weatherbot
# Check logs anytime
journalctl -u weatherbot -f| API | Purpose | Auth |
|---|---|---|
NWS/NOAA (api.weather.gov) |
Grid forecasts + station observations | Free, no key (needs User-Agent) |
METAR (aviationweather.gov) |
Real-time airport weather, updates every 30-60 min | Free, no key |
| OpenWeatherMap | Supplemental forecasts (optional) | Free tier 1000 calls/day, needs API key |
| Polymarket Gamma API | Market discovery + prices | Free, no key |
| Polymarket CLOB | Order placement + orderbook | Needs Polygon private key |
| Telegram | Trade alerts | Needs bot token + chat ID |
The bot's edge comes from knowing the weather better than the market:
- Most Polymarket traders use intuition, current weather, or basic forecasts
- The bot uses NWS grid forecasts, METAR aviation data, NOAA station observations, and ensemble blending
- When the market prices a bucket at 7% but the bot calculates 25%, it buys
- When the market prices an extreme bucket at 15% but the bot calculates 0%, it sells (buys NO)
- Only one bucket wins per city per day -- the SELL/NO bets on unlikely buckets win most often (10 out of 11 buckets lose each day)
This repo currently demonstrates:
- a fully typed and linted live trading path
- a passing automated test suite for runtime and backtesting logic
- dry-run execution against live orderbook data
- historical replay tooling under
backtesting/
This repo does not currently publish audited live P&L, a forward-test equity curve, or a canonical backtest scorecard in the README. That is intentional: credibility should come from reproducible artifacts, not hand-wavy headline numbers.
If you want stronger public evidence before allocating more capital, the next high-value additions are:
- a saved dry-run performance summary with win rate, drawdown, Sharpe, and trade count
- a reproducible backtest report generated from
backtesting/ - a small forward-test section summarizing paper-trading results over a fixed date range
- v1: Basic Gaussian model, flat Kelly (0.15x), flat edge threshold (8 cents), fire-and-forget orders
- v2: Weather regime detection (inflates sigma for storms/fronts), confidence-adaptive Kelly, dynamic edge thresholds
- v3: Fill tracking via PositionTracker, ensemble blending (NWS + OWM), stale order cancellation
- v3.1: 8 robustness fixes -- cancel-replace cooldown, negation-aware regime detection, API retry/backoff, parse metrics, city-specific peak hours, OWM cache pruning, configurable fees, orderbook depth check
- v4: 9 optimizations -- station-specific NOAA modeling, METAR aviation weather as 3rd ensemble source, seasonal sigma adjustment, time-decay capital allocation, correlated exposure caps, maker/taker fee optimization, adverse selection detection, Sharpe ratio tracking, capped adaptive Kelly
- v4.1: Realistic dry-run simulator -- live orderbook matching, partial fills, slippage tracking, fill rate metrics
- v5: Runtime hardening -- response validation, background persistence, queue-backed logging, health-monitor fail-safes, stronger live-path tests
- v5.1: Final package cleanup -- runtime consolidated into packages, backtest wrappers deleted, dashboard/tooling moved out of root, full-tree lint/type/test checks green
- See ARCHITECTURE.md for the current and target module layout.
requirements.txtis the runtime install surface.requirements-dev.txtis for testing, linting, property-based testing, and recorded-response integration work.- Optional: install
pre-commitand runpre-commit installto enforceruff,mypy, andpytestbefore commits.
Private use only. Not financial advice. Trading involves risk of loss. Use at your own risk.