A mean-reversion trading bot for Polymarket prediction markets. Buys after sharp price drops, exits on recovery. Tested across 280 live trades and 6,225 backtested trades.
Live Trading (March 28 – April 22, 2026)
| Metric | Value |
|---|---|
| Trades | 280 |
| Win Rate | 80.4% |
| Win/Loss Ratio | 2.6x |
| Avg Hold (winners) | 7.3 hours |
| Position Sizes | $1-$5 per trade (evolved during testing) |
Win rate is consistent across all position sizes (79-81%). See docs/PERFORMANCE.md for the full breakdown by size, category, and hold time.
Backtest (30-day dataset, 9,500 markets)
| Metric | Value |
|---|---|
| Trades | 6,225 |
| Win Rate | 75% |
| Avg Bounce (after >20% crash) | +6.6% in 15 min |
| Best Categories | Crypto ($0.030/trade), Sports ($0.027/trade) |
Prediction markets overreact to bad news. When a market drops >15% in under 4 hours, the price recovers to 90% of its pre-crash level 78% of the time. This bot detects these crashes and trades the recovery.
This is a well-documented phenomenon in prediction markets — unlike traditional financial markets, prediction market prices are bounded between $0 and $1, which creates a natural mean-reversion force.
polymarket-crash-bot/
├── src/
│ ├── crash_monitor.py # Main bot — crash detection + position management
│ ├── clob_executor.py # Polymarket CLOB order execution
│ └── config.py # All parameters (documented)
├── data/
│ └── sample_backtest.db # 1-day sample of market_universe data
├── docs/
│ ├── SETUP.md # Step-by-step setup guide
│ ├── PARAMETERS.md # Every parameter explained with data
│ ├── METHODOLOGY.md # How the strategy works (with math)
│ └── PERFORMANCE.md # Full performance breakdown
├── backtest/
│ ├── backtest_notebook.ipynb # Interactive Jupyter backtest
│ └── run_backtest.py # CLI backtest tool
├── requirements.txt
└── README.md
-
Get Polymarket API credentials (free):
- Create a Polymarket account
- Fund with USDC on Polygon
- Export your private key
-
Install:
pip install -r requirements.txt cp config.example.py config.py # Edit config.py with your credentials -
Run backtest first (no money needed):
python run_backtest.py --days 30
-
Start paper trading:
python crash_monitor.py --paper
-
Go live (when you're comfortable):
python crash_monitor.py --live --size 1.0
All parameters are configurable and documented with the data behind each choice:
| Parameter | Default | Why |
|---|---|---|
CRASH_THRESHOLD |
15% | Crashes >15% have 80.4% recovery rate in live data |
RECOVERY_TARGET |
90% | Exit at 90% of pre-crash high — captures most of the bounce |
MAX_HOLD_H |
12 hours | Winners resolve in 7.3h avg. 12h captures 90%+ of winners |
MAX_ENTRY_PRICE |
$0.30 | Best WR in $0.00-$0.20 range (81%), solid in $0.20-$0.30 (76%) |
POSITION_SIZE |
$1.00 | Start small. Scale after verifying your edge |
SKIP_CATEGORIES |
Weather | Economics, sports, crypto, politics all profitable in live data |
- Kill switch: Auto-pauses if win rate drops below 55% (after 20+ trades)
- Max daily loss: $10 hard ceiling
- Position limit: 45 concurrent positions max
- Cash reserve: Never deploys below $20 USDC
- FOK exits: Fill-or-kill sell orders — no partial fill dust
- This is a backtest + 280 live trades, not a guarantee. Past performance does not predict future results.
- Liquidity matters. Low-liquidity markets may not fill your orders. The bot handles this with FOK orders, but you may miss some entries.
- Prediction markets can go to zero. If you hold YES on a market that resolves NO, you lose 100% of that position. The 12-hour timeout limits this exposure.
- 22% of trades are timeout losses. Not every crash recovers. The edge comes from wins being 2.6x larger than losses on average.
- This strategy works on Polymarket specifically. The mean-reversion pattern is strongest in prediction markets with binary outcomes.
The backtest notebook lets you:
- Load the data and see every trade
- Change any parameter and re-run
- Filter by category, time period, or entry price
- See the exact entry/exit for every trade
Don't trust the numbers — verify them yourself. That's why the data is included.
The included sample is 1 day of data. For the full 30-day dataset (9.5M price points across 9,500 markets):
Personal use only. Do not redistribute.