Skip to main content
This guide covers setting up your environment to run the Polymarket Bot, including directory structure, logging configuration, data persistence, and production deployment considerations.

Prerequisites

System Requirements

  • Node.js: v18.0.0 or higher (ESM support required)
  • Package manager: pnpm (recommended) or npm
  • OS: Linux, macOS, or Windows (WSL recommended)
  • Disk space: 1-5 GB for logs and tick data (grows over time)
  • Network: Stable internet connection for WebSocket feeds

Installing Node.js

brew install node@20

Installing pnpm

npm install -g pnpm

Project Setup

Clone and Install

# Clone repository
git clone <repository-url>
cd polymarket-bot

# Install dependencies
pnpm install

# Verify installation
pnpm start --help

Dependencies

The bot has minimal dependencies (see package.json):
{
  "dependencies": {
    "chalk": "^5.6.2",   // Terminal colors
    "ws": "^8.19.0"      // WebSocket client
  },
  "devDependencies": {
    "@types/ws": "^8.18.1"  // TypeScript types
  }
}

Directory Structure

The bot expects the following directory structure:
polymarket-bot/
├── src/                 # Source code
├── config/              # Configuration files
│   └── default.json     # Main config (version controlled)
├── data/                # Auto-created data directory
│   ├── history.json     # Interval history (persistent)
│   ├── logs/            # Daily log files
│   │   ├── bot-2026-03-01.log
│   │   ├── bot-2026-03-02.log
│   │   └── ...
│   └── ticks/           # Raw tick data (optional)
│       ├── ticks-2026-03-01.jsonl
│       └── ...
└── package.json

Auto-Created Directories

The bot automatically creates directories as needed:
// From src/logger/logger.js
const LOG_DIR = join(__dirname, '..', '..', 'data', 'logs')
mkdirSync(LOG_DIR, { recursive: true })
Directories created on first run:
  • data/ — Root data directory
  • data/logs/ — Log files
  • data/ticks/ — Tick data (if tick logging is enabled)
You don’t need to manually create these directories. The bot handles it automatically.

Configuration

Configuration File Location

Configuration is loaded from config/default.json (see src/config.js:6):
const config = JSON.parse(
  readFileSync(join(__dirname, '..', 'config', 'default.json'), 'utf8')
)
Key points:
  • No environment variable overrides (all config in JSON)
  • Single source of truth: config/default.json
  • Changes require bot restart (no hot reloading)

Customizing Configuration

Edit config/default.json directly:
{
  "engine": {
    "abstention": {
      "minEV": 0.03,
      "minMargin": 0.10
    }
  },
  "bot": {
    "loopIntervalMs": 500
  }
}
Restart the bot to apply changes:
pnpm start

Initial Bankroll

Update the bankroll to match your trading capital:
{
  "risk": {
    "bankroll": 100  // Change to your starting capital in USD
  }
}
The bot does not connect to your Polymarket account. It only simulates bet sizing. You must manually execute trades on Polymarket based on the bot’s recommendations.

Logging

Log Structure

The bot uses a dual-logging system:
  1. Console output: Real-time display (stdout/stderr)
  2. File output: Daily rotating log files in data/logs/

Log Format

Logs use structured format with ISO timestamps (see src/logger/logger.js:14-17):
[2026-03-04T10:23:45.123Z] [INFO] WebSocket connected {"feed":"chainlink"}
[2026-03-04T10:23:46.234Z] [WARN] Market price stale {"age":12.5}
[2026-03-04T10:23:47.345Z] [ERROR] API request failed {"status":503,"url":"https://..."}
Format: [timestamp] [level] message {context}

Log Levels

LevelPurposeOutput
INFONormal operations, predictions, betsstdout + file
WARNRecoverable issues (stale data, spikes)stderr + file
ERRORErrors requiring attentionstderr + file

Accessing Logs

# View today's log
tail -f data/logs/bot-$(date +%Y-%m-%d).log

# Search for errors
grep ERROR data/logs/bot-2026-03-04.log

# Filter by context
grep 'abstained' data/logs/bot-2026-03-04.log | jq

Log Rotation

Logs are automatically rotated daily based on filename:
function getLogPath() {
  const date = new Date().toISOString().split('T')[0]
  return join(LOG_DIR, `bot-${date}.log`)
}
Behavior:
  • New file created at midnight (UTC)
  • No automatic deletion (manual cleanup required)
  • No size-based rotation (files grow unbounded per day)

Managing Log Growth

# Delete logs older than 30 days
find data/logs -name 'bot-*.log' -mtime +30 -delete
Production recommendation: Set up a cron job to compress logs older than 7 days and delete logs older than 90 days.

Data Persistence

Interval History

The bot stores all resolved intervals in data/history.json (configurable via storage.historyPath). Format: JSON array of interval objects:
[
  {
    "intervalNumber": 1,
    "targetPrice": 64232.50,
    "finalPrice": 64315.20,
    "outcome": "UP",
    "prediction": {
      "probability": 0.72,
      "direction": "UP",
      "capturedAt": "2026-03-04T10:24:30Z"
    },
    "marketPrice": 0.68,
    "ev": 0.059,
    "betSize": 2.50,
    "accuracy": true,
    "brierScore": 0.078,
    "...": "30+ fields total"
  }
]

