polycopy — Whale copy-trading bot
Mirrors trades from profitable Polymarket wallets within seconds. Per-whale WR gate ≥55% after 10 trades, 24h stale exit, $0.10 best-bid collapse exit. Adaptive 3s polling after whale activity.
| Strategy type | Copy trading |
|---|---|
| Asset | Multi-market |
| Timeframe | Event-driven |
| Market type | All Polymarket markets |
| Minimum capital | $50 |
| Dependencies | @polymarket/clob-client, ethers, puppeteer, puppeteer-extra, puppeteer-extra-plugin-stealth |
What it does
polycopy watches a configurable list of profitable Polymarket wallets ("whales") and mirrors their trades within seconds. It does not blindly copy: each whale has an independent win-rate gate, position size is your own (not the whale's), and exits are managed by polycopy independently of what the whale does.
The watcher uses Puppeteer with stealth plugins because Polymarket's Data API rate-limits aggressive polling and the on-chain trade tape is slower than the UI feed. The Puppeteer client masquerades as a regular browser session.
The edge
Profitable Polymarket wallets are public. Their PnL is on-chain. The hard part is acting fast enough that the price hasn't moved before you can copy. polycopy's polling cadence (adaptive 3s after recent whale activity, 30s+ when quiet) and independent exit discipline let you ride the whale's signal without depending on the whale's exit timing.
The WR gate is the key safety: a whale who stops being profitable gets paused automatically. You only copy whales who have a verified track record on your own observed trades.
How it works
Edit polycopy/config.json to define your whale list:
{
"whales": [
{ "address": "0x7c3db7...", "label": "Car", "enabled": true, "betPct": 0.05 },
{ "address": "0xab94...", "label": "Mango", "enabled": true, "betPct": 0.03 }
],
"settings": {
"betPct": 0.05, "maxBetUsd": 5,
"pollIntervalMs": 30000, "pollStaggerMs": 2000
}
}Main loop:
- Init: cancel any stale orders from previous runs, load whale state from
polycopy/state.json - Poll each whale on stagger (default 30s, with 2s stagger between whales to avoid bursting)
- Detect new trade: compare whale's recent trades to last known set
- WR gate: skip if this whale has fewer than 10 observed trades (
WHALE_MIN_TRADES_FOR_GATE) or WR below 55% (WHALE_MIN_WIN_RATE) - Compute size:
betPctof your balance, capped atmaxBetUsd - Copy buy: FOK taker at the whale's entry price ± slippage
- Adaptive poll: after any whale activity, drop poll interval to 3s for 5 minutes (
FAST_POLL_MS,FAST_POLL_WINDOW_MS)
Independent exits:
- Stale position exit: 24 hours held (
STALE_POSITION_HOURS) - Bid collapse exit: best bid drops below $0.10 (
BID_COLLAPSE_THRESHOLD) - Daily loss limit: tracked since Paris midnight
Sample output
[24/05/2026, 12:00:01] 🐋 PolyCopy [🔴 LIVE $50.00] [24/05/2026, 12:00:01] Whales: Car, Mango [24/05/2026, 12:00:01] Bet: 5% of balance (max $5) [24/05/2026, 12:00:01] Poll: every 30s (fast: 3s after activity), stagger 2s [24/05/2026, 12:00:01] 🚀 Watching for new whale trades... [24/05/2026, 12:14:32] Whale Car: BUY Yes "Will SCOTUS rule by July?" @ $0.34 [24/05/2026, 12:14:34] Copying: BUY (FOK) 7sh @ $0.35 ($2.45 incl fee) [24/05/2026, 12:14:34] Filled: 0xc8b1e9... [24/05/2026, 12:14:34] 🐋 Fast-poll mode for 5min
Design targets
Per-whale tracking: each whale has an observed-trades counter and an observed-WR. Trades only fire when both gates pass. Realistic expectation: 70-90% of trades are filtered by the gate during normal operation, so copy frequency is roughly 10-30% of whale activity.
Capital efficiency: maxBetUsd default is $5 per trade. With $50 starting bank, that's 10 simultaneous positions max. Bank can grow without changing position size (the bet-cap dominates the bet-pct calculation).
FAQ
How do I find whales?
Use polycopy/scripts/search-whale.js and polycopy/scripts/analyze-whale.js. They query the Polymarket Data API for top wallets by PnL and let you inspect a wallet's trade history. Once you've picked a list, add them to config.json.
Why Puppeteer instead of just the API?
Polymarket's Data API rate-limits aggressive polling and the on-chain tape lags the UI feed by 30-60 seconds. Puppeteer with stealth plugins gets the same WebSocket the UI does, which is real-time.
Will my orders move the price?
Default bet of $5 is too small to move any market with $1k+ volume. The volume filter in your whale list already enforces this.
What's included
polycopy/polycopy.jspolycopy/lib/{watcher, copier, state, utils}.jspolycopy/scripts/{find-wallet, search-whale, check-whale, analyze-whale}.jspolycopy/package.json(Puppeteer + stealth deps)- README with whale discovery workflow and gate tuning notes
Configuration
| Flag | Default | Description |
|---|---|---|
| --live | — | Place real orders. Default is dry-run. |
| --sim-balance 30 | 30 | Starting balance in dry-run mode (USD). |
| --max-balance 50 | 0 | Cap the balance used for sizing (USD). 0 = use full balance. |