An automated trading system for Polymarket prediction markets featuring quantitative strategies, real-time dashboards, and comprehensive risk management.
- Market Making: Avellaneda-Stoikov model with dynamic inventory management
- Edge Detection: Kelly criterion position sizing for probability edges
- Mean Reversion: Z-score based strategy with adaptive parameters
- Hot Market Scorer: Ranks markets by exploitability using microstructure metrics
- Real-time drawdown monitoring with circuit breakers
- Position limits by market, category, and total exposure
- Daily/weekly loss limits with automatic halt
- Slippage modeling for realistic paper trading
- Unified API Client: Type-safe Polymarket API access with shared rate limiting
- Paper Trading: Full simulation with realistic order fills and P&L tracking
- Backtesting: Walk-forward testing with Brier score metrics
- Real-time Dashboard: React frontend with live updates via WebSocket
- Telegram Alerts: Trade notifications and system alerts
polypigeon/ ├── backend/ # FastAPI Python backend │ ├── app/ │ │ ├── api/ # REST API routes │ │ │ └── routes/ # Dashboard, trading, markets, analysis │ │ ├── connectors/ # Legacy Polymarket connector + WebSocket │ │ ├── core/ # Trading engine, risk manager, paper bots │ │ ├── db/ # SQLAlchemy models and schemas │ │ ├── polymarket/ # ★ NEW: Unified API module │ │ │ ├── models/ # Pydantic models (OrderBook, Market, etc.) │ │ │ ├── endpoints/ # API endpoint handlers │ │ │ ├── normalizers/ # Response format normalization │ │ │ ├── client.py # Singleton client │ │ │ └── rate_limiter.py # Token bucket rate limiting │ │ ├── services/ # Alerts, monitoring │ │ └── strategies/ # Market making, edge detection, microstructure │ └── backtesting/ # Historical backtesting engine ├── frontend/ # Vite + React dashboard │ └── src/ │ ├── components/ # Dashboard cards, charts, tables │ ├── hooks/ # React Query hooks │ └── views/ # Analysis views └── docker-compose.yml # Docker orchestration - Python 3.12+
- Node.js 18+
- PostgreSQL (optional, SQLite works for development)
cd backend python -m venv venv source venv/bin/activate # Windows: venv\Scripts\activate pip install -r requirements.txt # Configure environment cp .env.example .env # Edit .env with your settings (see Configuration below)cd frontend npm install# Terminal 1 - Backend (starts on port 8000) cd backend uvicorn app.main:app --reload # Terminal 2 - Frontend (starts on port 5173) cd frontend npm run devNavigate to http://localhost:5173
docker-compose up -dCreate a .env file in the backend/ directory:
| Variable | Description | Default |
|---|---|---|
PRIVATE_KEY | Ethereum wallet private key for live trading | - |
FUNDER_ADDRESS | Polymarket funder address | - |
DATABASE_URL | Database connection string | sqlite:///./polypigeon.db |
TRADING_MODE | paper, live, or shadow | paper |
INITIAL_CAPITAL | Starting capital in USDC | 5000 |
TELEGRAM_BOT_TOKEN | Telegram bot for alerts | - |
TELEGRAM_CHAT_ID | Telegram chat ID | - |
| Limit | Value | Description |
|---|---|---|
| Max position | 10% | $500 per market |
| Max exposure | 60% | $3,000 total |
| Max category | 25% | $1,250 per category |
| Daily loss | 5% | $250 daily limit |
| Weekly loss | 10% | $500 weekly limit |
| Max drawdown | 20% | $1,000 circuit breaker |
The new app.polymarket module provides type-safe, rate-limited access to all Polymarket APIs.
from app.polymarket import get_client, init_client # Initialize once at startup (done in main.py) await init_client() # Use anywhere in the application client = get_client() # Fetch markets from Gamma API markets = await client.markets.list(active=True, limit=100) market = await client.markets.get(condition_id) results = await client.markets.search("election") # Fetch orderbook from CLOB API book = await client.orderbook.get(token_id) books = await client.orderbook.get_batch(token_ids) # Partial retry on failure midpoint = await client.orderbook.get_midpoint(token_id) # Place orders (requires credentials) if client.trading_enabled: from app.polymarket import OrderSide from decimal import Decimal order = await client.trading.place_limit_order( token_id=token_id, side=OrderSide.BUY, price=Decimal("0.55"), size=Decimal("100"), ) # Historical price data history = await client.historical.get_prices(token_id, interval="1h")All endpoints share a unified rate limiter respecting Polymarket's documented limits:
| Endpoint Group | Limit | Window |
|---|---|---|
| General | 5000 | 10s |
| Order book | 200 | 10s |
| Batch order books | 80 | 10s |
| Order placement | 2400 | 10s (burst) |
| Gamma markets | 125 | 10s |
# Check rate budget before batch operations from app.polymarket import get_rate_limiter limiter = get_rate_limiter() wait_time = await limiter.acquire("books", tokens=20) if wait_time > 0: await asyncio.sleep(wait_time)All responses are normalized to type-safe models:
from app.polymarket import ( OrderBook, OrderBookEntry, Market, MarketToken, Event, Order, Trade, OrderSide, OrderType, OrderStatus, PriceBar, PriceHistory, ) # OrderBook with typed entries book: OrderBook = await client.orderbook.get(token_id) for bid in book.bids: print(f"Price: {bid.price}, Size: {bid.size}") # Both are DecimalThe market making strategy uses a simplified Avellaneda-Stoikov model:
Reservation Price: r = s - q × γ × σ² × (T - t) Spread: base_spread + (2.5 × σ × √holding_period) + (0.02 × |inventory_ratio|) Where:
s= mid priceq= current inventoryγ= risk aversion (0.3-0.7)σ= volatilityT-t= time remaining to resolution
Uses Kelly criterion for position sizing on probability edges:
Kelly% = (p × b - q) / b Position = Capital × Kelly% × Fraction × Min(Max_Position) Where:
p= your model's probability estimateb= implied odds from market price- Recommended: 25% Kelly (quarter Kelly) for safety
Ranks markets by exploitability using seven microstructure signals:
| Signal | Weight | Description |
|---|---|---|
| Hurst Exponent | 20% | Mean reversion potential (H < 0.5 = mean reverting) |
| Variance Ratio | 15% | Market efficiency deviation |
| Volatility | 15% | Opportunity size |
| OBI Volatility | 15% | Order book imbalance swings |
| Kurtosis | 10% | Fat tails (emotional trading) |
| Half-life | 15% | Time to mean revert (5-50 is ideal) |
| Inverse VPIN | 10% | Noise trading dominance |
Score Interpretation:
> 1.3: HIGH_OPPORTUNITY - deploy mean reversion strategy0.8-1.3: MODERATE - use conservative sizing< 0.8: LOW/AVOID - skip or use momentum
| Endpoint | Method | Description |
|---|---|---|
/api/dashboard/stats | GET | Dashboard summary statistics |
/api/dashboard/pnl | GET | Detailed P&L breakdown |
/api/dashboard/positions | GET | Current open positions |
/api/dashboard/orders | GET | Open orders |
/api/dashboard/risk | GET | Risk metrics and limits |
/api/dashboard/status | GET | System status |
/api/dashboard/equity-history | GET | Equity curve for charting |
| Endpoint | Method | Description |
|---|---|---|
/api/trading/start | POST | Start trading engine |
/api/trading/stop | POST | Stop trading engine |
/api/trading/markets/add | POST | Add market to trade |
/api/trading/markets/remove | POST | Remove market |
/api/trading/orders/place | POST | Place manual order |
/api/trading/orders/cancel | POST | Cancel order |
| Endpoint | Method | Description |
|---|---|---|
/api/markets | GET | List markets with pagination |
/api/markets/screen | GET | Screen markets for MM suitability |
/api/markets/{condition_id} | GET | Get market details |
/api/markets/{token_id}/orderbook | GET | Order book snapshot |
/api/markets/{token_id}/spread | GET | Bid-ask spread |
/api/markets/{token_id}/history | GET | Price history |
/api/markets/{token_id}/quote-preview | GET | Preview MM quotes |
| Endpoint | Method | Description |
|---|---|---|
/api/analysis/discover-hot | GET | Discover exploitable markets |
/api/analysis/microstructure/{token_id} | GET | Microstructure metrics |
/api/analysis/signals/{token_id} | GET | Trading signals |
| Endpoint | Description |
|---|---|
/ws/dashboard | Real-time dashboard updates |
/ws/orderbook/{token_id} | Live order book stream |
/ws/trades | Trade notifications |
/ws/alerts | System alerts |
Polypigeon includes a comprehensive paper trading system that simulates real trading conditions:
- Realistic fills: Orders fill based on actual order book depth
- Slippage modeling: Simulates market impact and execution slippage
- P&L tracking: Real-time profit/loss calculation
- Multiple bots: Run different strategies simultaneously
- Historical price charts: Real-time price history for all scanned markets
| Parameter | Value | Description |
|---|---|---|
| Premium Markets | 150 | Persistent set of high-quality markets |
| Scan Interval | 5 seconds | Synchronized scan cycle for all bots |
| Volume Range | $50K - $20M | Filters illiquid and whale-dominated markets |
| Min Liquidity | $10K | Ensures tradeable order book depth |
| Min Days to Resolution | 3 | Avoids near-expiry volatility |
The system initializes with these default paper trading bots:
- Conservative market maker
- Aggressive edge detector
- Balanced portfolio bot
The backtesting engine supports walk-forward analysis:
cd backend python -m backtesting.engine --strategy market_making --days 30Metrics calculated:
- Total return and Sharpe ratio
- Maximum drawdown
- Brier score (prediction accuracy)
- Win rate and profit factor
Important Considerations:
- US residents should wait for the CFTC-regulated Polymarket US platform
- Do not use VPN to access global Polymarket from restricted jurisdictions
- Automated trading IS allowed on Polymarket (official SDK provided)
- Consult a tax professional for your jurisdiction's reporting requirements
- This software is provided as-is for educational purposes
cd backend pytest tests/ -vcd backend mypy app/# Backend black app/ isort app/ # Frontend npm run lintMIT License - see LICENSE for details.
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
- GitHub Issues: Report bugs or request features
- Documentation: Check the
algo.mdfile for detailed algorithm explanations
Built with ❤️ for the Polymarket trading community