A Python bot that monitors wallets on Polymarket and mirrors their open positions at scale.
Designed to validate strategies in paper mode before risking real capital.
poly-agent/
├── main.py # Entry point
├── config.py # Central configuration (edit this)
├── trader.py # Core engine
├── api.py # Polymarket API wrapper
├── storage.py # Persistence (CSV trades, JSON positions, capital)
├── requirements.txt
├── .env.example # Credentials template (copy to .env, never commit .env)
└── data/ # Created at runtime — gitignored
├── trades.csv # Full trade history (opens, closes, skips)
├── positions.json # Currently open positions
├── capital.json # Capital state
└── cerrados.json # Already-closed markets (prevents re-entry)
# 1. Create and activate a virtual environment
python3 -m venv venv
source venv/bin/activate # Mac/Linux
# 2. Install dependencies
pip install -r requirements.txt
# 3. Create .env (only needed for live mode)
cp .env.example .env
# Then fill in your POLY_PRIVATE_KEY and POLY_PROXY_WALLET
# 4. Add wallets to follow in config.py
# Edit: WALLETS = {"alias": "0x..."}python main.py --paperRuns indefinitely, polling every 60 seconds. Press Ctrl+C to stop.
python main.py --paper --oncepython main.py --paper --interval 30 # every 30 seconds
python main.py --paper --interval 120 # every 2 minutes# In another terminal
cat data/trades.csv | column -t -s,
# Only closed trades with PnL
grep "CLOSE" data/trades.csv | column -t -s,
# Quick PnL summary
grep "CLOSE" data/trades.csv | awk -F',' '{sum+=$13} END {print "Total PnL: $" sum}'# Before running live:
# 1. Make sure POLY_PRIVATE_KEY and POLY_PROXY_WALLET are set in .env
# 2. Update CAPITAL_INICIAL in config.py with your real account balance
# 3. Adjust MAX_TRADE_USDC if your capital is larger
python main.py --liveIn live mode the system reads the real USDC balance from the account before each trade, enabling automatic real compounding.
| Parameter | Default | Description |
|---|---|---|
PAPER_MODE |
True |
Paper vs live trading |
CAPITAL_INICIAL |
1000.0 |
Reference USDC for paper mode |
TRADE_PCT |
0.05 |
% of capital per trade (5% = up to 20 simultaneous slots) |
MIN_TRADE_USDC |
1.0 |
Minimum per trade |
MAX_TRADE_USDC |
8.0 |
Maximum per trade (safety cap — raise as capital grows) |
MAX_PRICE_DRIFT |
0.10 |
Max allowed drift to enter (10%) |
MAX_ENTRY_PRICE |
0.97 |
Skip if price is already >97% (minimal upside) |
POLL_INTERVAL |
60 |
Seconds between polls |
In config.py:
WALLETS = {
"trader_one": "0x...",
"trader_two": "0x...",
}data/trades.csv contains all columns needed to calculate:
- PnL per followed wallet
- Your win rate vs the copied wallet's win rate
- Impact of drift (skipped trades)
- % return on capital
Key columns:
price_entry/price_exit→ to manually calculate PnLside→ OPEN / CLOSE / SKIPpnl_usdc/pnl_pct→ automatically calculated on closewallet_alias→ to filter by followed wallet
Paper mode: capital grows/shrinks with PnL from the CSV. Each trade is
capital_total × TRADE_PCT. Simulated compounding effect.
Live mode: reads real USDC balance from the account before each trade. If you gain $20, the next trade is 5% of the new total. Real automatic compounding.
With TRADE_PCT = 0.05 you have 20 simultaneous slots available.
If the followed wallet opens more than 20 trades at once, the excess are queued
and entered when capital is freed.
If a new position is detected but no capital is available:
- It gets queued in memory
- Each cycle checks the current price vs the price when the target wallet entered
- If drift exceeds
MAX_PRICE_DRIFT(10%) → SKIP, logged in trades.csv - If the price is still close → enters when capital is freed
data/cerrados.jsonpersists across restarts — already-closed markets are not reopened even if the target wallet still holds them- If the process crashes, on restart it restores positions and capital from
data/ - Do not delete
data/while there are open positions - Never commit
.env— it contains your private key
If this project was useful to you, contributions are welcome via USDC on Polygon:
0xbc48eAebC98463c7c9521e1310C13FC1A080B419