A high-frequency arbitrage bot that detects and executes complete-set arbitrage opportunities on Polymarket prediction markets.
In binary prediction markets, every outcome resolves to exactly 1ドル.00. Complete-set arbitrage exploits pricing inefficiencies where:
YES_price + NO_price + fees < 1ドル.00
When this occurs, buying both YES and NO tokens guarantees profit at resolution, regardless of the outcome.
Example:
- YES token ask: 0ドル.45
- NO token ask: 0ドル.52
- Total cost: 0ドル.97
- Resolution payout: 1ドル.00
- Guaranteed profit: 0ドル.03 (3%)
- Real-time WebSocket data - Streams order book updates from Polymarket CLOB
- Sub-second opportunity detection - Evaluates every book update for arbitrage
- Paper trading mode - Full simulation without placing real orders (default)
- Partial-fill protection - Cancels unfilled legs and halts on partial fills
- Kill switch - Auto-halts on repeated failures to prevent losses
- Full audit trail - SQLite ledger tracks every opportunity, order, and fill
- CLI + Dashboard - Rich terminal interface and Streamlit web dashboard
- Venue-agnostic architecture - Adapter pattern supports multiple venues
- Python 3.11+
- Non-US server (Polymarket blocks US IPs)
# Clone the repository git clone https://github.com/YOUR_USERNAME/polymarket-arb-bot.git cd polymarket-arb-bot # Create virtual environment python3 -m venv venv source venv/bin/activate # Install dependencies pip install -r requirements.txt
- Copy the environment template:
cp deploy/.env.example .env
- Edit
.envwith your Polymarket credentials (for live trading):
POLYMARKET_API_KEY=your_key POLYMARKET_API_SECRET=your_secret POLYMARKET_PASSPHRASE=your_passphrase
- Review
config.yamlfor strategy parameters.
# With mock data (for testing) python -m src.cli.commands run --paper -c config_mock.yaml # With real Polymarket data (no real orders) python -m src.cli.commands run --paper -c config.yaml
streamlit run app.py --server.port 5000
polymarket-arb-bot/
├── src/
│ ├── adapters/ # Venue adapters
│ │ ├── base.py # VenueAdapter interface
│ │ ├── mock.py # Mock adapter for testing
│ │ └── polymarket.py # Polymarket CLOB adapter
│ ├── marketdata/
│ │ └── orderbook_state.py # Order book state management
│ ├── strategy/
│ │ └── signal_engine.py # Opportunity detection
│ ├── execution/
│ │ ├── executor.py # Trade execution engine
│ │ └── risk.py # Kill switch & risk management
│ ├── storage/
│ │ └── ledger.py # SQLite audit trail
│ ├── cli/
│ │ └── commands.py # CLI interface
│ ├── reporting/
│ │ └── report.py # Performance reports
│ ├── config.py # Configuration loader
│ └── main.py # Bot orchestrator
├── deploy/ # Deployment files
│ ├── README.md # Deployment guide
│ ├── install.sh # Ubuntu setup script
│ ├── arbbot.service # Systemd service
│ └── .env.example # Environment template
├── app.py # Streamlit dashboard
├── config.yaml # Production config
├── config_mock.yaml # Mock testing config
└── requirements.txt # Python dependencies
# Run the bot python -m src.cli.commands run --paper -c config.yaml # Check current status python -m src.cli.commands status # Generate performance report python -m src.cli.commands report # Halt trading (emergency stop) python -m src.cli.commands halt # Resume trading python -m src.cli.commands resume
venue: name: polymarket # or "mock" for testing strategy: min_edge: 0.01 # Minimum profit threshold (0ドル.01) min_depth: 10 # Minimum size at best ask cooldown_seconds: 5 # Cooldown between trades on same market execution: order_size: 10 # Base order size in tokens timeout_seconds: 30 # Order timeout before cancel risk: halt_on_partial_fill: true # Auto-halt if only one leg fills max_consecutive_failures: 3 # Kill switch threshold paper_mode: true # Simulation mode (no real orders)
| Variable | Description | Required |
|---|---|---|
POLYMARKET_API_KEY |
Polymarket API key | For live trading |
POLYMARKET_API_SECRET |
Polymarket API secret | For live trading |
POLYMARKET_PASSPHRASE |
Polymarket passphrase | For live trading |
POLYMARKET_PROXY_URL |
HTTP proxy URL | If behind geo-restriction |
The bot connects to Polymarket's WebSocket API and subscribes to order book updates for active markets.
On every book update, the SignalEngine evaluates:
- Combined cost of YES + NO at best asks
- Available depth at those prices
- Market cooldown status
- Minimum edge threshold
When an opportunity is found:
- Submit buy orders for both YES and NO tokens
- Monitor for fills with timeout
- If partial fill occurs, cancel unfilled leg and trigger halt
- Log all activity to SQLite ledger
The kill switch monitors for:
- Partial fills (single-leg exposure)
- Order rejections
- WebSocket disconnections
- Consecutive failures
The bot requires a non-US server due to Polymarket's geo-restrictions.
- Create an Ubuntu 24.04 droplet in Amsterdam or any EU region (8ドル/month)
- Clone this repo and run the install script:
git clone https://github.com/YOUR_USERNAME/polymarket-arb-bot.git
cd polymarket-arb-bot
chmod +x deploy/install.sh
sudo ./deploy/install.sh- Configure your credentials:
cp deploy/.env.example /home/arbbot/arb-bot/.env nano /home/arbbot/arb-bot/.env
- Start the bot:
sudo systemctl start arbbot sudo systemctl status arbbot
See deploy/README.md for detailed deployment instructions.
| Feature | Description |
|---|---|
| Paper Mode | Default mode - simulates trades without real orders |
| Kill Switch | Auto-halts after consecutive failures |
| Partial-Fill Protection | Cancels unfilled legs, halts to prevent exposure |
| Cooldown | Prevents rapid-fire trades on same market |
| Audit Trail | Full SQLite log of all trading activity |
| Position Limits | Configurable maximum position sizes |
All trading activity is logged to arb_ledger.db:
-- View recent opportunities SELECT * FROM opportunities ORDER BY timestamp DESC LIMIT 10; -- View trade history SELECT * FROM tradesets ORDER BY created_at DESC LIMIT 10; -- Check risk events SELECT * FROM risk_events ORDER BY timestamp DESC;
The web dashboard provides:
- Real-time bot status
- Opportunity history
- Trade history
- PnL tracking
- Risk event log
Use the mock adapter for testing without connecting to Polymarket:
python -m src.cli.commands run --paper -c config_mock.yaml
The mock adapter generates synthetic market data with configurable arbitrage opportunities.
If you see "US IP detected" or connection failures:
- Ensure you're running from a non-US server
- Check if proxy is configured in
.env
Complete-set arbitrage opportunities are rare. The bot will:
- Log "Scanning..." periodically to confirm it's running
- Alert immediately when opportunities are detected
# Restart the bot to clear memory
sudo systemctl restart arbbotThis is a personal project, but suggestions are welcome. Please open an issue first to discuss any changes.
This software is for educational purposes only.
- Trading prediction markets involves significant risk
- Past performance does not guarantee future results
- Always test thoroughly in paper mode before live trading
- The authors are not responsible for any financial losses
- Ensure compliance with all applicable laws in your jurisdiction
MIT License - see LICENSE for details.