Skip to content

faw01/melody

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

15 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Melody

Melody is an automated weather trading bot for Polymarket. It fetches multi-model weather forecasts, compares them against market prices, and places trades when it finds a statistical edge.

How it works

Polymarket lists daily temperature markets for cities worldwide: "Will the high in Dallas be 84-85°F on Feb 28?" You buy YES or NO shares priced between $0.01 and $0.99. If your outcome occurs, each share pays $1.

Most Polymarket traders don't run numerical weather prediction. Melody does, and trades the difference.

Scan markets → Fetch 7 weather models → Build probability distribution
→ Compare to market prices → Size bets with Kelly criterion → Execute

The pipeline

  1. Scan Polymarket for active temperature markets across 30+ cities
  2. Fetch ensemble forecasts from 6-7 weather models (GFS, ECMWF, ICON, GEM, JMA, MeteoFrance, HRRR)
  3. Model temperature as a normal distribution; calculate bucket probabilities via CDF with continuity correction
  4. Compare model probabilities to market prices; flag edges above 10%
  5. Size each bet with quarter-Kelly relative to bankroll and edge
  6. Place GTC limit orders on Polymarket's CLOB (or record paper trades)
  7. Check for forecast drift, order fills, and trade resolution
  8. Fetch observed temperatures, mark trades won or lost, calculate P&L

Philosophy

Why weather?

Most prediction markets are hard. Politics has insiders, narratives, and October surprises. Sports have injuries, momentum, and locker room drama. Crypto markets move on tweets. In all of these, your informational edge is fragile and fleeting.

Weather is different. The atmosphere is a physical system governed by fluid dynamics and thermodynamics. There are no insiders. Nobody has a secret weather source. The physics is the same for everyone, and the numerical models that solve the equations are publicly available. Tomorrow's high temperature in Atlanta is not a matter of opinion; it is a matter of computation.

At 1-2 day horizons, the GFS, ECMWF, and other NWP models ingest millions of observations (radiosondes, satellites, surface stations, aircraft) and simulate the atmosphere forward in time. Their average error for next-day highs is 2-3°F. That is precise enough to price a temperature bucket market.

The edge exists because most Polymarket participants are retail traders, not meteorologists. They trade on gut feeling, anchor to yesterday's temperature, or pattern-match. They don't run ensemble forecasts, calculate CDFs, or think in probability distributions. The result: systematic mispricing, especially in the tails.

The strategy

Bet NO on unlikely outcomes that the market overprices.

Polymarket weather markets divide a city's daily high into 7-9 temperature buckets. Prices across all buckets must sum to roughly $1. Retail traders tend to spread money too evenly, or overweight "interesting" outcomes, leaving tail buckets overpriced relative to their true probability.

Example: Atlanta's forecast is 63.5°F with 2.4°F uncertainty. The 68-69°F bucket is 2+ standard deviations above the mean, roughly a 3% event. But the market prices it at 36% YES. That is a 33% edge on the NO side. Melody buys NO shares at $0.64; if the actual high falls anywhere outside 68-69°F (which it will ~97% of the time), each share pays $1.

The structure resembles selling overpriced insurance. Most of the time you collect the premium. Occasionally you pay out. But the math favors the seller.

Why an ensemble? No single weather model is always right. GFS might run warm in the Southeast; ECMWF might underperform in the Rockies. Averaging 6-7 independent models cancels individual biases and produces a tighter estimate. The ensemble spread also measures uncertainty; when models disagree widely, you should bet less aggressively.

Why Kelly sizing? The Kelly criterion maximizes long-term compound growth given your edge and bankroll, but full Kelly is aggressive: it assumes your edge estimate is perfect. Weather models have error and bucket probabilities are approximate, so Melody uses quarter-Kelly, betting 25% of what full Kelly suggests. This cuts variance sharply at the cost of slightly slower growth; in practice, it means surviving losing streaks without blowing up.

Why the uncertainty floor? When all 7 models agree, the raw standard deviation might be 0.5°F. Real forecast error is never that low; local effects, measurement error, and chaotic sensitivity create irreducible uncertainty. Melody floors uncertainty at 3.0°F for Fahrenheit cities and 1.7°C for Celsius cities, scaled upward for longer horizons. Without this floor, the model would be overconfident on near-the-mean buckets and underestimate tail probabilities.

Why limit orders? Polymarket charges 0% fees for makers (limit orders) and dynamic fees for takers (market orders). Every Melody order is a GTC limit order placed at the current market price: zero execution fees. Some orders won't fill if the market moves away, but unfilled orders cost nothing.

