Skip to content

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

@calebpanza/polymarket-bot

Production-grade Polymarket copy-trading bot optimized for always-on deployment on a Raspberry Pi 3.

Monitors 1–5 target wallets, copies BUY trades into your burner wallet, and stores everything in a local SQLite database. DRY_RUN=true by default — it never places real orders unless you explicitly opt in.


Features

  • Copy-trade any Polymarket wallet with configurable sizing (fixed USD or scaled)
  • Exposure cap prevents runaway spending
  • Market filter by keywords (only copy markets you care about)
  • SQLite database for all state — no JSON files, no cloud dependencies
  • Built-in web dashboard for LAN visibility (optional)
  • CLI commands for status checks and ad-hoc DB queries
  • Pi-optimized: WAL mode, infrequent writes, <300 MB total RAM

Quick Start

1. Install globally from your private GitHub repo

# Authenticate with GitHub Packages (one time)
echo "//npm.pkg.github.com/:_authToken=YOUR_GITHUB_PAT" >> ~/.npmrc

# Install globally
npm install -g @calebpanza/polymarket-bot

2. Configure

Create a .env file in the directory where you'll run the bot:

cp .env.example .env
# Edit .env with your target wallets (PRIVATE_KEY is optional for dry-run)

Minimal dry-run config — no private key needed:

TARGET_WALLETS=0xSomeWhaleAddress
DRY_RUN=true

3. Run

# Start in dry-run mode (default — safe, no real orders, no key needed)
polymarket-bot start

# Check status from another terminal
polymarket-bot status

# Query the database directly
polymarket-bot db-query "SELECT * FROM copied_trades ORDER BY timestamp DESC LIMIT 20"

Configuration

All configuration is via environment variables (loaded from .env):

Variable Default Description
PRIVATE_KEY '' Hex private key of your burner wallet (only required when DRY_RUN=false)
TARGET_WALLETS required Comma-separated wallet addresses to copy (1–5)
POLL_INTERVAL_MS 30000 Polling interval in milliseconds
COPY_MODE fixed fixed = always copy FIXED_COPY_USD; scaled = originalSize * SCALE_FACTOR
FIXED_COPY_USD 4.00 Amount to copy per trade (fixed mode)
SCALE_FACTOR 0.10 Multiplier for original trade size (scaled mode)
MIN_COPY_USD 2.00 Minimum copy size (scaled mode floor)
MAX_COPY_USD 5.00 Maximum copy size (scaled mode ceiling)
MAX_TOTAL_EXPOSURE_USD 15.00 Total USD exposure cap across all positions
FILTER_KEYWORDS election,politics,crypto,trump Only copy markets matching these keywords
DRY_RUN true Safe default — logs trades but never places orders
DB_PATH ./bot-state.db Path to the SQLite database file
ENABLE_WEB false Start the built-in web dashboard
WEB_PORT 3001 Dashboard port (only when ENABLE_WEB=true)
CLOB_API_URL https://clob.polymarket.com Polymarket CLOB API endpoint
DATA_API_URL https://data-api.polymarket.com Polymarket data API endpoint
CHAIN_ID 137 Polygon chain ID

CLI Commands

# Start the bot (foreground process)
polymarket-bot start

# Show current exposure and recent trades from the DB
polymarket-bot status

# Run any SQL query against the database
polymarket-bot db-query "SELECT * FROM copied_trades WHERE dry_run = 0"
polymarket-bot db-query "SELECT * FROM exposure_log ORDER BY timestamp DESC LIMIT 10"
polymarket-bot db-query "SELECT * FROM wallet_last_seen"

Viewing the Database

Option 1: Built-in Web Dashboard (recommended)

Set ENABLE_WEB=true in your .env, then open your browser:

http://raspberrypi.local:3001

Or use your Pi's IP address: http://192.168.1.X:3001

The dashboard shows:

  • Current exposure vs. cap
  • Dry-run status
  • Number of monitored wallets
  • Uptime
  • Last 50 copied trades in a table

The dashboard runs in the same process — adds <30 MB RAM on a Pi 3.

Option 2: sqlite3 CLI

Pre-installed on most Linux systems, or install with:

sudo apt install sqlite3

Then query directly:

# View recent trades
sqlite3 bot-state.db "SELECT * FROM copied_trades ORDER BY timestamp DESC LIMIT 20;"

# Check exposure
sqlite3 bot-state.db "SELECT SUM(copied_size) FROM copied_trades WHERE dry_run = 0;"

# See what the bot last saw per wallet
sqlite3 bot-state.db "SELECT * FROM wallet_last_seen;"

