Detects mispriced sports markets on Polymarket using value-bet signals from The Odds API. Buys when a statistically significant edge exists; exits positions when the signal disappears.
npm install
cp .env.example .envUpdate src/config.ts
See .env.example for full list with defaults.
# Development
npm run dev
# Production
npm run build && npm start- Startup: Fetches the funder wallet's USDC balance on-chain, hydrates team knowledge and open positions, fetches active Polymarket sports markets from Gamma API
- Polling: Every 30s, polls
/v3/value-bets?bookmaker=Polymarketfor markets with positive expected value. Extracts odds event details and feeds them to the matcher - Market matching: Maps Polymarket markets to Odds API events using team knowledge (deterministic); falls back to Claude Haiku for new/unmatched events
- Sizing: Quarter Kelly by default —
bet = bankroll × (edge / (1 − price)) × 0.25, capped atMAX_KELLY_PCT - Exits: Every 5 minutes, checks open positions. If the value-bet signal disappears (event no longer in
/v3/value-bets), evaluates P&L thresholds: take profit, cut loss, lock gains, or exit after prolonged absence - Maintenance: Every 5 minutes, refreshes Gamma markets, re-syncs positions from Data API, refreshes on-chain USDC balance, prunes expired matches
poller.ts — Polls /v3/value-bets, sizes signals, feeds odds events to matcher
market-matcher.ts — Deterministic + LLM fallback matching (Polymarket ↔ Odds API)
team-knowledge.ts — Team abbreviation resolution, h2h outcomeMap cache
exits.ts — Exit logic: value-bet presence check + P&L thresholds
executor.ts — GTD/FAK order placement via Polymarket CLOB
user-stream.ts — Authenticated WS for fill confirmations
position-tracker.ts — Open position tracking (Data API + WS updates)
order-tracker.ts — Resting orders + signal metadata
No database. All state is in-memory with JSON file persistence in ./data/:
match-table.json— Polymarket ↔ Odds API event mappingsteam-knowledge.json— Team abbreviations + h2h outcomeMap cachetrades.jsonl— Append-only signal/trade logerrors.jsonl— Error log
Long-running process on Railway. Use a Railway volume mounted at /data/ so match-table.json and trades.jsonl survive deploys. Positions are hydrated live from the Data API on startup.