AI-powered news trading bot for Polymarket prediction markets.
PolyGoblin monitors breaking news, matches stories to active prediction markets, and uses AI (Claude/GPT-4) to estimate probability impacts. When it detects a gap between AI estimates and market prices, it calculates expected value and either alerts or auto-trades.
How it works:
- Ingest — Poll RSS feeds, Finlight API, or accept manual submissions
- Match — Find relevant markets using keyword extraction and similarity scoring
- Analyze — Send news + market context to Claude/GPT-4 for probability estimation
- Calculate — Compute expected value and Kelly-optimal position size
- Trade — Queue for approval (simulation) or execute automatically (live)
Trading modes:
simulation— Paper trades with virtual bankroll; all actions loggedlive— Real trades via Polymarket CLOB (requires wallet key)
| Feature | Description |
|---|---|
| News ingestion | RSS feeds, Finlight API, manual submissions |
| Market matching | Keyword extraction + trigram similarity scoring |
| AI analysis | Claude (Anthropic) or GPT-4 (OpenAI) probability estimation |
| Expected value | (p_est - p_market) * payout - (1 - p_est) * stake |
| Position sizing | Kelly Criterion with configurable multiplier |
| Order execution | Polymarket CLOB client with slippage protection |
| Feature | Description |
|---|---|
| Kill switch | Halt all trading instantly (file, SIGUSR1, or API) |
| Drawdown protection | Warning at 15%, auto-halt at 30% of peak equity |
| Circuit breakers | Per-service fault tolerance (Polymarket, LLM, RSS, Finlight) |
| Graceful shutdown | SIGTERM/SIGINT handling; completes in-flight operations |
| Preflight checks | Validates config, API keys, and DB before trading |
| Feature | Description |
|---|---|
| Equity snapshots | 5-minute portfolio snapshots with position details |
| LLM calibration | Track prediction accuracy with Brier score |
| Activity log | Audit trail for all system events |
| Alerts | Telegram and Discord notifications |
| Feature | Description |
|---|---|
| WebSocket prices | Live order book updates from Polymarket |
| Market snapshots | Historical price/liquidity data for backtesting |
| Backtest engine | Replay strategies against historical data |
| Performance metrics | PnL, win rate, Sharpe ratio, max drawdown |
News Sources Polymarket
(RSS/Finlight) API/WS
│ │
▼ ▼
┌─────────┐ ┌──────────┐
│ News │ │ Market │
│Ingestion│ │ Sync │
└────┬────┘ └────┬─────┘
│ │
▼ ▼
┌─────────────────────────────┐
│ Matching Service │
│ (keywords, similarity, EV) │
└──────────────┬──────────────┘
│
▼
┌─────────────────────────────┐
│ LLM Analysis │
│ (Claude/GPT-4 probability) │
└──────────────┬──────────────┘
│
▼
┌─────────────────────────────┐
│ Trading Engine │
│ (Kelly sizing, execution) │
└──────────────┬──────────────┘
│
▼
PostgreSQL
| Component | Technology |
|---|---|
| Runtime | Bun |
| Framework | ElysiaJS |
| Database | PostgreSQL 16+ (with pg_trgm) |
| Language | TypeScript (strict mode) |
| Scheduling | Croner |
| Polymarket | @polymarket/clob-client |
With Docker (recommended):
git clone <repo-url>
cd polygoblin
cp .env.example .env
# Edit .env with your settings
docker compose up -dOpen http://localhost:3000/admin and log in with ADMIN_PASSWORD.
Manual setup: See Local Setup below.
| Variable | Required | Default | Description |
|---|---|---|---|
DATABASE_URL |
Yes | — | PostgreSQL connection string |
PORT |
No | 3000 | Server port |
HOST |
No | 0.0.0.0 | Server bind address |
ADMIN_PASSWORD |
No | admin | Dashboard login password |
API_KEY |
No | dev-key | API authentication key |
ANTHROPIC_API_KEY |
No | — | Claude API key for LLM analysis |
OPENAI_API_KEY |
No | — | GPT-4 API key (alternative to Claude) |
FINLIGHT_API_KEY |
No | — | Finlight news API key |
POLYMARKET_PRIVATE_KEY |
No | — | Wallet private key for live trading |
TELEGRAM_BOT_TOKEN |
No | — | Telegram bot token for alerts |
TELEGRAM_CHAT_ID |
No | — | Telegram chat ID for alerts |
DISCORD_WEBHOOK_URL |
No | — | Discord webhook for alerts |
Configurable via API (PUT /api/settings) or admin dashboard:
| Setting | Default | Description |
|---|---|---|
trading_mode |
simulation | simulation or live |
auto_trade_enabled |
false | Auto-execute approved trades |
min_expected_value |
0.05 | Minimum EV to consider (5%) |
max_bet_size |
50 | Maximum trade size in USDC |
kelly_multiplier |
0.25 | Fraction of Kelly (0.25 = quarter Kelly) |
min_liquidity |
5000 | Minimum market liquidity in USDC |
max_drawdown_pct |
0.30 | Drawdown threshold to halt trading (30%) |
drawdown_warning_pct |
0.15 | Drawdown threshold for warning (15%) |
slippage_tolerance |
0.05 | Maximum acceptable slippage (5%) |
virtual_bankroll |
1000 | Starting bankroll for simulation |
llm_provider |
anthropic | anthropic or openai |
enabled_news_sources |
["rss"] | Active news sources |
use_websocket_prices |
true | Use WebSocket for live prices |
All /api/* endpoints require authentication via X-API-Key header or Authorization: Bearer <key>.
| Endpoint | Method | Description |
|---|---|---|
/health |
GET | Health check (no auth required) |
/api/status |
GET | System status, stats, open positions |
/api/preflight |
GET | Run preflight checks |
| Endpoint | Method | Description |
|---|---|---|
/api/settings |
GET | Get all runtime settings |
/api/settings |
PUT | Update settings (JSON body) |
| Endpoint | Method | Description |
|---|---|---|
/api/news |
GET | List news items (?limit=20) |
/api/news |
POST | Submit manual news ({title, content, url?}) |
| Endpoint | Method | Description |
|---|---|---|
/api/markets |
GET | List markets (?q=search&limit=50) |
/api/markets/:id |
GET | Get market details |
| Endpoint | Method | Description |
|---|---|---|
/api/opportunities |
GET | List opportunities (?status=pending&limit=20) |
/api/opportunities/:id/approve |
POST | Approve and execute trade |
/api/opportunities/:id/reject |
POST | Reject opportunity |
/api/opportunities/:id/analyze |
POST | Queue for LLM analysis |
| Endpoint | Method | Description |
|---|---|---|
/api/trades |
GET | List trades (?status=filled&outcome=won) |
/api/activity |
GET | Activity log (?limit=50) |
| Endpoint | Method | Description |
|---|---|---|
/api/trigger/news |
POST | Poll news sources now |
/api/trigger/markets |
POST | Sync markets now |
/api/trigger/prices |
POST | Update prices now |
/api/trigger/analyze |
POST | Run analysis batch |
/api/trigger/opportunities |
POST | Process opportunities |
/api/trigger/snapshot |
POST | Capture equity snapshot |
/api/trigger/drawdown |
POST | Check drawdown |
/api/trigger/calibration |
POST | Check LLM calibration |
| Endpoint | Method | Description |
|---|---|---|
/api/kill-switch |
GET | Get kill switch state |
/api/kill-switch/activate |
POST | Activate kill switch ({reason?}) |
/api/kill-switch/deactivate |
POST | Deactivate kill switch ({reason?}) |
/api/drawdown |
GET | Get drawdown state |
/api/drawdown/reset-peak |
POST | Reset peak equity |
/api/circuit-breakers |
GET | List all circuit breaker states |
/api/circuit-breakers/:name |
GET | Get specific circuit state |
/api/circuit-breakers/:name/reset |
POST | Reset circuit breaker |
| Endpoint | Method | Description |
|---|---|---|
/api/snapshots |
GET | List equity snapshots |
/api/snapshots/:id |
GET | Get snapshot details |
/api/snapshots/:id/positions |
GET | Get position details for snapshot |
/api/equity-timeseries |
GET | Equity over time (?hours=24) |
/api/calibration |
GET | LLM calibration report |
/api/calibration/records |
GET | Individual calibration records |
/api/alerts/test |
POST | Send test alert |
| Endpoint | Method | Description |
|---|---|---|
/api/websocket/status |
GET | WebSocket connection status |
/api/websocket/connect |
POST | Connect to Polymarket WS |
/api/websocket/disconnect |
POST | Disconnect WebSocket |
/api/websocket/reconnect |
POST | Reconnect WebSocket |
| Endpoint | Method | Description |
|---|---|---|
/api/backtest/data-range |
GET | Available data range |
/api/backtest/capture-snapshot |
POST | Capture market snapshot |
/api/backtest/runs |
GET | List backtest runs |
/api/backtest/runs |
POST | Create backtest run |
/api/backtest/runs/:id |
GET | Get run details with trades |
/api/backtest/runs/:id/start |
POST | Start backtest execution |
/api/backtest/runs/:id |
DELETE | Delete backtest run |
/api/backtest/runs/:id/compare/:otherId |
GET | Compare two runs |
| Table | Purpose |
|---|---|
news_items |
Ingested news articles |
markets |
Polymarket markets with prices/liquidity |
opportunities |
News-market matches with analysis |
trades |
Executed trades (simulated and live) |
settings |
Runtime configuration |
system_state |
Kill switch persistence |
activity_log |
Audit trail |
equity_snapshots |
Portfolio snapshots |
position_snapshots |
Per-position data at snapshot time |
llm_calibration |
LLM prediction vs actual outcome |
circuit_breaker_state |
Circuit breaker persistence |
backtest_market_snapshots |
Historical market data |
backtest_runs |
Backtest configurations |
backtest_trades |
Simulated backtest trades |
backtest_metrics |
Aggregated backtest results |
Three activation methods:
- File: Create
/tmp/polygoblin-killfile - Signal: Send
SIGUSR1to the process - API:
POST /api/kill-switch/activate
When active, all trading operations halt immediately. Clear via API or remove the file.
- Warning threshold (15%): Sends alert, continues trading
- Halt threshold (30%): Activates kill switch automatically
Reset peak equity via POST /api/drawdown/reset-peak after adding capital.
Per-service fault tolerance with three states:
- Closed: Normal operation
- Open: Service unavailable, requests fail fast
- Half-open: Testing recovery
Default circuits: polymarket_gamma, polymarket_clob, llm, rss, finlight
On SIGTERM/SIGINT:
- Stop accepting new tasks
- Complete in-flight operations
- Close database connections
- Exit cleanly
| Interval | Task |
|---|---|
| 5 min | Poll news sources |
| 5 min | Sync markets |
| 5 min | Capture equity snapshot |
| 3 min | Update prices |
| 2 min | Analyze pending opportunities |
| 2 min | Process opportunities |
| 1 min | Check drawdown |
| 15 min | Capture backtest market snapshots |
| 1 hour | Check trade resolutions |
| 4 hours | Update LLM calibration |
| Daily 3am | Database cleanup |
src/
adapters/ # External service interfaces
news.ts # RSS/Finlight/Manual adapters
llm.ts # Claude/OpenAI adapters
polymarket.ts # Polymarket API client
polymarket-ws.ts # WebSocket client
services/ # Business logic
scheduler.ts # Background task scheduling
ingestion.ts # News processing
matching.ts # News-to-market matching
analysis.ts # LLM analysis
trading.ts # Trade execution
markets.ts # Market sync
snapshots.ts # Equity snapshots
backtest.ts # Backtest engine
db/
schema.sql # PostgreSQL schema
client.ts # Database client + queries
web/
routes.ts # API endpoints
admin.ts # Admin dashboard
lib/
keywords.ts # Keyword extraction
ev.ts # Expected value calculation
kelly.ts # Position sizing
events.ts # Internal event bus
killswitch.ts # Kill switch
drawdown.ts # Drawdown monitor
circuit-breaker.ts # Circuit breakers
preflight.ts # Preflight checks
alerts.ts # Telegram/Discord alerts
types.ts # TypeScript interfaces
config.ts # Environment configuration
index.ts # Application entry point
Prerequisites: Bun, PostgreSQL 16+
-
Configure environment:
cp .env.example .env
Edit
.envand setDATABASE_URL,ADMIN_PASSWORD,API_KEY. Optional: LLM and trading keys. -
Create database:
bash scripts/init-db.sh
Override if needed:
PSQL_BIN=/opt/homebrew/opt/postgresql@17/bin/psql \ PGUSER_NAME=johny \ ROLE_NAME=polygoblin \ DB_NAME=polygoblin \ ROLE_PASSWORD=polygoblin \ bash scripts/init-db.sh
-
Load schema:
psql "$DATABASE_URL" -f src/db/schema.sql -
Install and run:
bun install bun run dev
Production:
bun src/index.ts -
Open admin:
http://localhost:3000/admin
-
Set secrets in
.env:ADMIN_PASSWORDAPI_KEY- Optional:
ANTHROPIC_API_KEY,OPENAI_API_KEY,FINLIGHT_API_KEY,POLYMARKET_PRIVATE_KEY
-
Build and run:
docker compose up -d --build
-
App available on port 3000. Postgres data persists in
pgdatavolume.
- Provision PostgreSQL and load
src/db/schema.sql - Set
DATABASE_URLand secrets on the host - Run
bun src/index.tsunder a process manager (systemd, PM2, etc.)
- Backups: Schedule
pg_dump "$DATABASE_URL"to object storage; keep 7 daily + 4 weekly snapshots - Monitoring: Watch logs for
*_erroractivity events; track health via/healthand/api/status - Upgrades: Stop service, run schema changes, restart; keep
src/db/schema.sqlaligned - Live trading safety: Start in
simulation, capmax_bet_size, setauto_trade_enabled=falseuntil confident
MIT