# Pretty-print with headers and columns
sqlite3 -header -column bot-state.db "SELECT timestamp, market, copied_size, dry_run FROM copied_trades ORDER BY timestamp DESC LIMIT 10;"

Option 3: DB Browser for SQLite (GUI)

Install on your Pi (if you have a desktop environment):

sudo apt install sqlitebrowser

Or copy the DB file to your laptop:

scp pi@raspberrypi.local:~/bot-state.db ./

Then open it in DB Browser for SQLite on macOS/Windows/Linux for a full graphical view.

Option 4: CLI db-query command

polymarket-bot db-query "SELECT timestamp, market, copied_size, side, dry_run FROM copied_trades ORDER BY timestamp DESC LIMIT 20"

A note on cloud databases

You might be tempted to use Supabase or another hosted database. For a local $20 play-money bot on a Pi, this adds unnecessary complexity:

  • Requires constant internet connectivity
  • Adds network latency to every write
  • External dependency and privacy concerns
  • Free tier limits

If you later want remote access, consider PocketBase (single Go binary with SQLite + admin UI) or Turso (distributed SQLite). But for this use case, local SQLite + the built-in dashboard gives you perfect visibility while keeping everything offline-capable and lightweight.


Database Schema

wallet_last_seen

Column Type Description
wallet TEXT PK Target wallet address
last_timestamp TEXT ISO timestamp of newest processed activity

copied_trades

Column Type Description
id INTEGER PK Auto-increment ID
timestamp TEXT When the copy was executed
source_wallet TEXT Which target wallet this came from
market TEXT Market title
token_id TEXT Condition token ID
original_size REAL Original trade size in USD
copied_size REAL Copied trade size in USD
side TEXT Always "BUY" (sells are filtered out)
dry_run INTEGER 1 = dry run, 0 = live order placed
pnl REAL Profit/loss (reserved for future use)

exposure_log

Column Type Description
id INTEGER PK Auto-increment ID
timestamp TEXT When the snapshot was taken
total_exposure REAL Total USD exposure at that point

Raspberry Pi Setup

Prerequisites

# Install Node.js 22 LTS (if not already installed)
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
sudo apt install -y nodejs

# Verify
node --version  # v22.x
npm --version

Install and run

# Create a directory for the bot
mkdir ~/polymarket-bot && cd ~/polymarket-bot

# Create your .env file
nano .env  # paste your config

# Install the bot globally
npm install -g @calebpanza/polymarket-bot

# Run in the foreground to verify
polymarket-bot start

# Or run as a systemd service (see below)

Run as a systemd service (recommended)

Create /etc/systemd/system/polymarket-bot.service:

[Unit]
Description=Polymarket Copy-Trading Bot
After=network.target

[Service]
Type=simple
User=pi
WorkingDirectory=/home/pi/polymarket-bot
ExecStart=/usr/bin/polymarket-bot start
Restart=always
RestartSec=30
Environment=NODE_ENV=production

[Install]
WantedBy=multi-user.target

Then:

sudo systemctl daemon-reload
sudo systemctl enable polymarket-bot
sudo systemctl start polymarket-bot

# View logs
journalctl -u polymarket-bot -f

Pi 3 performance tips

  • SD card: Use a quality card (SanDisk Extreme or better). WAL mode minimizes write amplification.
  • RAM: The bot uses ~100–150 MB. Leave room for the OS (~150 MB). Avoid running a desktop environment.
  • Swap: Add a small swap file if needed: sudo fallocate -l 256M /swapfile && sudo chmod 600 /swapfile && sudo mkswap /swapfile && sudo swapon /swapfile
  • Overclocking: Not needed. The bot is I/O-bound (network polling), not CPU-bound.

Security

This bot is designed for $20 of play money. Treat it accordingly.

  • BURNER WALLET ONLY: Create a fresh wallet. Send $20–25 USDC and a small amount of POL for gas. Never use a wallet with significant funds.
  • Never commit .env: The .gitignore already excludes it.
  • Never commit the DB file: It may contain trade data you don't want public.
  • Web dashboard: Only binds to 0.0.0.0 when ENABLE_WEB=true. This is LAN-only by default — don't expose port 3001 to the internet without additional security (reverse proxy, auth, etc.).
  • Private key handling: The key is read from the environment at startup and passed to ethers.js for signing. It's never logged or written to disk by the bot.

Development

# Clone the repo
git clone https://github.com/calebpanza/polymarket-copybot.git
cd polymarket-copybot

# Install dependencies
npm install

# Run in dev mode
npm run dev -- start

# Run tests with coverage
npm test

# Build
npm run build

License

Private — not for redistribution.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages