polymarket-trading-bot

agent
Security Audit
Warn
Health Pass
  • License — License: MIT
  • Description — Repository has a description
  • Active repo — Last push 0 days ago
  • Community trust — 15 GitHub stars
Code Warn
  • process.env — Environment variable access in apps/web/next.config.mjs
  • process.env — Environment variable access in apps/web/src/app/dashboard/new/page.tsx
  • network request — Outbound network request in apps/web/src/app/dashboard/new/page.tsx
  • crypto private key — Private key handling in apps/web/src/app/dashboard/new/page.tsx
  • process.env — Environment variable access in apps/web/src/app/dashboard/page.tsx
  • network request — Outbound network request in apps/web/src/app/dashboard/page.tsx
Permissions Pass
  • Permissions — No dangerous permissions requested

No AI report is available for this listing yet.

SUMMARY

Open-source Polymarket copy trading & autonomous trading bot. Mirror whale wallets, run 24/7 strategies (arbitrage, momentum, mean-reversion, endgame) via the Gamma + CLOB v2 APIs. TypeScript SDK, terminal CLI, Next.js dashboard, anti-Sybil guard, and a Cloudflare Workers-backed custodial key vault.

README.md

Polybot

The most advanced open-source platform for Polymarket copy-trading and autonomous trading.

Mirror the smartest wallets on Polymarket. Run battle-tested autonomous strategies. Plug it into any AI agent. All in TypeScript, all non-custodial.

License: MIT
Node 18+
TypeScript
Polymarket CLOB v2
SDK on npm
CLI on npm

60-second start · SDK · AI agents · CLI · Architecture · Strategies · Risk


Why Polybot?

There are dozens of toy Polymarket bots. None of them give you all of:

  • Real Polymarket APIs — Gamma, CLOB v2 (L1 EIP-712 + L2 HMAC), Data API, authenticated user WebSocket. No RPC scraping, no half-baked clones.
  • Sub-second copy trading with proportional sizing, per-market cooldowns, and slippage guards.
  • Production risk engine — position caps, daily loss limits, market black/whitelists, paper-trading mode, on-chain confirmation.
  • First-class AI agent integration — 11 ready-made tool definitions for Claude / GPT / Vercel AI SDK / MCP.
  • Three wallet modes — EOA, Polymarket Magic proxy, and Gnosis Safe — handled with one config flag.
  • Anti-Sybil by construction@polybot/guard requires every wallet to be EIP-712 attested before it touches the system, with plan-aware capacity caps and cooldowns. Zero database, zero env vars — state lives in ~/.polybot/state.jsonl, all operational knobs are embedded constants.
  • Zero-install pathnpx polybot init works on a fresh laptop. SQLite by default. Docker is optional.
  • An npm SDK + CLI + REST API + Next.js dashboard, all in the same monorepo.
  • Self-hostable. Your wallet, your keys, your data.

⚡ 60-second start

git clone https://github.com/your-org/polybot.git
cd polybot
pnpm setup           # installs deps + creates local SQLite + writes .env
# open .env, paste PRIVATE_KEY — that's the ONLY required value
pnpm dev             # API on :4000, dashboard on :3000

That's it. No Docker, no Postgres, no Redis required. SQLite handles dashboard state; the wallet guard journals to ~/.polybot/state.jsonl; an in-process scheduler handles jobs. Polymarket endpoints, plan limits and the EIP-712 domain are embedded constants — you don't configure them, you upgrade the package.

When you outgrow the local setup, set DATABASE_URL=postgres://… and REDIS_URL=redis://… (the only two infra knobs we expose) and the same code scales horizontally.

Paper-trading is on by default. Flip the bot's paperTrading flag to false only when you're ready to commit real USDC.

Or skip the repo entirely

If you just want to mirror a wallet from your terminal, you don't even need to clone anything:

npx polybot init                                          # writes .env
# paste PRIVATE_KEY into .env
npx polybot copy --target 0xWhale --size-multiplier 0.05  # paper mode

See the CLI section for the full command list.


📦 What's in the box

polybot/
├── packages/
│   ├── sdk/        # 📦 @polybot/sdk — npm package for embedding in any Node app
│   ├── cli/        # 📦 polybot — npm CLI (npx polybot …)
│   ├── guard/      # 📦 @polybot/guard — wallet attestation + capacity + bot policy
│   ├── signer/     # 📦 @polybot/signer — Vercel-flavoured custodial key vault (legacy)
│   ├── core/       # Gamma, CLOB v2, Data API, WebSocket clients
│   ├── engine/     # CopyEngine, AutoEngine, RiskManager, strategies
│   ├── api/        # Fastify REST + WebSocket server (auth, billing, dashboard backend)
│   ├── worker/     # In-process or Redis-backed bot runner
│   └── db/         # Prisma schema (SQLite default, Postgres-ready)
├── apps/
│   └── web/        # Next.js 15 + Tailwind dashboard
├── infra/advanced/ # Docker Compose + Dockerfiles (opt-in)
├── examples/       # Standalone scripts
└── docs/           # Architecture, strategies, copy-trading playbook, security

Two of these packages are designed to be published to npm and consumed standalone:

Package Use when…
@polybot/sdk You want to embed Polybot in your own backend, AI agent, or CI job
polybot (CLI) You want to trade or copy-trade from the terminal with no setup
@polybot/guard You're running Polybot as a multi-tenant service and need anti-Sybil + capacity enforcement
@polybot/signer You're running Polybot custodially on Vercel (legacy — Cloudflare Worker is the recommended path)

The rest of the repo is the full hosted product (dashboard + REST API + billing + worker).


🔧 SDK

Install

npm i @polybot/sdk

5-line example

import { Polybot } from "@polybot/sdk";

const bot = await Polybot.create({
  privateKey: process.env.PRIVATE_KEY!,
  paperTrading: true,
});

const result = await bot.trade({
  market: "will-trump-be-president-on-january-20-2026",
  side: "BUY",
  outcome: "YES",
  usdcSize: 25,
});

Wallet modes (one config, three variants)

// 1. EOA — your own wallet, you funded it directly
await Polybot.create({ privateKey, wallet: { type: "eoa" } });

// 2. Polymarket Magic / email proxy
await Polybot.create({
  privateKey,                                   // signing key from Magic
  wallet: { type: "proxy", funder: "0xYourPolymarketProxy" },
});

// 3. Gnosis Safe
await Polybot.create({
  privateKey,
  wallet: { type: "safe", funder: "0xYourSafe" },
});

The SDK derives the right Polymarket signature type (0 / 1 / 2) automatically.

Copy trading

bot.copy.addTarget({
  wallet: "0xYourFavouriteWhale",
  sizeMultiplier: 0.05,
  maxTradeUsd: 50,
});
await bot.copy.start();

Autonomous strategies

await bot.auto.start({
  strategies: ["arbitrage", "endgame"],
  perTradeUsd: 25,
  scanIntervalMs: 15_000,
});

Live event stream

const stop = await bot.stream({
  onTrade: (e) => console.log("fill:", e),
  onOrder: (e) => console.log("order:", e),
});

Full SDK reference: packages/sdk/README.md.


🤖 AI agent integration

The SDK ships with 11 LLM tool definitions that work with any tool-calling framework. Every tool call still goes through the risk engine, so a hallucinating model can't blow up your bankroll past your configured caps.

Vercel AI SDK + Anthropic

import { Polybot } from "@polybot/sdk";
import { polymarketAgentTools } from "@polybot/sdk/agent-tools";
import { generateText } from "ai";
import { anthropic } from "@ai-sdk/anthropic";

const bot = await Polybot.create({
  privateKey: process.env.PRIVATE_KEY!,
  wallet: { type: "proxy", funder: process.env.POLY_FUNDER! },
  paperTrading: false,
});

const out = await generateText({
  model: anthropic("claude-opus-4-6"),
  prompt: "Find a market about the 2026 election, " +
          "buy $20 of YES if YES is between 0.45 and 0.55 and liquidity > $5,000",
  tools: polymarketAgentTools(bot),
  maxSteps: 6,
});

Available tools

polymarket_search_markets        polymarket_quote
polymarket_trending_markets      polymarket_place_trade
polymarket_get_market            polymarket_balances
polymarket_positions             polymarket_open_orders
polymarket_add_copy_target       polymarket_start_copy
polymarket_stop_copy

Helpers also exported for Anthropic Messages API (polymarketAnthropicTools()) and OpenAI Responses API (polymarketOpenAITools()).


🖥 CLI

npx polybot --help

# Discovery
npx polybot scan --limit 10
npx polybot quote --market will-eth-hit-10k

# Manual trading
npx polybot trade --market will-eth-hit-10k --side BUY --outcome YES --usdc 25 --live

# Copy whales
npx polybot copy --target 0xWhale --size-multiplier 0.05

# Autonomous
npx polybot auto --strategies arbitrage,endgame --per-trade 25

# Account
npx polybot balances
npx polybot positions
npx polybot watch       # live trade/order stream

Without --live, every command runs in paper mode. Reads PRIVATE_KEY (and optionally POLY_FUNDER_ADDRESS + POLY_SIGNATURE_TYPE) from .env.

Full CLI reference: packages/cli/README.md.


🏛 Architecture

                     ┌──────────────────────────────┐
                     │           Next.js            │  apps/web
                     │       Dashboard + Auth       │
                     └──────────────┬───────────────┘
                                    │ REST + JWT + WS
                                    ▼
   ┌──────────────┐    ┌─────────────────────────────┐    ┌────────────┐
   │ Stripe webhk │◄──►│         Fastify API         │◄──►│  SQLite or │
   └──────────────┘    │   /v1/auth · /bots · /…     │    │  Postgres  │
                       └────────────┬────────────────┘    └────────────┘
                                    │ in-process queue (default)
                                    │ or BullMQ/Redis (when scaled)
                                    ▼
                       ┌─────────────────────────────┐
                       │       Worker / SDK          │
                       │  ┌───────────────────────┐  │
                       │  │  Copy Engine          │──┼──► Polymarket Data API
                       │  │   └─ WalletWatcher    │  │
                       │  ├───────────────────────┤  │
                       │  │  Auto Engine          │──┼──► Polymarket Gamma API
                       │  │   └─ Strategies       │  │
                       │  ├───────────────────────┤  │
                       │  │  Risk Manager         │──┼──► Polymarket CLOB v2
                       │  └───────────────────────┘  │     EIP-712 + HMAC
                       └────────────┬────────────────┘
                                    │
                                    ▼
                       ┌─────────────────────────────┐
                       │   Polymarket User WS        │
                       │   wss://ws-…/user           │  authenticated fills
                       └─────────────────────────────┘

Single-process by default

Out of the box, one Node process runs the API, the in-process job queue, the worker, and the engines. SQLite stores everything. Perfect for solo users, AI agents, and single-VPS deployments.

Scale-out path

When you grow:

  1. Set DATABASE_URL=postgres://… — Prisma is dual-provider, no schema rewrite.
  2. Set REDIS_URL=redis://… — the queue swaps to BullMQ automatically.
  3. Run multiple @polybot/worker processes side-by-side; they share work via Redis.
  4. Optionally use the Docker stack at infra/advanced/ for everything-in-containers.

The SDK and CLI never need any of this — they run fully in-memory.


🤖 Built-in strategies

Strategy What it does Default safety
arbitrage Buys both sides when YES + NO < 1 min 75 bps edge
mean_reversion Z-score reversion against 60-tick mean only price band 0.05–0.95
momentum Rides slope above threshold over 30 ticks suppressed at price ≥ 0.9
endgame Buys near-certain winners < 24h to close hard size cap, ≥ 0.94 threshold

Authoring a new one takes ~20 lines — see docs/STRATEGIES.md.


🛡 Risk engine

Every order — manual, copy, or autonomous — passes through RiskManager.evaluate():

{
  "maxPositionUsd": 100,
  "maxDailyLossUsd": 250,
  "minLiquidityUsd": 500,
  "maxSlippageBps": 150,
  "minPrice": 0.05,
  "maxPrice": 0.95,
  "blacklist": ["my-banned-slug"],
  "whitelist": [],
  "paperTrading": true
}

Rejections are logged with structured reasons (pino redacts secrets automatically). The risk engine is non-bypassable by AI agents — tool calls cannot disable it.


📡 REST + WebSocket API

All routes under /v1. JWT auth, Zod validation, helmet + CORS + rate limit.

POST   /v1/auth/register           POST   /v1/wallets/challenge
POST   /v1/auth/login              POST   /v1/wallets/attest
GET    /v1/auth/me                 GET    /v1/wallets
                                    DELETE /v1/wallets/:address
GET    /v1/bots
POST   /v1/bots                    POST   /v1/bots/:id/start
GET    /v1/bots/:id                POST   /v1/bots/:id/stop
PATCH  /v1/bots/:id
DELETE /v1/bots/:id                GET    /v1/markets/trending
                                    GET    /v1/markets/search?q=…
GET    /v1/bots/:id/targets        GET    /v1/markets/:slug
POST   /v1/bots/:id/targets
DELETE /v1/bots/:id/targets/:tid   GET    /v1/trades?botId=
                                    GET    /v1/trades/positions
POST   /v1/stripe/checkout         GET    /v1/trades/metrics
POST   /v1/stripe/webhook
                                    WS     /v1/ws/stream?token=…

💳 Subscriptions

The dashboard ships with three tiers (FREE, PRO, ELITE). Wire Stripe Checkout via:

STRIPE_SECRET_KEY=sk_live_…
STRIPE_WEBHOOK_SECRET=whsec_…
STRIPE_PRICE_PRO=price_…
STRIPE_PRICE_ELITE=price_…

Checkout sessions and webhook handlers are already implemented in packages/api/src/routes/stripe.ts.

The whole engine is open source and free to self-host. Subscriptions only pay for hosted infrastructure and convenience.


🛡 Anti-Sybil (@polybot/guard)

A determined user can paste a mnemonic into Cursor or Claude and have an agent derive thousands of child wallets — invisible to the chain until they trade. Polybot does not try to count derived keys (impossible). It counts the addresses that touch our infrastructure and forces every one of them to be explicitly authorised.

Three primitives compose into one chokepoint:

  1. EIP-712 wallet attestation — every wallet must sign a server-issued, single-use nonce before it can be used.
  2. Plan-aware capacitymaxActiveWallets, maxConcurrentBots, attach + detach cooldowns. Embedded as constants — bump them and ship a new release.
  3. Frozen BotPolicy — every running bot operates under a snapshot taken at start time. Plan downgrades cannot widen capacity mid-run.

@polybot/guard is fully self-contained: no database (state journaled to ~/.polybot/state.jsonl), no env vars (Polymarket endpoints + plan limits + EIP-712 domain are embedded constants).

client                                   server (guard)
  │   POST /v1/wallets/challenge ─────────►│
  │ ◄── { nonce, expiresAt, … }            │   issueChallenge()
  │   user.signTypedData(challenge)        │
  │   POST /v1/wallets/attest ────────────►│   attach()
  │       │                                │     ├ verify EIP-712 signature
  │       │                                │     ├ enforce nonce single-use
  │       │                                │     ├ enforce plan capacity
  │       │                                │     ├ enforce attach/detach cooldowns
  │       │                                │     └ persist Wallet + WalletAttestation
  │ ◄── { ok, walletId, expiresAt }        │

Off-chain mnemonic derivation cannot bypass this. The user can derive 10,000 keys, but none of them can clear an order through Polybot until they sign the EIP-712 attestation — and once they do, plan caps decide whether the slot is available.

Full rationale and ops guide: packages/guard/README.md.


🔑 Custodial key vault (Cloudflare Worker)

When Polybot runs as a hosted service, users paste their EVM private key once via polybot login and we sign Polymarket orders on their behalf. The hosted vault is a Cloudflare Worker backed by Workers KV:

  • AES-256-GCM with a per-user HKDF-derived data key — leaking one user's ciphertext does not help with anyone else's.
  • Ciphertext in Cloudflare Workers KV — globally replicated, eventually consistent (~60s), Cloudflare-encrypted at rest as a second layer on top of our own AES-GCM.
  • Master key in Cloudflare encrypted secrets (KEY_ENC_MASTER) — set once via wrangler secret put, never logged, never returned by any API, never rotated by the Worker itself.
  • Plaintext lives in memory only at sign time — wiped immediately after, never written to disk, never written to logs.
  • Key version field in every blob makes rotation a one-pass re-encryption job (see packages/vault-worker/src/rotate.ts).
  • Offline disaster recoverypackages/vault-worker/scripts/decrypt.py decodes any blob given the master key, with zero Cloudflare dependency.

From the CLI (the recommended path — uses the hosted vault Worker):

polybot login                        # interactive: paste key once, pushed to vault
polybot wallets list                 # only address + fingerprint stored locally
polybot wallets forget 0xAbCd…1234   # delete remotely + locally

Programmatic access — REST API contract:

Method Path Purpose
POST /v1/wallets/keys Import + encrypt a private key
GET /v1/wallets/keys List addresses in the vault
DELETE /v1/wallets/keys/:address Forget the key for an address

Default endpoint: https://polymarketbot.polymarketdev.workers.dev. Override with POLYBOT_API_URL.

Honest trade-off: this is a custodial design. The Vercel project owner can decrypt every wallet (master key + KV both in their control). For true non-custodial signing — keys that never reach our infrastructure even encrypted — swap @polybot/signer for a Turnkey, Privy, or AWS KMS adapter. The interface is small enough to make that a one-day migration.

The vault Worker source and rotation playbook live in packages/vault-worker/ (private — not in this public repo). The public @polybot/signer package is the legacy Vercel KV implementation, still functional for self-hosters.

🔐 Security model

  • Custodial when hosted, non-custodial when self-hosted. The @polybot/signer vault is custodial-by-design; the SDK and CLI are fully non-custodial.
  • Encrypted private keys (AES-256-GCM) at rest in Cloudflare Workers KV (hosted), or in the dashboard DB for legacy self-hosted installs.
  • Pino log redaction strips privateKey, secret, passphrase automatically.
  • Risk gates are non-bypassable, even by AI agents.
  • Read-only by default. Market discovery (Gamma + Data API) is unauthenticated; trading requires explicit user signature.
  • Paper mode is default for every new bot, every CLI run, every SDK instance.
  • Rate limiting + Helmet + CORS out of the box on the API.

See SECURITY.md for the hardening checklist.


🗺 Roadmap

  • On-chain Polygon log subscription for sub-300 ms wallet watching
  • ML-ranked copy targets (auto-discover from leaderboard + Sharpe filter)
  • Negative-risk arbitrage on multi-outcome event markets
  • Backtester with historical Gamma snapshots
  • Telegram bot frontend
  • Standalone MCP server bundle for Cursor / Claude Desktop

🤝 Contributing

pnpm install
pnpm typecheck
pnpm build
pnpm --filter @polybot/api dev   # hot-reload api
pnpm --filter @polybot/web dev   # hot-reload dashboard

To add a new strategy, drop a file under packages/engine/src/strategies/, export from index.ts, register in AutoEngine.buildStrategies(). See CONTRIBUTING.md.


⚖ Legal & disclaimer

Polybot is not financial advice. Predictions markets are inherently risky. You are responsible for understanding the legal status of Polymarket in your jurisdiction. The maintainers are not affiliated with Polymarket Inc.

Released under the MIT License.


Built by traders, for traders.
Star ⭐ the repo if Polybot helps you ship.

Reviews (0)

No results found