History File Management

history.json grows continuously. A typical day generates 288 intervals (24h × 12 per hour). At ~1KB per interval, expect ~100KB per day or ~3MB per month.
Backup strategy:
# Daily backup (add to cron)
cp data/history.json data/backups/history-$(date +%Y-%m-%d).json

# Compress old backups
gzip data/backups/history-*.json
Archiving old data:
# Archive intervals older than 90 days to separate file
node scripts/archive-history.js --days 90

Tick Data (Optional)

Raw tick data can be logged to JSONL files for backtesting:
{"timestamp":1709550123456,"price":64232.50,"source":"chainlink"}
{"timestamp":1709550124567,"price":64233.12,"source":"chainlink"}
Enable tick logging: Tick logging is not included in the default configuration. To enable, modify src/feeds/chainlink.js to import and use src/logger/tick-logger.js.
Only enable tick logging if you plan to backtest or analyze tick-level data. It generates ~50MB per day at 1 tick/second.

Running the Bot

Development Mode

# Start with auto-reload on file changes
pnpm dev

# Equivalent to:
node --watch src/index.js
Use case: Local development, testing config changes

Production Mode

# Start normally
pnpm start

# Equivalent to:
node src/index.js

Background Execution

nohup pnpm start > output.log 2>&1 &

# Check process
ps aux | grep node

# Stop
kill <pid>

Monitoring

Health checks:
# Check if process is running
pgrep -f 'node src/index.js'

# Check last log entry (should be recent)
tail -n 1 data/logs/bot-$(date +%Y-%m-%d).log

# Check WebSocket connection
grep 'WebSocket' data/logs/bot-$(date +%Y-%m-%d).log | tail -n 5
Alert on errors:
# Count errors in last hour
grep ERROR data/logs/bot-$(date +%Y-%m-%d).log | tail -n 100 | wc -l

# Alert if > 10 errors
if [ $(grep ERROR data/logs/bot-$(date +%Y-%m-%d).log | tail -n 100 | wc -l) -gt 10 ]; then
  echo "High error rate detected" | mail -s "Bot Alert" [email protected]
fi

Performance Optimization

Memory Usage

Expected memory footprint:
  • Base: 50-80 MB
  • With 300-tick momentum buffer: +5-10 MB
  • With Platt scaler (200+ samples): +2-5 MB
Total: ~100 MB RSS
The bot is designed for low memory usage. If you see >200 MB, check for memory leaks in custom modifications.

CPU Usage

Expected CPU usage:
  • Idle (waiting for ticks): <1%
  • Active (processing ticks): 2-5%
  • Prediction calculation: <1ms per tick
Bottlenecks:
  • WebSocket parsing (unavoidable)
  • JSON serialization for logging (reduce log verbosity if needed)
  • Momentum buffer operations (reduce bufferSize if needed)

Network

Bandwidth usage:
  • Chainlink WebSocket: ~1 KB/s (continuous)
  • Polymarket API polls: ~5 KB/5s (intermittent)
Total: <100 MB per day

Production Checklist

Before deploying to production:
  • Configuration reviewed: Tune parameters based on backtest results
  • Bankroll set correctly: Update risk.bankroll to match trading capital
  • Log rotation configured: Set up daily compression and 90-day deletion
  • History backups enabled: Daily backup of history.json
  • Systemd service created: Auto-start on boot, restart on failure
  • Monitoring alerts set up: Email or Slack alerts for high error rates
  • Disk space allocated: At least 5 GB for logs and history (3-6 months)
  • Network stability verified: Test WebSocket connection reliability
  • Manual trading workflow documented: How to execute bot recommendations on Polymarket

Troubleshooting

Bot won’t start

# Check Node.js version
node --version  # Should be v18.0.0 or higher

# Check dependencies
pnpm install

# Check config file syntax
node -e "console.log(JSON.parse(require('fs').readFileSync('config/default.json')))"

WebSocket connection issues

# Check logs for connection errors
grep 'WebSocket' data/logs/bot-$(date +%Y-%m-%d).log

# Test connectivity
curl -I https://ws-live-data.polymarket.com

# Check firewall (port 443 must be open)
telnet ws-live-data.polymarket.com 443

High abstention rate

# Analyze abstention reasons
grep 'abstained' data/logs/bot-$(date +%Y-%m-%d).log | jq -r .reason | sort | uniq -c

# Common fixes:
# - Too many dead_zone: Decrease engine.abstention.deadZone
# - Too many insufficient_margin: Decrease engine.abstention.minMargin
# - Too many anomalous_regime: Increase engine.abstention.sigmaMultiplier

Poor prediction accuracy

# Generate daily report
node src/reporter/daily.js 2026-03-04

# Check Brier Score (should be < 0.22)
# If Brier > 0.22: Tune logit weights (see Tuning Parameters guide)
# If accuracy < 70%: Increase abstention thresholds

Next Steps

Config Reference

Complete reference for all configuration parameters.

Tuning Parameters

Learn how to optimize the bot for your market conditions.

Build docs developers (and LLMs) love