A production-grade Polymarket copy trading bot with bug fixes and improvements. This bot automatically monitors target wallets and copies their trades in real-time using WebSocket connections.
This bot is an improved version of the Polymarket copy trading bot with the following fixes and enhancements:
- Fixed maxAmount calculation bug - Corrected logic in order amount calculation
- Enabled balance validation for SELL orders - Re-enabled commented-out balance checks to prevent overselling
- Added duplicate trade prevention - Prevents processing the same trade multiple times using transaction hash tracking
- Improved wallet address validation - Now checks all possible wallet address fields (proxyWallet, wallet, user, address, userAddress)
- Added WebSocket reconnection logic - Automatic reconnection with exponential backoff on connection failures
- Fixed directory creation - Automatically creates data directory if it doesn't exist
- Enhanced error handling - Better error recovery and logging
- Runtime: Node.js with TypeScript
- Language: TypeScript 5.9+ (strict mode)
- Blockchain: Polygon (Ethereum-compatible L2)
- APIs:
- Polymarket CLOB Client (
@polymarket/clob-client) - Polymarket Real-Time Data Client (
@polymarket/real-time-data-client)
- Polymarket CLOB Client (
- Web3: Ethers.js for blockchain interactions
- Logging: Custom structured logger with chalk
WebSocket Connection β Trade Detection β Wallet Validation β Duplicate Check
β
Order Execution β Balance Validation β Order Building β Trade Processing
β
Holdings Update β Success Logging
- Node.js 18+ and npm
- TypeScript 5.9+
- Polygon wallet with USDC for trading
- Private key for wallet authentication
-
Clone or navigate to the project
cd Polymarket-Copytrading-Bot -
Install dependencies
npm install
-
Configure environment variables
cp .env.example .env
Edit
.envwith your configuration:# Wallet Configuration (REQUIRED) PRIVATE_KEY=your_private_key_here TARGET_WALLET=0x... # Wallet address to copy trades from # Trading Configuration SIZE_MULTIPLIER=1.0 MAX_ORDER_AMOUNT=100 ORDER_TYPE=FAK TICK_SIZE=0.01 NEG_RISK=false ENABLE_COPY_TRADING=true # Redemption Configuration REDEEM_DURATION=60 # Minutes between auto-redemptions (null = disabled) # API Configuration CHAIN_ID=137 # Polygon mainnet (80002 for Amoy testnet) CLOB_API_URL=https://clob.polymarket.com USER_REAL_TIME_DATA_URL=wss://ws-live-data.polymarket.com # Optional DEBUG=false
-
Initialize credentials On first run, the bot will automatically create API credentials using your
PRIVATE_KEY. Credentials are saved tosrc/data/credential.json.
| Variable | Type | Default | Description |
|---|---|---|---|
PRIVATE_KEY |
string | required | Private key of trading wallet |
TARGET_WALLET |
string | required | Wallet address to copy trades from |
SIZE_MULTIPLIER |
number | 1.0 |
Multiplier for trade sizes (e.g., 2.0 = 2x size) |
MAX_ORDER_AMOUNT |
number | undefined |
Maximum USDC amount per order |
ORDER_TYPE |
string | FAK |
Order type: FAK or FOK |
TICK_SIZE |
string | 0.01 |
Price precision: 0.1, 0.01, 0.001, 0.0001 |
NEG_RISK |
boolean | false |
Enable negative risk (allow negative balances) |
ENABLE_COPY_TRADING |
boolean | true |
Enable/disable copy trading |
REDEEM_DURATION |
number | null |
Minutes between auto-redemptions (null = disabled) |
CHAIN_ID |
number | 137 |
Blockchain chain ID (137 = Polygon, 80002 = Amoy) |
CLOB_API_URL |
string | https://clob.polymarket.com |
CLOB API endpoint |
USER_REAL_TIME_DATA_URL |
string | wss://ws-live-data.polymarket.com |
WebSocket URL |
DEBUG |
boolean | false |
Enable debug logging |
- Size Multiplier: Scales the copied trade size.
1.0= exact copy,2.0= double size,0.5= half size - Max Order Amount: Safety limit to prevent oversized positions. When exceeded, uses 50% of maxAmount
- Order Type:
FAK(Fill-and-Kill): Partial fills allowed, remaining unfilled portion cancelledFOK(Fill-or-Kill): Entire order must fill immediately or cancelled
- Tick Size: Price precision for order placement. Must match market's tick size
- Negative Risk: When enabled, allows orders that may result in negative USDC balance
# Start copy trading bot
npm start
# Or using ts-node directly
ts-node src/index.tsThe bot will:
- Initialize WebSocket connection to Polymarket
- Subscribe to trade activity feed
- Monitor target wallet for trades
- Automatically copy trades when detected
- Run scheduled redemptions (if enabled)
# Redeem all resolved markets from token-holding.json
npm run redeem
# Or directly
ts-node src/auto-redeem.ts# Check market status
ts-node src/redeem.ts --check <conditionId>
# Redeem specific market
ts-node src/redeem.ts <conditionId>- Trade Detection: WebSocket receives trade activity message
- Wallet Filtering: Validates trade originates from target wallet (checks all address fields)
- Duplicate Prevention: Checks if trade has already been processed (by transaction hash)
- Order Construction: Converts trade payload to market order:
- Applies size multiplier
- Validates against max order amount
- Adjusts price to tick size
- Sets order type (FAK/FOK)
- Balance Validation:
- For BUY: Checks sufficient USDC balance
- For SELL: Checks available token balance (accounting for open orders)
- Allowance Management: Ensures proper token approvals
- Order Execution: Submits order to CLOB API
- Holdings Update: Records token positions locally
- Logging: Logs all operations with structured output
// Tracks processed trades by transaction hash
const processedTrades = new Set<string>();
// Prevents processing same trade twice
if (isTradeProcessed(tradeHash)) {
return; // Skip duplicate
}// Checks all possible wallet address fields
function isFromTargetWallet(payload: TradePayload, targetAddress: string): boolean {
const walletFields = [
payload.proxyWallet,
payload.wallet,
payload.user,
payload.address,
payload.userAddress,
];
return walletFields.some(field => field?.toLowerCase() === target);
}// Automatic reconnection with exponential backoff
if (reconnectAttempts < maxReconnectAttempts) {
setTimeout(() => {
const newClient = connectWebSocket();
newClient.connect();
}, reconnectDelay);
}// Re-enabled balance validation to prevent overselling
const balanceCheck = await validateSellOrderBalance(
this.client,
tokenId,
holdingsAmount
);
const sellAmount = Math.min(holdingsAmount, balanceCheck.available);The bot maintains a local JSON database (src/data/token-holding.json) tracking all token positions. When markets resolve:
- Resolution Check: Queries Polymarket API for market status
- Winning Detection: Identifies winning outcome tokens
- Balance Verification: Confirms user holds winning tokens
- Redemption Execution: Calls Polymarket redemption contract
- Holdings Cleanup: Removes redeemed positions from database
- Credential Management: Secure API key storage in
src/data/credential.json - Allowance Control: Automatic USDC approval management
- Balance Validation: Pre-order balance checks prevent over-trading
- Error Handling: Comprehensive error handling with graceful degradation
- Private Key Security: Uses environment variables (never hardcoded)
- Duplicate Prevention: Prevents accidental double execution
Polymarket-Copytrading-Bot/
βββ src/
β βββ index.ts # Main bot entry point (FIXED)
β βββ auto-redeem.ts # Automated redemption script
β βββ redeem.ts # Manual redemption script
β βββ data/ # Data storage (auto-created)
β β βββ credential.json # API credentials (auto-generated)
β β βββ token-holding.json # Token holdings database
β βββ order-builder/ # Order construction logic
β β βββ builder.ts # TradeOrderBuilder class (FIXED)
β β βββ helpers.ts # Order conversion utilities (FIXED)
β β βββ types.ts # Type definitions
β β βββ index.ts # Exports
β βββ providers/ # API clients
β β βββ clobclient.ts # CLOB API client
β β βββ wssProvider.ts # WebSocket provider
β β βββ rpcProvider.ts # RPC provider
β βββ security/ # Security utilities
β β βββ allowance.ts # Token approval management
β β βββ createCredential.ts # Credential generation
β βββ utils/ # Utility functions
β βββ balance.ts # Balance checking
β βββ holdings.ts # Holdings management (FIXED)
β βββ logger.ts # Logging utility
β βββ redeem.ts # Redemption logic
β βββ types.ts # TypeScript types
β βββ config.ts # Configuration
βββ package.json
βββ tsconfig.json
βββ README.md
The bot uses the official @polymarket/clob-client for order execution:
import { ClobClient, OrderType, Side } from "@polymarket/clob-client";
const client = await getClobClient();
const response = await client.createAndPostMarketOrder(
marketOrder,
orderOptions,
orderType
);WebSocket connection for live trade monitoring:
import { RealTimeDataClient } from "@polymarket/real-time-data-client";
client.subscribe({
subscriptions: [{
topic: "activity",
type: "trades"
}]
});The bot provides comprehensive logging:
- Trade Detection: Logs all detected trades from target wallet
- Order Execution: Records order placement and results
- Redemption Activity: Tracks redemption operations
- Error Handling: Detailed error messages with stack traces
- Balance Updates: Displays wallet balances after operations
- WebSocket Status: Logs connection and reconnection events
Log levels:
info: General operational messagessuccess: Successful operationswarning: Non-critical issueserror: Errors requiring attentiondebug: Debug messages (whenDEBUG=true)
- Market Risk: Copy trading amplifies both gains and losses
- Liquidity Risk: Large orders may not fill completely
- Slippage: Market orders execute at current market price
- Gas Costs: Each transaction incurs Polygon gas fees
- API Limits: Rate limiting may affect order execution
- Network Latency: WebSocket delays may cause missed trades
- Duplicate Prevention: Failed trades are unmarked for retry, which could cause issues if not handled properly
Recommendations:
- Start with small size multipliers
- Set conservative max order amounts
- Monitor wallet balance regularly
- Test with small amounts before scaling
- Review logs regularly for errors
- Keep sufficient USDC balance for trading
# Type checking
npm run build
# Run in development
npm start# Test redemption (dry run)
ts-node src/auto-redeem.ts
# Test specific market
ts-node src/redeem.ts --check <conditionId>-
maxAmount Calculation Bug (helpers.ts)
- Issue: When calculated amount exceeded maxAmount, it returned maxAmount instead of the calculated capped amount
- Fix: Returns
maxAmount * 0.5when limit is exceeded (as per original logic)
-
Disabled Balance Validation (builder.ts)
- Issue: Balance validation for SELL orders was commented out, risking overselling
- Fix: Re-enabled balance validation to prevent selling more tokens than available
-
Missing Duplicate Prevention (index.ts)
- Issue: Same trade could be processed multiple times if WebSocket sent duplicates
- Fix: Added transaction hash tracking to prevent duplicate execution
-
Incomplete Wallet Validation (index.ts)
- Issue: Only checked
proxyWalletfield, missing other possible address fields - Fix: Now checks all wallet address fields (proxyWallet, wallet, user, address, userAddress)
- Issue: Only checked
-
No WebSocket Reconnection (index.ts)
- Issue: Bot would crash on WebSocket disconnection
- Fix: Added automatic reconnection logic with retry limits
-
Missing Directory Creation (holdings.ts)
- Issue: Data directory might not exist, causing file write failures
- Fix: Automatically creates
src/data/directory if it doesn't exist
ISC
Contributions welcome! Please ensure:
- Code follows TypeScript best practices
- All functions are properly typed
- Error handling is comprehensive
- Logging is informative
- Documentation is updated
For issues, questions, or contributions:
- Review existing documentation
- Check Polymarket API documentation
- Review logs for error messages
Disclaimer: This software is provided as-is. Trading cryptocurrencies and prediction markets carries significant risk. Use at your own discretion and never trade more than you can afford to lose.
Version: 1.0.0 (Fixed and Improved) Last Updated: 2024