What can go wrong

The strategy is not risk-free:

  • Forecast busts: Weather models occasionally produce large errors, especially for convective events, frontal passages with uncertain timing, or temperature inversions. A 5-6°F miss happens a few times per month.
  • Coordinate mismatch: Melody forecasts from city-center coordinates, but Polymarket resolves against specific weather stations. A 0.5-1°F difference is typical; more in coastal or elevation-varying cities.
  • Thin liquidity: Limit orders may not fill, leaving edge on the table, or may fill right before a forecast shift, locking you into a stale position.
  • Model correlation: The 7 models share some input data and similar physics. The ensemble may be overconfident when all models share the same blind spot.
  • Bucket boundary effects: When the actual temperature lands on a bucket boundary (e.g., 69.0°F for a 68-69°F bucket), rounding rules determine the outcome. A 0.1°F difference can flip a trade.

The defense: diversify across cities, dates, and buckets, with conservative sizing. A single trade loss is small. The strategy wins by being right far more often than it is wrong.

Quick start

uv sync
cp .env.example .env
uv run python -m melody scan       # paper trade scan
uv run python -m melody dashboard  # view portfolio

Commands

melody scan

Runs one full cycle: discover markets, fetch forecasts, find edges, place trades, check fills, detect drift, resolve outcomes. Takes 30-60 seconds. Safe to run repeatedly; duplicate prevention stops the same trade from being placed twice.

uv run python -m melody scan

melody run

Continuous loop. Runs scan every N minutes (default 30, set via MELODY_SCAN_INTERVAL). Ctrl+C to stop.

uv run python -m melody run

melody dashboard

Shows trades and portfolio summary. Reads from local SQLite; makes no network calls.

uv run python -m melody dashboard
 #  Mode   City    Date     Bucket      Side  Entry  Size   Edge   Status  P&L
 1  LIVE   nyc     2026-…   ≥50.0°F     NO    $0.55  $1.…  27.8%  open
    (filled)
 2  LIVE   miami   2026-…   82-83°F     NO    $0.42  $1.…  44.7%  won    +$2.90
    (filled)

Portfolio Summary:
  Total trades:  26
  Open:          20
  Closed:        6
  Win rate:      83.3%
  Total P&L:     +$8.42
  • Mode: LIVE (filled) means the order executed. LIVE (pending) means the limit order sits on the book.
  • Entry: Price paid per NO share. Lower entry = more upside on a win ($1 - entry).
  • Edge: How much the model probability exceeded the market price at entry.
  • Status: open (awaiting resolution), won (shares paid $1), lost (shares worth $0).
  • P&L: Win: shares * (1 - entry_price). Loss: -(shares * entry_price).

melody history

Same as dashboard: complete trade history.

melody setup

Verifies live trading credentials and wallet status: private key, API credentials, USDC balance, contract allowances.

uv run python -m melody setup

Verbose mode

Add -v to any command for debug logging:

uv run python -m melody scan -v

Interpreting results

Trade signals

 City       Date       Bucket      Side  Edge   Conf   Size   Forecast
 Atlanta    2026-02-…  68-69°F     NO    29.2%  86%    $2.02  63.5±2.4 (7m)
  • Bucket: temperature range bet on
  • Side: NO means betting the temperature will not land in this bucket
  • Edge: 29.2% means the model gives 97% NO probability; the market gives only 68%
  • Conf: model agreement; 86% means 6 of 7 models agree the temp is far from this bucket
  • Size: Kelly-optimal position size given edge, confidence, and bankroll
  • Forecast: 63.5±2.4 (7m) = ensemble mean 63.5°F, std dev 2.4°F, from 7 models

What "edge" means

Model says:  P(temp in 68-69°F) = 2.8%  →  P(NOT in 68-69°F) = 97.2%
Market says: NO shares cost $0.68        →  Market implies 68% NO probability
Edge:        97.2% - 68% = 29.2%

You buy something worth ~$0.97 for $0.68. If the model is right, you profit $0.29 per dollar on average.

Forecast drift alerts

⚠ atlanta 2026-02-28 68-69°F — entry forecast 63.5, now 68.2 (shifted 2.0σ)

The forecast changed since entry. A 2σ shift means the new forecast moved 2 standard deviations; the trade thesis may no longer hold. Consider whether to hold or exit.

Resolution

Trades resolve when the target date has passed and Open-Meteo publishes observed temperatures (usually ~24h after). Won trades pay $1 per share - entry cost. Lost trades lose the entry cost.

