How to Trade Prediction Markets on Polymarket Using NOAA Weather Data

Polymarket lets you trade on the outcome of real-world events. Weather markets are a good fit for data-driven trading: NOAA publishes free historical and forecast data, and many weather contracts resolve on official sources. If you can estimate the probability of an event better than the crowd, you can place informed bets.

This tutorial shows how to use Python to pull NOAA weather data, find relevant prediction markets on Polymarket, and place orders when your model disagrees with the market price. You’ll need a Polymarket account (wallet with USDC on Polygon) to trade; reading markets and fetching NOAA data require no API keys.

What You’ll Build

  • Fetch daily weather (precipitation, snow, min/max temp) from NOAA’s NCEI API for any US station.
  • Query Polymarket’s Gamma API for active markets and filter for weather-related questions.
  • Compare a simple historical probability (e.g. chance of 1″ snow on a given date) to the market’s implied probability.
  • Place a limit order with the py_clob_client when you think the market is mispriced.

Step 1: Fetch NOAA Data

NOAA’s National Centers for Environmental Information (NCEI) expose a free REST API. The daily-summaries dataset gives you one row per station per day with precipitation, snow depth, and temperature. No token required.

First, pick a station. Use the NCEI station search or the GHCND station list. For example, Central Park NYC is GHCND:USW00094728. The data API uses a different ID format; for daily-summaries the stations parameter takes station IDs like GHCND:USW00094728.

import urllib.request
import json
from datetime import datetime, timedelta

BASE = "https://www.ncei.noaa.gov/cdo-web/api/v2"
# NCEI data service (no token for public data):
DATA_BASE = "https://www.ncei.noaa.gov/access/services/data/v1"

def fetch_noaa_daily(station_id: str, start: str, end: str) -> list[dict]:
    """Fetch daily summaries for a station. start/end: YYYY-MM-DD."""
    params = {
        "dataset": "daily-summaries",
        "stations": station_id,
        "startDate": start,
        "endDate": end,
        "dataTypes": "PRCP,SNOW,TMAX,TMIN",
        "format": "json",
    }
    q = "&".join(f"{k}={v}" for k, v in params.items())
    url = f"{DATA_BASE}?{q}"
    with urllib.request.urlopen(url) as r:
        return json.loads(r.read().decode())

# Example: last 30 days for Central Park
end = datetime.now()
start = end - timedelta(days=30)
data = fetch_noaa_daily("GHCND:USW00094728", start.strftime("%Y-%m-%d"), end.strftime("%Y-%m-%d"))
# Each record: DATE, STATION, PRCP (mm), SNOW (mm), TMAX/TMIN (C if metric)
print(len(data), "days")

If your market resolves on a specific definition (e.g. “at least 1 inch of snow at Central Park”), use historical years to estimate the probability for that date or date range. For example: fraction of years where SNOW >= 25.4 (mm) on that day.

Step 2: Find Weather Markets on Polymarket

Polymarket’s Gamma API is public. You can list markets and filter by keyword. Weather markets often include words like “snow”, “temperature”, “rain”, or “weather” in the question.

import requests

GAMMA_URL = "https://gamma-api.polymarket.com/markets"

def get_weather_markets(limit: int = 50) -> list[dict]:
    resp = requests.get(GAMMA_URL, params={
        "active": "true",
        "closed": "false",
        "limit": limit,
    })
    markets = resp.json()
    keywords = ["snow", "rain", "temperature", "weather", "°F", "°C", "inch", "precip"]
    return [
        m for m in markets
        if any(kw in (m.get("question") or "").lower() for kw in keywords)
    ]

weather = get_weather_markets()
for m in weather[:5]:
    q = m.get("question", "")
    prices = m.get("outcomePrices", "[]")
    print(q[:70], "|", prices)

Each market has clobTokenIds (Yes token, No token), conditionId, outcomePrices, and negRisk. You need these to place orders.

Step 3: Compare Your Probability to the Market

Suppose you have a historical probability p_yes (e.g. 0.35 for “at least 1 inch snow on Dec 25 at Central Park”). The market’s current “Yes” price is the implied probability. If outcomePrices is ["0.28", "0.72"], the market implies 28% Yes. If you think 35% is correct, buying Yes at 0.28 has positive expected value (before fees and slippage).

Build a small helper to decide side and price:

def should_buy_yes(my_prob: float, best_ask: float, edge_min: float = 0.05) -> bool:
    """Buy Yes if your prob is above ask by at least edge_min."""
    return my_prob >= best_ask + edge_min

def should_buy_no(my_prob: float, best_bid_yes: float, edge_min: float = 0.05) -> bool:
    """Buy No if 1 - my_prob is above (1 - best_bid_yes)."""
    return (1 - my_prob) >= (1 - best_bid_yes) + edge_min

Use the market’s bestAsk / bestBid when available, or the last trade price. Always leave an edge to cover fees and resolution risk.

Step 4: Place an Order with py_clob_client

To trade you need the official Python CLOB client, a wallet with USDC on Polygon, and POL for gas (or use a gasless relayer). Install:

pip install py-clob-client

Derive API credentials and create a client (see Polymarket Quickstart). Then place a limit order:

from py_clob_client.client import ClobClient
from py_clob_client.clob_types import OrderArgs, OrderType
from py_clob_client.order_builder.constants import BUY
import os

host = "https://clob.polymarket.com"
chain_id = 137  # Polygon
private_key = os.environ["PRIVATE_KEY"]

client = ClobClient(host, key=private_key, chain_id=chain_id)
creds = client.create_or_derive_api_creds()
client = ClobClient(host, key=private_key, chain_id=chain_id, creds=creds, signature_type=0, funder=client.get_address())

# From Step 2: token_id = first element of clobTokenIds (Yes token)
token_id = market["clobTokenIds"][0]   # parse JSON if stored as string
condition_id = market["conditionId"]
market_details = client.get_market(condition_id)
tick_size = str(market_details.get("minimum_tick_size", "0.01"))
neg_risk = market_details.get("neg_risk", False)

response = client.create_and_post_order(
    OrderArgs(
        token_id=token_id,
        price=0.30,   # your limit price (e.g. below your 0.35 fair value)
        size=10.0,    # USDC
        side=BUY,
        order_type=OrderType.GTC,
    ),
    options={"tick_size": tick_size, "neg_risk": neg_risk},
)
print(response.get("orderID"), response.get("status"))

Putting It Together

A minimal flow: (1) get historical NOAA data for the resolution location and date; (2) compute your probability; (3) fetch Polymarket weather markets and match by location/date if possible; (4) if your prob is above the ask (or below the bid for No), place a limit order. You can add api.weather.gov forecasts to blend historical and forecast data for near-term events.

If you’re into pulling other kinds of data for trading, check out our guide to yfinance for stock and fundamental data in Python. For an AI that pulls live financial data and charts on demand, see FinanceWizard.

Disclaimer

This is for educational use only. Prediction markets and trading involve risk. Past weather does not guarantee future outcomes. Only risk what you can afford to lose and do your own research.

Leave a Comment