What if you could just do what the best traders do, a second later?
That’s the whole pitch of copy trading. You find someone who’s consistently right on Polymarket, watch their wallet, and mirror every trade at your own size.
It sounds like a weekend project. It isn’t.
My bot started from an open-source copy-trading bot by vladmeer. Most of this post is about what came after: making it fast, making it honest about its own positions, and keeping it alive on top of Polymarket’s APIs.
I won’t tell you who it copies or how it picks them. That part stays private. The rest is fair game.
Right, not fast
The first question isn’t technical. It’s who to copy.
Every copy trader is late by definition. My bot reacts about two seconds after a trade lands on-chain, and that lag decides which traders are worth copying at all.
If someone scalps in and out of a market within seconds, you’ll always be buying after the move. If someone runs a market-making algorithm, you’ll be chasing fills you never get. You want the opposite: people who trade a handful of times a day and hold for hours.
I ended up writing the principle at the top of the scoring code:
We want traders whose edge is being RIGHT, not being FAST.
Candidates don’t go live straight away either. They’re paper-traded first, in a “shadow” mode that simulates fills against the real order book, and they only get real money once they pass a promotion check.
One shadow run taught me something no backtest had. A candidate looked great on paper but kept re-trading the same few markets dozens of times each, and the bot filled almost none of those copies. Per-market churn is now a filter of its own.
From 4.5 seconds to 190 milliseconds
The original bot polled Polymarket’s activity API for each tracked wallet, one after the other, then made several round trips before placing an order. A copy went out about 4.5 seconds after detection.
So I rewrote the path from detection to order.
Instead of polling the API, the bot now watches the chain. One persistent WebSocket to a Polygon node subscribes to token transfer events for the tracked wallets. A transfer to a wallet is a buy, and a transfer from it is a sell.
To get the price, it reads the transaction receipt over the same socket, which takes about 50ms and gives the exact USDC amount. That works even for brand-new markets the bot has never seen.
The API poller didn’t go away. It runs as a fallback and adapts its pace: every 500ms right after a hit, every 30s while the WebSocket is healthy. Both paths share one dedupe set, so a trade never gets copied twice.
A background job also keeps Polymarket’s balance and allowance cache warm every 5 seconds, so a buy never has to wait for it.
The RPC provider mattered too. In my tests Alchemy answered in 51ms, Infura in 107ms.
Execution went from about 4.5s to about 190ms. Today’s budget is roughly 100ms from detection to order, or about 2.15 seconds once you count Polygon’s block time.
All of it runs on the cheapest AWS Lightsail instance ($5 a month, 1 vCPU, 1GB of RAM) in Dublin, close to Polymarket’s edge servers.
One order, no retry loop
Every copy is a single fill-and-kill order. It fills whatever it can right away and cancels the rest. The hot path has no “fetch the book, place an order, retry” loop.
Buys and sells are deliberately treated differently.
Buys get a price ceiling: the trader’s price plus a small slippage that scales with the price, so a 3-cent token can’t soak up a huge absolute premium. Overpaying on entry kills the edge.
Sells go out with a floor of one cent. That sounds reckless, but a fill-and-kill order fills against the best bids first anyway. The floor only matters when the book has collapsed, and then I’d rather take a bad fill than sit on a failing position.
The $224 lesson
In shadow mode, the bot once copied a trader who had bought at 50 cents into a market whose best ask was 4 cents.
It used the trader’s price as its ceiling and walked right up the book. It spent $224 at an average of 12.3 cents a share, on a market that resolved worthless.
The fix is a depth guard. Before buying, the bot fetches the live book and caps its ceiling just above the best ask, so a trader’s stale print can’t drag it far above the market anymore. If the book fetch fails, the order still goes out, just without the guard.
Resting orders that never fill
For a while, any unfilled part of a buy was parked as a resting limit order at the trader’s price.
It sounded smart. The data disagreed: 0 out of 86 of those orders ever filled. Worse, they counted against the per-market position cap while they sat there, so after a few of them every new buy on that market got skipped with “position limit reached”.
I added a cap clamp and a 15-minute expiry sweep, then switched the feature off by default. The code is still there in case the data changes.
Knowing what you own
The bot keeps its own record of every token it bought, because it should only ever sell what it bought, not whatever else is sitting in the wallet.
That record drifts. Positions get redeemed, markets resolve, I sell something by hand. Every 20 minutes a reconciler compares it with the on-chain balances and corrects it, but only ever down. Tokens on-chain that the bot didn’t buy are none of its business.
Two smaller bugs from the same family.
The redeemer was blind to small wins. Polymarket’s positions API hides positions under one token by default, and the hourly redeemer never passed the flag to include them. 68 small winning positions, about $20 in total, piled up unclaimed for months.
The shadow ledger leaked money. Paper trades only moved cash on fills, and resolved markets were never settled, so winnings never came back to the paper bankroll. The first settlement pass returned about $2,050 of paper money that had been stuck there.
Living with flaky APIs
Polymarket’s data API fails intermittently on a small share of requests. In September 2026 it was about 1 to 3%, for hours at a time.
Every poll goes through one fetch helper with a per-host circuit breaker. After five failures in a row, requests to that host short-circuit for 30 seconds, doubling up to 5 minutes, and then a single probe decides whether to close the breaker again. That way a real outage doesn’t turn into a request storm across every tracked wallet.
Telegram gets an alert when a host degrades, plus a message for every fill, kill and failure. Notifications are fire-and-forget and never awaited in the hot path.
Watching it
Once an hour, separately from trading, the bot exports its balance, positions and trades to a database, and a private dashboard on this site reads from it.
So, does it make money? On average, about 1% a week. The catch is big world events. When something major breaks, markets reprice in minutes, and that’s where the bot takes its sharpest losses.
The cheapest lesson I ever paid for
Speaking of losing money.
I once ran a script without reading it properly. It had malware in it, and it liquidated my wallet. Thank god there was only about $100 on it.
If you take one thing from this post, take that one. Read every line of anything that gets near a private key before you run it, and never leave more in a bot’s wallet than you can afford to lose.
What I’d tell you
- •Latency decides your strategy, not the other way around. Know your lag before you pick who to copy.
- •Paper trade against the real book. Backtests didn’t catch the churn problem or the overpaying problem.
- •Make buys strict and sells forgiving.
- •Your own position records will drift. Reconcile them against the chain, and decide which direction you trust.
- •Read the code before you hand it your keys.