polymarket-copy-trading-bot
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChinesePolymarket Copy Trading Bot
Polymarket跟单交易机器人
Skill by ara.so — Daily 2026 Skills collection.
A TypeScript bot that continuously monitors a target Polymarket wallet, detects trades in real time via REST polling and/or WebSocket, and mirrors BUY orders to your own account using the Polymarket CLOB SDK on Polygon mainnet.
Skill由ara.so开发 — 2026年度技能合集系列。
这是一个基于TypeScript开发的机器人,可持续监控指定的Polymarket目标钱包,通过REST轮询和/或WebSocket实时检测交易,并且通过Polygon主网上的Polymarket CLOB SDK将目标的买入订单同步复制到你的个人账户。
What It Does
功能特性
- Monitors a target wallet via Polymarket Data API (REST polling every ~2s) and optionally WebSocket
- Mirrors BUY trades only — SELL trades are detected but skipped by default
- Sizes copies using a configurable (default 10%) with min/max caps
POSITION_MULTIPLIER - Submits orders as FOK, FAK, or LIMIT via the Polymarket CLOB client
- Enforces risk limits — per-session and per-market notional caps
- Supports three auth modes — EOA (), Poly Proxy (
SIG_TYPE=0), Poly Polymorphic (SIG_TYPE=1)SIG_TYPE=2
- 通过Polymarket数据API(每2秒左右轮询一次REST接口)监控目标钱包,也可选择使用WebSocket
- 仅复制买入交易 — 默认会检测到卖出交易但会自动跳过
- 可通过配置(默认10%)设置跟单仓位比例,同时支持设置最小/最大跟单金额限制
POSITION_MULTIPLIER - 可通过Polymarket CLOB客户端提交FOK、FAK或LIMIT类型的订单
- 风险限制机制 — 支持单会话和单市场的名义金额上限控制
- 支持三种身份验证模式 — EOA()、Poly代理(
SIG_TYPE=0)、Poly多签(SIG_TYPE=1)SIG_TYPE=2
Installation
安装
bash
git clone https://github.com/Neron888/Polymarket-copy-trading-bot.git
cd Polymarket-copy-trading-bot
npm installRequires Node.js v18+. The CLOB SDK requires ethers v5 (already pinned in ).
package.jsonbash
git clone https://github.com/Neron888/Polymarket-copy-trading-bot.git
cd Polymarket-copy-trading-bot
npm install需要Node.js v18+版本。CLOB SDK依赖ethers v5(已在中锁定版本)。
package.jsonConfiguration
配置
bash
cp .env.example .envEdit :
.envenv
undefinedbash
cp .env.example .env编辑文件:
.envenv
undefinedRequired
必填项
TARGET_WALLET=0xTargetWalletAddressToMonitor
WALLET_PRIVATE_KEY=0xYourPrivateKey
RPC_URL=https://your-quicknode-polygon-endpoint.quiknode.pro/your-key/
TARGET_WALLET=0x待监控的目标钱包地址
WALLET_PRIVATE_KEY=0x你的钱包私钥
RPC_URL=https://your-quicknode-polygon-endpoint.quiknode.pro/your-key/
Auth mode (0=EOA default, 1=Poly Proxy, 2=Poly Polymorphic)
验证模式(0=默认EOA,1=Poly代理,2=Poly多签)
SIG_TYPE=0
SIG_TYPE=0
Required only for SIG_TYPE=1 or 2
仅当SIG_TYPE=1或2时必填
PROXY_WALLET_ADDRESS=
PROXY_WALLET_ADDRESS=
Sizing
仓位配置
POSITION_MULTIPLIER=0.1 # 10% of target's trade size
MAX_TRADE_SIZE=100 # Max USDC per copied trade
MIN_TRADE_SIZE=1 # Min USDC per copied trade
POSITION_MULTIPLIER=0.1 # 跟单金额为目标交易金额的10%
MAX_TRADE_SIZE=100 # 单笔跟单最大USDC金额
MIN_TRADE_SIZE=1 # 单笔跟单最小USDC金额
Order behavior
订单行为配置
ORDER_TYPE=FOK # FOK | FAK | LIMIT
SLIPPAGE_TOLERANCE=0.02 # 2%
ORDER_TYPE=FOK # FOK | FAK | LIMIT
SLIPPAGE_TOLERANCE=0.02 # 滑点容忍度2%
Risk caps (0 = disabled)
风险上限(0=关闭限制)
MAX_SESSION_NOTIONAL=500 # Total USDC for entire session
MAX_PER_MARKET_NOTIONAL=100 # Per market USDC cap
MAX_SESSION_NOTIONAL=500 # 单会话总USDC上限
MAX_PER_MARKET_NOTIONAL=100 # 单市场USDC上限
Monitoring
监控配置
USE_WEBSOCKET=true
POLL_INTERVAL=2000 # ms between REST polls
USE_USER_CHANNEL=false # true = user WS channel, false = market channel
USE_WEBSOCKET=true
POLL_INTERVAL=2000 # REST轮询间隔,单位毫秒
USE_USER_CHANNEL=false # true=用户WS通道,false=市场通道
Optional
可选配置
POLYMARKET_GEO_TOKEN=
WS_ASSET_IDS= # comma-separated asset IDs for market WS
WS_MARKET_IDS= # comma-separated condition IDs for user channel
MIN_PRIORITY_FEE_GWEI=30
MIN_MAX_FEE_GWEI=60
---POLYMARKET_GEO_TOKEN=
WS_ASSET_IDS= # 市场WS通道的资产ID,英文逗号分隔
WS_MARKET_IDS= # 用户通道的条件ID,英文逗号分隔
MIN_PRIORITY_FEE_GWEI=30
MIN_MAX_FEE_GWEI=60
---Key Commands
核心命令
bash
undefinedbash
undefinedStart the bot (development mode with ts-node)
启动机器人(ts-node开发模式)
npm start
npm start
Generate and persist API credentials to .polymarket-api-creds
生成API凭证并持久化到.polymarket-api-creds文件
npm run generate-api-creds
npm run generate-api-creds
Validate existing API credentials
验证现有API凭证
npm run test-api-creds
npm run test-api-creds
Compile TypeScript to dist/
编译TypeScript代码到dist/目录
npm run build
npm run build
Run compiled production build
运行编译后的生产版本
npm run start:prod
---npm run start:prod
---Architecture Overview
架构概览
index.ts
└── TradeMonitor — REST polls Polymarket Data API for new target trades
└── WebSocketMonitor — Optional low-latency WS subscription (market or user channel)
└── TradeExecutor — Sizes trade, checks balance/allowance, submits CLOB order
└── PositionTracker — In-memory positions updated on fills
└── RiskManager — Session + per-market notional enforcementExecution flow:
detect trade → BUY? → subscribe WS if needed → compute copy size
→ risk check → execute order (FOK/FAK/LIMIT) → record fill → update statsindex.ts
└── TradeMonitor — 调用Polymarket数据API REST轮询获取目标的新交易
└── WebSocketMonitor — 可选低延迟WS订阅(市场或用户通道)
└── TradeExecutor — 计算跟单金额,检查余额/授权,提交CLOB订单
└── PositionTracker — 内存中存储成交后的持仓更新
└── RiskManager — 执行会话+单市场名义金额限制执行流程:
检测交易 → 是买入交易? → 按需订阅WS → 计算跟单金额
→ 风险校验 → 执行订单(FOK/FAK/LIMIT) → 记录成交 → 更新统计数据Code Examples
代码示例
Starting the bot programmatically
以编程方式启动机器人
typescript
import { startBot } from './src/index';
// The bot reads all config from process.env / .env
startBot();typescript
import { startBot } from './src/index';
// 机器人会从process.env / .env读取所有配置
startBot();TradeMonitor — polling pattern
TradeMonitor — 轮询模式
typescript
import { TradeMonitor } from './src/TradeMonitor';
const monitor = new TradeMonitor({
targetWallet: process.env.TARGET_WALLET!,
pollInterval: Number(process.env.POLL_INTERVAL ?? 2000),
});
monitor.on('trade', (trade) => {
console.log('New trade detected:', trade);
// trade.side: 'BUY' | 'SELL'
// trade.asset: token ID (outcome token address)
// trade.size: USDC size
// trade.price: fill price (0–1)
});
monitor.start();typescript
import { TradeMonitor } from './src/TradeMonitor';
const monitor = new TradeMonitor({
targetWallet: process.env.TARGET_WALLET!,
pollInterval: Number(process.env.POLL_INTERVAL ?? 2000),
});
monitor.on('trade', (trade) => {
console.log('检测到新交易:', trade);
// trade.side: 'BUY' | 'SELL'
// trade.asset: 代币ID(结果代币地址)
// trade.size: USDC金额
// trade.price: 成交价格(0–1)
});
monitor.start();TradeExecutor — placing a copy order
TradeExecutor — 提交跟单订单
typescript
import { TradeExecutor } from './src/TradeExecutor';
import { ClobClient } from '@polymarket/clob-client';
import { ethers } from 'ethers';
const provider = new ethers.providers.JsonRpcProvider(process.env.RPC_URL);
const signer = new ethers.Wallet(process.env.WALLET_PRIVATE_KEY!, provider);
const clobClient = new ClobClient(
'https://clob.polymarket.com',
137, // Polygon chainId
signer,
apiCreds, // loaded from .polymarket-api-creds
Number(process.env.SIG_TYPE ?? 0),
process.env.PROXY_WALLET_ADDRESS || undefined,
);
const executor = new TradeExecutor({
client: clobClient,
positionMultiplier: Number(process.env.POSITION_MULTIPLIER ?? 0.1),
maxTradeSize: Number(process.env.MAX_TRADE_SIZE ?? 100),
minTradeSize: Number(process.env.MIN_TRADE_SIZE ?? 1),
orderType: (process.env.ORDER_TYPE ?? 'FOK') as 'FOK' | 'FAK' | 'LIMIT',
slippageTolerance: Number(process.env.SLIPPAGE_TOLERANCE ?? 0.02),
});
// Copy a detected trade
await executor.copyTrade({
side: 'BUY',
tokenId: '0xAssetId...',
originalSize: 12.5, // USDC from target's trade
price: 0.62,
});typescript
import { TradeExecutor } from './src/TradeExecutor';
import { ClobClient } from '@polymarket/clob-client';
import { ethers } from 'ethers';
const provider = new ethers.providers.JsonRpcProvider(process.env.RPC_URL);
const signer = new ethers.Wallet(process.env.WALLET_PRIVATE_KEY!, provider);
const clobClient = new ClobClient(
'https://clob.polymarket.com',
137, // Polygon链ID
signer,
apiCreds, // 从.polymarket-api-creds加载
Number(process.env.SIG_TYPE ?? 0),
process.env.PROXY_WALLET_ADDRESS || undefined,
);
const executor = new TradeExecutor({
client: clobClient,
positionMultiplier: Number(process.env.POSITION_MULTIPLIER ?? 0.1),
maxTradeSize: Number(process.env.MAX_TRADE_SIZE ?? 100),
minTradeSize: Number(process.env.MIN_TRADE_SIZE ?? 1),
orderType: (process.env.ORDER_TYPE ?? 'FOK') as 'FOK' | 'FAK' | 'LIMIT',
slippageTolerance: Number(process.env.SLIPPAGE_TOLERANCE ?? 0.02),
});
// 复制检测到的交易
await executor.copyTrade({
side: 'BUY',
tokenId: '0x资产ID...',
originalSize: 12.5, // 目标交易的USDC金额
price: 0.62,
});RiskManager — checking before execution
RiskManager — 执行前风险校验
typescript
import { RiskManager } from './src/RiskManager';
const riskManager = new RiskManager({
maxSessionNotional: Number(process.env.MAX_SESSION_NOTIONAL ?? 0),
maxPerMarketNotional: Number(process.env.MAX_PER_MARKET_NOTIONAL ?? 0),
});
const allowed = riskManager.checkTrade({
marketId: '0xConditionId...',
notional: copySize,
});
if (!allowed) {
console.log('Trade blocked by risk limits');
}typescript
import { RiskManager } from './src/RiskManager';
const riskManager = new RiskManager({
maxSessionNotional: Number(process.env.MAX_SESSION_NOTIONAL ?? 0),
maxPerMarketNotional: Number(process.env.MAX_PER_MARKET_NOTIONAL ?? 0),
});
const allowed = riskManager.checkTrade({
marketId: '0x条件ID...',
notional: copySize,
});
if (!allowed) {
console.log('交易被风险限制拦截');
}WebSocket monitor — low-latency subscription
WebSocket监控 — 低延迟订阅
typescript
import { WebSocketMonitor } from './src/WebSocketMonitor';
const wsMonitor = new WebSocketMonitor({
useUserChannel: process.env.USE_USER_CHANNEL === 'true',
assetIds: process.env.WS_ASSET_IDS?.split(',').filter(Boolean) ?? [],
marketIds: process.env.WS_MARKET_IDS?.split(',').filter(Boolean) ?? [],
});
wsMonitor.on('orderFilled', (fill) => {
console.log('Fill received via WS:', fill);
});
wsMonitor.connect();typescript
import { WebSocketMonitor } from './src/WebSocketMonitor';
const wsMonitor = new WebSocketMonitor({
useUserChannel: process.env.USE_USER_CHANNEL === 'true',
assetIds: process.env.WS_ASSET_IDS?.split(',').filter(Boolean) ?? [],
marketIds: process.env.WS_MARKET_IDS?.split(',').filter(Boolean) ?? [],
});
wsMonitor.on('orderFilled', (fill) => {
console.log('通过WS收到成交通知:', fill);
});
wsMonitor.connect();Authentication Modes
身份验证模式
EOA (default — SIG_TYPE=0
)
SIG_TYPE=0EOA(默认 — SIG_TYPE=0
)
SIG_TYPE=0env
SIG_TYPE=0
WALLET_PRIVATE_KEY=0xYourKeyenv
SIG_TYPE=0
WALLET_PRIVATE_KEY=0x你的私钥PROXY_WALLET_ADDRESS — leave empty
PROXY_WALLET_ADDRESS — 留空即可
On first run, the bot auto-submits USDC.e/CTF approval transactions. Wallet needs POL for gas.
首次运行时,机器人会自动提交USDC.e/CTF授权交易,钱包需要有POL支付gas费。Poly Proxy (SIG_TYPE=1
)
SIG_TYPE=1Poly代理(SIG_TYPE=1
)
SIG_TYPE=1env
SIG_TYPE=1
WALLET_PRIVATE_KEY=0xSignerKey
PROXY_WALLET_ADDRESS=0xYourPolymarketProxyAddressenv
SIG_TYPE=1
WALLET_PRIVATE_KEY=0x签名者私钥
PROXY_WALLET_ADDRESS=0x你的Polymarket代理地址Poly Polymorphic (SIG_TYPE=2
)
SIG_TYPE=2Poly多签(SIG_TYPE=2
)
SIG_TYPE=2env
SIG_TYPE=2
WALLET_PRIVATE_KEY=0xSignerKey
PROXY_WALLET_ADDRESS=0xYourPolymorphicSafeAddressenv
SIG_TYPE=2
WALLET_PRIVATE_KEY=0x签名者私钥
PROXY_WALLET_ADDRESS=0x你的多签Safe地址Generating API Credentials
生成API凭证
bash
npm run generate-api-credsThis derives API keys from your wallet signature and writes them to . Run once before if you want to pre-generate credentials. The bot also auto-generates them on first start in EOA mode.
.polymarket-api-credsnpm startValidate credentials:
bash
npm run test-api-credsbash
npm run generate-api-creds该命令会通过你的钱包签名生成API密钥,并写入到文件。如果你希望预先生成凭证,可以在运行前执行一次。EOA模式下机器人首次启动时也会自动生成凭证。
.polymarket-api-credsnpm start验证凭证:
bash
npm run test-api-credsCommon Patterns
常用配置方案
Conservative testing setup
保守测试配置
env
POSITION_MULTIPLIER=0.05
MAX_TRADE_SIZE=5
MIN_TRADE_SIZE=1
MAX_SESSION_NOTIONAL=20
ORDER_TYPE=FOK
USE_WEBSOCKET=falseenv
POSITION_MULTIPLIER=0.05
MAX_TRADE_SIZE=5
MIN_TRADE_SIZE=1
MAX_SESSION_NOTIONAL=20
ORDER_TYPE=FOK
USE_WEBSOCKET=falseWebSocket-only market channel (lower latency)
仅使用WebSocket市场通道(更低延迟)
env
USE_WEBSOCKET=true
USE_USER_CHANNEL=false
WS_ASSET_IDS=0xTokenId1,0xTokenId2env
USE_WEBSOCKET=true
USE_USER_CHANNEL=false
WS_ASSET_IDS=0x代币ID1,0x代币ID2LIMIT orders with slippage buffer
带滑点缓冲的限价单配置
env
ORDER_TYPE=LIMIT
SLIPPAGE_TOLERANCE=0.03env
ORDER_TYPE=LIMIT
SLIPPAGE_TOLERANCE=0.03Troubleshooting
常见问题排查
Bot starts but no trades detected
- Verify is a valid Polymarket wallet with recent activity
TARGET_WALLET - Check — default 2000ms; lower means more API calls
POLL_INTERVAL - Confirm the target wallet trades on Polymarket (not just holds positions)
ethers- The project pins ethers v5. Do not upgrade to v6 — the CLOB SDK requires v5
- Run to check for duplicate versions
npm ls ethers
Approval transactions failing
- Ensure the wallet has sufficient POL (MATIC) for gas on Polygon mainnet
- Try increasing and
MIN_PRIORITY_FEE_GWEIif transactions stallMIN_MAX_FEE_GWEI
generate-api-creds- Confirm is correct and 0x-prefixed
WALLET_PRIVATE_KEY - For , ensure
SIG_TYPE=1/2matches your Polymarket accountPROXY_WALLET_ADDRESS
Orders rejected by CLOB
- FOK orders fail if insufficient liquidity — try or
ORDER_TYPE=FAKLIMIT - Check isn't too tight for illiquid markets
SLIPPAGE_TOLERANCE
Session notional cap hit immediately
- resets per process run; restart the bot to reset
MAX_SESSION_NOTIONAL - Set to disable the cap entirely
MAX_SESSION_NOTIONAL=0
机器人启动但未检测到任何交易
- 确认是有效的Polymarket钱包,且近期有交易活动
TARGET_WALLET - 检查配置,默认2000ms,值越小API调用频率越高
POLL_INTERVAL - 确认目标钱包确实在Polymarket上交易(而非仅持有仓位)
ethers- 项目已锁定ethers v5版本,请勿升级到v6,CLOB SDK依赖v5
- 运行检查是否存在重复版本
npm ls ethers
授权交易失败
- 确认钱包在Polygon主网上有足够的POL(原MATIC)支付gas费
- 如果交易卡住,可以尝试提高和
MIN_PRIORITY_FEE_GWEI的值MIN_MAX_FEE_GWEI
generate-api-creds- 确认正确且带有0x前缀
WALLET_PRIVATE_KEY - 如果是,确认
SIG_TYPE=1/2和你的Polymarket账户匹配PROXY_WALLET_ADDRESS
订单被CLOB拒绝
- 如果流动性不足,FOK订单会失败,可以尝试或
ORDER_TYPE=FAKLIMIT - 对于流动性差的市场,检查是否设置过小
SLIPPAGE_TOLERANCE
刚启动就触发会话金额上限
- 每次进程运行都会重置,重启机器人即可重置计数
MAX_SESSION_NOTIONAL - 设为即可完全关闭该限制
MAX_SESSION_NOTIONAL=0
Wallet Requirements
钱包要求
- USDC.e on Polygon mainnet (collateral for trades)
- POL (formerly MATIC) for gas fees
- Approve USDC.e for Polymarket CTF Exchange and CLOB contracts (bot does this automatically on first EOA run)
- Polygon主网上有USDC.e(交易抵押品)
- 有POL(原MATIC)支付gas费
- 需要授权Polymarket CTF交易所和CLOB合约调用USDC.e(EOA模式下首次运行机器人会自动完成授权)