CLAUDE.md 6.1 KB

Poly Weather — Polymarket Weather Arbitrage Bot

Project Overview

Automated weather prediction market trading bot that exploits pricing inefficiencies in Polymarket's daily temperature markets. Compares professional weather forecast model probabilities (GFS/ECMWF/ICON ensembles) against market-implied probabilities and trades the delta.

Three Strategies

  • TAIL_NO — Buy NO on overpriced tail buckets (e.g. "56°F or higher") where model prob < 5% but market prices YES > 3¢
  • LATENCY_ARB — Trade when new weather model data shifts probabilities >5% but market hasn't repriced yet
  • PARITY_ARB — Exploit when sum of all YES prices in an event deviates from 100¢ (pure arbitrage)

Architecture

TypeScript monorepo using Turborepo + pnpm workspaces.

packages/
  core/             — Shared types, utils, Prisma schema, constants
  weather-engine/   — GFS/ECMWF/ICON forecast fetching via Open-Meteo, ensemble probability calculation
  market-engine/    — Polymarket Gamma API scanning, CLOB orderbook reads, authenticated order placement
  strategy/         — Signal generation (Tail NO, Latency Arb, Parity Arb), risk management, Kelly sizing
  trading-engine/   — Main bot loop, pipeline orchestration, health-check server
  dashboard/        — Next.js App Router dashboard with live market data, signals, manual order placement

Dependency Graph

core (leaf — no internal deps)
  ↑
weather-engine, market-engine (depend on core)
  ↑
strategy (depends on core + weather-engine + market-engine)
  ↑
trading-engine (depends on all above)
dashboard (depends on core, reads DB directly)

Tech Stack

  • Runtime: Node.js ≥ 20, TypeScript (ES2022, NodeNext modules, strict)
  • Monorepo: pnpm workspaces + Turborepo
  • Database: PostgreSQL 16 (Prisma ORM) + Redis 7
  • Dashboard: Next.js 14 (App Router), Tailwind CSS, next-themes (light/dark), Radix UI primitives
  • Market APIs: Polymarket Gamma API (market discovery), CLOB API (orderbook + trading)
  • Weather APIs: Open-Meteo (GFS, ECMWF, ICON models)
  • Trading: @polymarket/clob-client, ethers (wallet signing)

Key Commands

pnpm install                  # Install all deps
pnpm build                    # Build all packages (turbo)
pnpm dev                      # Dev mode all packages
pnpm docker:up                # Start PostgreSQL + Redis
pnpm db:push                  # Push Prisma schema to DB
pnpm db:studio                # Open Prisma Studio
pnpm bot:start                # Start trading bot
pnpm dashboard:dev            # Start dashboard on :3000
pnpm derive-keys              # Derive L2 API keys from PRIVATE_KEY
pnpm test                     # Run all tests

Database Schema (Prisma)

Located at packages/core/prisma/schema.prisma.

  • WeatherForecast — Stored model forecasts (city, date, model, predictedHigh, stdDev)
  • MarketSnapshot — Point-in-time market prices (yesPrice, noPrice, volume, tokenIds)
  • Signal — Detected trading signals (type, city, bucket, edge, modelProb, marketPrice, executed)
  • Trade — Order records (side, tokenId, price, size, costBasis, status, dryRun, pnl)
  • DailyMetrics — Aggregated daily performance (trades, winRate, netPnl, maxDrawdown)

Dashboard Structure

src/app/
  layout.tsx          — Root layout with Sidebar + ThemeProvider
  page.tsx            — Dashboard home (summary cards, recent signals)
  signals/            — Signal history with strategy filters + manual order placement
  markets/            — Live market data from Polymarket Gamma API + orderbook viewer
  pnl/                — PnL charts and performance metrics
  api/
    dashboard/        — GET summary stats
    signals/          — GET signal history
    markets/          — GET DB market snapshots
    live-markets/     — GET live Polymarket data via Gamma API
    orderbook/        — GET merged YES/NO orderbook from CLOB
    prices/           — POST fetch latest prices for selected signals
    orders/           — POST place orders (dry run or live)

Dashboard Features

  • Light/Dark theme via next-themes with class attribute strategy
  • Neg-risk orderbook merging: YES bids = direct YES bids ∪ (1 − NO asks)
  • Manual order placement: Multi-select signals → fetch live prices → choose limit/market → confirm → execute (works in DRY_RUN)
  • Polymarket deep links: Direct links to specific market events using city slug mapping

Important Conventions

  • DRY_RUN=true by default — All signal detection and DB recording works, but no real orders are placed
  • Temperature units — NYC/Chicago/Miami/Houston/Denver/LA/Phoenix/Seattle = °F, others = °C
  • Maker orders only — Limit orders (GTC) on Polymarket to pay zero fees
  • All timestamps UTC — Local timezone only in dashboard display
  • Error isolation — One city/market failing must not block others
  • City slug overrides — new_york → nyc in Polymarket URLs (see citySlugOverrides in queries.ts)

CSS Theme System

Uses Tailwind darkMode: 'class' with custom component classes in globals.css:

  • .card, .badge-*, .table-header, .table-cell, .btn-* — All have light + .dark variants
  • .text-heading, .text-body, .text-sub, .text-dim — Theme-aware text colors
  • Always use dark: prefix for dark-mode-specific colors inline

Environment Variables

See .env.example for all required variables. Key ones:

  • DATABASE_URL — PostgreSQL connection
  • PRIVATE_KEY + FUNDER_ADDRESS — Polymarket wallet (for live trading)
  • DRY_RUN — true (default) to simulate, false for real orders
  • SIGNATURE_TYPE — 1 for POLY_PROXY (standard Polymarket exported wallets)

Polymarket Integration Notes

  • Gamma API (gamma-api.polymarket.com) — Market discovery, no auth needed
  • CLOB API (clob.polymarket.com) — Orderbook reads (no auth), order placement (requires wallet auth)
  • Neg-risk markets have separate YES and NO token IDs; orderbooks must be merged for accurate pricing
  • Market URL pattern: https://polymarket.com/event/highest-temperature-in-{city-slug}-on-{month}-{day}-{year}