TypeScript-native directional arbitrage pipeline and paper auto-trading engine for Polymarket sports markets.
This edition is intentionally built for Node.js operations, npm automation, and JS/TS ecosystem integration.
Polymarket-Sports-Arb-Bot.mp4
This project runs a full research-to-execution flow:
- fetch sports markets from Polymarket Gamma
- filter market rows to arbitrage-relevant candidates
- fetch and merge sportsbook odds data
- detect directional value opportunities
- run paper auto-trading with risk gates
- write persistent journal files for analysis
It is directional trading, not guaranteed risk-free arbitrage.
- npm-first runtime and tooling
- TypeScript contract safety across modules
- easy script orchestration with
tsx - better fit for teams already running JS services
- straightforward integration into dashboards and bots
- Gamma market fetch + flatten
- match-winner and draw-focused filtering
- sport auto-detection from ticker/teams/text
- event matching with confidence score
- odds normalization and bookmaker consolidation
- directional opportunity detection and sell points
- paper-mode auto-trader with risk denials
- live-mode credential guardrails
- JSON, CSV, JSONL output surfaces
src/
cli/ # runnable commands
data/ # fetch and merge adapters
processing/ # matching and strategy math
trading/ # config, engine, journals
utils/ # logger and file helpers
Main loop:
Gamma -> Filter -> Odds Merge -> Detection -> Risk -> Paper Fill -> Journals
- Node.js 20+
- npm 9+
- valid
ODDS_API_KEY
npm install
cp .env.example .envOptional build check:
npm run buildMinimum required:
ODDS_API_KEY=your_odds_api_key
TRADING_MODE=paper
ENABLE_LIVE_TRADING=false
TRADING_DRY_RUN=true| Variable | Default | Purpose |
|---|---|---|
GAMMA_API_URL |
https://gamma-api.polymarket.com |
Market source |
OUTPUT_DIR |
data |
Output directory |
ODDS_API_REGIONS |
us,us_ex |
Odds regions |
ODDS_API_MARKETS |
h2h |
Odds market type |
ODDS_API_MIN_CONFIDENCE |
0.5 |
Match confidence gate |
USE_STORED_EVENTS |
true |
Use cached event files |
EVENTS_DIR |
data/sportsbook_data/events |
Event cache location |
| Variable | Default | Purpose |
|---|---|---|
TRADING_MODE |
paper |
paper or live |
ENABLE_LIVE_TRADING |
false |
Live hard gate |
TRADING_DRY_RUN |
true |
Decision-only mode |
TRADING_STAKE_USD |
25 |
Per-entry size |
TRADING_MAX_POSITIONS |
5 |
Open position cap |
TRADING_MAX_DAILY_LOSS_USD |
100 |
Daily loss cap |
TRADING_MIN_PROFIT |
0.02 |
Min strategy edge |
TRADING_MIN_CONFIDENCE |
0.75 |
Min confidence gate |
TRADING_MIN_LIQUIDITY_USD |
2000 |
Liquidity floor |
TRADING_MAX_SPREAD |
0.03 |
Spread ceiling |
TRADING_CYCLE_SECONDS |
60 |
Loop interval |
TRADING_COMPARISON_PATH |
data/arbitrage_comparison.json |
Trader input |
TRADING_JOURNAL_DIR |
data/trading |
Journal path |
npm run fetch:marketsnpm run filter:marketsnpm run fetch:odds-comparisonnpm run detect:arbnpm run run:auto-trader -- --cycles 1 --dry-runnpm run summarize:sessionnpm run run:full
Standard flow:
npm run fetch:markets
npm run filter:markets
npm run fetch:odds-comparison
npm run detect:arb
npm run run:auto-trader -- --cycles 1 --dry-run
npm run summarize:sessionPaper fills (still simulated):
TRADING_DRY_RUN=false npm run run:auto-trader -- --cycles 3One command:
npm run run:fulldata/ artifacts:
sports_markets.json/csvarbitrage_data.json/csvarbitrage_data_filtered.json/csvarbitrage_comparison.json/csvdirectional_arbitrage.json
data/trading/ journals:
signals.jsonlrisk_events.jsonlorders.jsonlfills.jsonlpositions.jsonlstate.json
Live startup is blocked unless:
TRADING_MODE=liveENABLE_LIVE_TRADING=true- private key exists (
PRIVATE_KEYorPK) - proxy wallet exists (
POLYMARKET_PROXY_ADDRESSorBROWSER_ADDRESS)
And in this TS build, live execution still exits intentionally because adapter implementation is deferred.
Usually invalid/missing ODDS_API_KEY.
echo $ODDS_API_KEYUpdate .env, then rerun npm run fetch:odds-comparison.
The trader was started before comparison generation.
Run:
npm run fetch:markets
npm run filter:markets
npm run fetch:odds-comparisonInspect data/trading/risk_events.jsonl.
Tune gradually:
TRADING_MAX_POSITIONSTRADING_MIN_CONFIDENCETRADING_MAX_SPREADTRADING_MIN_LIQUIDITY_USD
Recommended progression:
- run with
TRADING_DRY_RUN=true - observe deny reasons and signal quality
- adjust one threshold at a time
- switch to
TRADING_DRY_RUN=falsein paper mode - compare session summaries across multiple runs
- Never commit private keys.
- Keep
.envlocal. - Rotate exposed credentials immediately.
- Treat live-mode rollout as a production security event.
- real live execution adapter with explicit order routing
- better soccer alias normalization for matching quality
- richer risk/exit parity with advanced engines
- broader test coverage for pipeline + CLI
For research and automation development only. Not financial advice. Use paper mode first.