Configuration

All settings go in .env. Every option has a default.

Core settings

Variable Default Description
MELODY_PAPER_MODE true true = simulated trades, false = real money
MELODY_BANKROLL 1000 Capital for position sizing (USD)
MELODY_MIN_EDGE 0.10 Minimum edge to trade (10%)
MELODY_MAX_POSITION 50 Max USD per single trade
MELODY_SCAN_INTERVAL 30 Minutes between scans in run mode
MELODY_DB_PATH melody.db SQLite database path
MELODY_MIN_STD_F 3.0 Forecast uncertainty floor (°F)
MELODY_MIN_STD_C 1.7 Forecast uncertainty floor (°C)

Live trading (required when MELODY_PAPER_MODE=false)

Variable Description
PRIVATE_KEY Polygon wallet private key (hex, 0x-prefixed)
POLYMARKET_PROXY_ADDRESS Your Polymarket proxy wallet address (from polymarket.com profile)
POLYMARKET_API_KEY API key (auto-derived on first run, save to skip re-derivation)
POLYMARKET_API_SECRET API secret
POLYMARKET_PASSPHRASE API passphrase

Going live

  1. Set MELODY_PAPER_MODE=false in .env
  2. Add your PRIVATE_KEY
  3. Add your POLYMARKET_PROXY_ADDRESS (find it on polymarket.com under profile/settings)
  4. Run uv run python -m melody setup to verify credentials and derive API keys
  5. Save the printed API key/secret/passphrase back to .env
  6. Fund your Polymarket account with USDC
  7. Start with a small bankroll ($10-50) to validate

Weather models

Melody averages six to seven independent numerical weather prediction models:

Model Provider Coverage Resolution
GFS NOAA (US) Global 0.25°
ECMWF IFS ECMWF (EU) Global 0.25°
ICON DWD (Germany) Global Seamless
GEM CMC (Canada) Global Seamless
JMA JMA (Japan) Global Seamless
MeteoFrance Meteo-France Global Seamless
HRRR NOAA (US) US only 3km

HRRR is used only for US cities (higher resolution, shorter range). All forecasts come from the Open-Meteo API.

The ensemble mean gives the temperature estimate. The ensemble standard deviation (floored at 3.0°F / 1.7°C, scaled by forecast horizon) gives the uncertainty. A normal distribution CDF converts these into bucket probabilities.

Risk controls

  • Quarter-Kelly sizing: bets are 25% of the theoretically optimal Kelly size
  • Exposure cap: total open exposure capped at 3x bankroll (configurable)
  • Minimum edge threshold: only trades with 10%+ edge (configurable)
  • Confidence gate: only trades where 70%+ of models agree
  • Minimum 3 models: skips any city/date with fewer than 3 models reporting
  • Uncertainty floor: never assumes forecast error below 3°F / 1.7°C, scaled by horizon
  • Duplicate prevention: same market+side combination never traded twice
  • Drift monitoring: alerts when forecasts shift from entry values
  • GTC limit orders: all live trades are maker orders (0% maker fee on Polymarket)

Project structure

melody/
├── __main__.py          # CLI entry point
├── main.py              # Scan loop, command dispatch
├── config.py            # Configuration loading
├── types.py             # Data classes (Market, Signal, Trade, etc.)
├── cities.py            # City definitions with coordinates
├── db.py                # SQLite trade storage
├── dashboard.py         # Rich terminal display
├── markets/
│   ├── scanner.py       # Polymarket API discovery
│   └── parser.py        # Parse market questions into buckets
├── models/
│   ├── weather.py       # Open-Meteo forecast fetching
│   └── probability.py   # Normal CDF bucket probabilities
├── strategy/
│   ├── edge.py          # Signal detection (edge + confidence)
│   └── sizing.py        # Kelly criterion position sizing
├── execution/
│   ├── paper.py         # Paper trade execution
│   └── live.py          # Polymarket CLOB execution
└── tracking/
    ├── resolution.py    # Trade resolution (actual temp lookup)
    ├── drift.py         # Forecast drift detection
    └── pnl.py           # P&L calculation

Dependencies

  • Python >= 3.13
  • httpx: async HTTP client
  • scipy: normal CDF
  • rich: terminal UI
  • python-dotenv: environment config
  • py-clob-client: Polymarket CLOB API (live trading only)

About

Automated weather trading bot for Polymarket. Ensemble forecast models vs market prices, Kelly-sized limit orders, real money.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages