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.
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
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)
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
Located at packages/core/prisma/schema.prisma.
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)
class attribute strategynew_york → nyc in Polymarket URLs (see citySlugOverrides in queries.ts)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 colorsdark: prefix for dark-mode-specific colors inlineSee .env.example for all required variables. Key ones:
DATABASE_URL — PostgreSQL connectionPRIVATE_KEY + FUNDER_ADDRESS — Polymarket wallet (for live trading)DRY_RUN — true (default) to simulate, false for real ordersSIGNATURE_TYPE — 1 for POLY_PROXY (standard Polymarket exported wallets)gamma-api.polymarket.com) — Market discovery, no auth neededclob.polymarket.com) — Orderbook reads (no auth), order placement (requires wallet auth)https://polymarket.com/event/highest-temperature-in-{city-slug}-on-{month}-{day}-{year}