When a Polymarket trader I follow makes a trade, I want an AI agent to see it, look at the market, and decide whether to do anything about it.
Agents like Claude Code or Codex can read a fill and reason about a market, but they don't work well as long-running listeners. They exit when their task is done. In this setup, a small process holds the live connection and queues fills. It starts the agent once per batch with the fills on stdin; the agent handles the batch and exits.
Everything here uses two command-line tools that print JSON, and both also run as MCP servers:
-
pmwallets: the data side. Leaderboard, trader stats, subscriptions, live fills. -
pmwallets-copytrade: the trading side. Market and order book lookups, balance, positions, and orders on Polymarket.
Install
npm i -g pmwallets pmwallets-copytrade # Node.js 20+
# or
pip install pmwallets pmwallets-copytrade # same commands
You need a PMWallets API key (created on pmwallets.com/keys):
export PMW_API_KEY=pmw_...
Pick traders to follow
pmwallets leaderboard --period 30d --minWinLo 0.55 --category politics --limit 20
pmwallets entity 7KQ2MF9X4B1C # one trader's stats, by handle
minWinLo is the lower bound of the 95% confidence interval on a trader's win rate. A trader who won 3 bets out of 3 has a 100% win rate and a lower bound well under 0.5, because three trades say very little. Filtering on the lower bound pushes lucky streaks down the list.
Then follow one:
pmwallets subscribe 7KQ2MF9X4B1C # billed per hour while subscribed
pmwallets subscriptions
Getting fills to the agent
There are two ways, depending on whether you can keep a process running.
Pull: new-fills
If your agent runs on a schedule (a cron job, a loop inside the agent, a chat agent you poke now and then), call:
pmwallets new-fills
It returns the fills since the previous call, each one once. The position is kept in ~/.pmwallets/mcp-cursor.json, or wherever PMW_MCP_STATE points. One reader per file: if two agents poll, give each its own PMW_MCP_STATE, or they will split the fills between them.
Push: watch --exec
If you can keep a process up, watch holds a live connection and runs your command for each batch of fills:
pmwallets watch --batch-sec 30 --exec 'claude -p "Fills from traders I follow are on stdin. For each BUY above $1000 in a market ending after 2026-12-31, read the market with pmwallets-copytrade market, then buy $5 with --key <eventId> if the price is below 0.6. One line per fill: what you did." --allowedTools "Bash(pmwallets-copytrade:*)"'
The fills arrive on the command's stdin as JSON lines, and the same lines are in a file named by $PMW_BATCH_FILE. Fills that come in while the agent is still running go into the next batch. --batch-sec 30 waits 30 seconds after the first fill so that a burst becomes one agent run instead of ten.
--allowedTools "Bash(pmwallets-copytrade:*)" lets headless Claude run the trading CLI. Without it, Claude either can't run anything or you end up granting far more than it needs.
For other agents, the command looks similar:
# Codex: its default sandbox has no network, so the trading CLI can't reach Polymarket
--exec 'codex exec --sandbox danger-full-access "...same instructions..."'
# Gemini CLI
--exec 'gemini -p "..." --yolo'
Without --exec, watch just prints one JSON line per fill, which is handy for piping into your own script.
A fill looks like this (trimmed):
{
"eventId": "137:78012345:0x…:0x…:212",
"side": "BUY",
"role": "taker",
"price": "0.570000",
"tokenId": "1043…",
"usdcAmount": "1824.000000",
"sharesAmount": "3200.000000",
"market": { "question": "…", "outcome": "Yes", "endDate": "2026-11-03T00:00:00Z" },
"source": "ws",
"receivedAt": "2026-10-14T09:12:03.417Z"
}
The raw usdc and shares fields are integers in millionths. The *Amount fields are the same values as decimals, so the agent doesn't have to divide by a million (models do get this wrong). The market question and outcome are attached, so the agent can tell what was bought without looking it up.
A batch is handed to the command at most once. If the agent crashes, times out, or the machine reboots mid-run, that batch goes to pmw-watch/failed/ and is never run again, because the agent may already have placed an order. Those batches need to be checked by hand. A restart picks up the stream where it stopped.
Placing orders
First write a config. It starts in dry-run:
pmwallets-copytrade init # writes config.yaml, mode: dry-run
pmwallets-copytrade check # checks keys and account, places nothing
In dry-run, every order is simulated against the live order book and nothing is sent. That is the mode to leave the agent in for a while.
The commands an agent needs:
pmwallets-copytrade market <tokenId> # question, outcomes, prices, order book
pmwallets-copytrade balance
pmwallets-copytrade positions
pmwallets-copytrade order buy <tokenId> --usdc 5 --max-price 0.45 --key <eventId>
pmwallets-copytrade order sell <tokenId> --all --min-price 0.40 --key <eventId>:exit
The order commands follow these rules:
- A BUY is fill-or-kill: all of it at
--max-priceor better, or nothing. -
--usdcsets the maximum spend. The share count isusdc / max-price, so the order can't cost more than--usdcwhatever it matches. It may spend less than that amount. Without--max-pricethe limit is the current best ask. - A SELL is fill-and-kill and is capped at what the account holds.
-
--keyis an idempotency key. Pass the fill'seventId. The same key never sends a second order, so an agent that retries after a timeout doesn't double up. -
status: unknown(orverify: true) means the order may have filled. The agent should checktradesbefore sending another one. Exit codes: 0 filled or dry-run, 2 not traded, 3 unknown.
I'd explicitly require --key in the prompt, since agents may retry after a slow response. Without a key, that retry sends a second order.
When you switch the config to mode: live, give it a Polymarket account of its own with only what you're willing to lose in it. Polymarket doesn't accept orders from some countries (including the US and the UK); pmwallets-copytrade check tells you whether your machine's location can trade.
MCP instead of a shell
For Claude Desktop, Cursor, Windsurf, Cline and similar, the same tools are available as MCP servers:
{
"mcpServers": {
"pmwallets": {
"command": "npx",
"args": ["-y", "pmwallets", "mcp"],
"env": { "PMW_API_KEY": "pmw_..." }
},
"copytrade": {
"command": "npx",
"args": ["-y", "pmwallets-copytrade", "mcp", "--config", "/abs/path/config.yaml"]
}
}
}
The new_fills tool shares its position with pmwallets new-fills, so you can mix the two, but the one-reader-per-file rule still applies.
The trading MCP server rejects arguments it doesn't know. If a model sends max_price instead of maxPrice, the call fails with an error that lists the allowed names, rather than quietly dropping the limit and buying at whatever the ask is.
No shell, no MCP
For Dify, Coze, n8n or a custom GPT, import the OpenAPI spec at https://pmwallets.com/openapi.json and call the REST API with an x-api-key header. Fills can also arrive as signed webhooks. Placing orders from there is up to you; the trading CLI needs a machine to run on.
How fast is it
Two measurements from testing:
- A headless
claude -ptook about 11 seconds to read one fill, look up the market and place a dry-run order.codex exectook about 27 seconds for the same thing. - In a production test, 57 real fills reached the agent command between 0.01 and 0.16 seconds after PMWallets pushed them, each with its market question and outcome attached.
Most of the delay comes from the agent. If you care about getting the same price as the trader you follow, waiting 10 to 30 seconds for a model matters: in fast markets the price will have moved. For that case I'd use a fixed-rule bot (pmwallets-copytrade run). The agent setup is more useful when a task needs reading, such as skipping sports or only acting if the question mentions a specific event. It can also summarise what the people you follow did today.
Things to check before going live
- Run in dry-run for a while and read what the agent did.
- Put the key rule in the prompt: every order gets
--key <eventId>. - Keep
--usdcsmall and set--max-priceyourself rather than letting the model pick one. - Look in
pmw-watch/failed/after any crash. - Check whether you're allowed to trade on Polymarket from where you are.
None of this is financial advice, and copying a trader is not the same as being that trader: you buy later, at a different price, and pay fees.
The guide to hand your agent is printed by npx pmwallets skill, and the same material is at pmwallets.com/sdk. Package versions at the time of writing: pmwallets 0.6.5 and pmwallets-copytrade 0.4.1.
I help maintain PMWallets.
Top comments (0)