Build a Polymarket mean reversion bot in Python using price history, z-scores, order-book data, execution controls, and production risk management.
Introduction
A Polymarket mean reversion strategy is based on a simple quantitative hypothesis: when an outcome-token price moves unusually far from its recent statistical range, it may eventually move back toward its local mean.
The difficult part is not calculating a moving average.
The difficult part is determining whether the deviation is actually temporary—or whether new information has permanently changed the market's fair probability.
For a trading bot, that means the strategy needs three separate components:
- A statistical signal.
- An executable market-data layer.
- An execution and risk-management system.
Polymarket's current API exposes order-book snapshots and historical price data, making it possible to build the research layer directly from market data. ([Polymarket Documentation][1])
About the Author
Bo$onaX
I write about Polymarket trading bots, prediction-market infrastructure, algorithmic trading, Python automation, Web3 development, and quantitative strategies.
Contact:
Github: github.com/n9xdev/poly-alpha-lab
Telegram: t.me/bosonax
Youtube: youtube.com/@bosonax
X: x.com/xxniiinxx
Gmail: mailto:dylandevera91928@gmail.com
What You'll Learn
- How mean reversion applies to prediction-market prices
- How to calculate a rolling z-score
- How to filter false signals
- How to incorporate the CLOB order book
- How to structure a Python bot
- Why fees, spread, liquidity and adverse selection matter
- How to backtest and paper trade the strategy
1. The Mean-Reversion Model
Let (P_t) represent the price of an outcome token.
Calculate a rolling mean:
{
mu_t = SMA(P_{t-n+1},...,P_t)
}
and rolling standard deviation:
{
sigma_t = Std(P_{t-n+1},...,P_t)
}
Then calculate:
{
Z_t = \frac{P_t-\mu_t}{\sigma_t}
}
A basic strategy might define:
- Z < -2: unusually low price → investigate a long
- Z > +2: unusually high price → investigate an exit or short-side opportunity
- Z near 0: price has returned toward its local mean
The important word is investigate.
A z-score is a signal, not proof of mispricing.
A breaking-news event can legitimately move a token several standard deviations away from its previous distribution.
2. Architecture
A production implementation should separate research from execution:
flowchart LR
A[Market Discovery] --> B[Historical / Live Data]
B --> C[Feature Engine]
C --> D[Mean Reversion Signal]
D --> E[Risk Manager]
E --> F[Execution Engine]
F --> G[Polymarket CLOB]
G --> H[Order / Fill State]
H --> I[Monitoring]
This separation is important because changing the strategy should not require rewriting authentication, order management, or portfolio accounting.
Polymarket's official Python SDK is currently available as polymarket-client; Polymarket describes it as a unified Python SDK and currently labels the API beta. ([GitHub][2])
3. Getting Historical Prices
Polymarket documents a /prices-history endpoint for retrieving historical market prices, with supported intervals including 1m, 1h, 1d, and others. ([Polymarket Documentation][3])
For research, your data pipeline should look approximately like:
import requests
import pandas as pd
def get_price_history(token_id: str):
response = requests.get(
"https://clob.polymarket.com/prices-history",
params={
"market": token_id,
"interval": "1h",
"fidelity": 1,
},
timeout=10,
)
response.raise_for_status()
history = response.json()["history"]
df = pd.DataFrame(history)
df["timestamp"] = pd.to_datetime(df["t"], unit="s")
df["price"] = df["p"].astype(float)
return df
This is research code, not a complete live trading engine.
4. Calculate the Signal
A compact implementation is:
def mean_reversion_signal(
prices,
window=20,
entry_z=2.0,
exit_z=0.5,
):
mean = prices.rolling(window).mean()
std = prices.rolling(window).std()
z = (prices - mean) / std
latest = z.iloc[-1]
if latest <= -entry_z:
return "LONG", latest
if abs(latest) <= exit_z:
return "EXIT", latest
return "HOLD", latest
But a production bot should not trade solely because z <= -2.
Add filters such as:
- minimum order-book depth
- maximum spread
- minimum recent volume
- stale-data detection
- market status
- volatility regime
- time-to-resolution
- external information events
5. The Order Book Changes Everything
A model may calculate a fair entry at $0.48, while the actual ask is $0.51.
That difference is your execution problem.
Polymarket's CLOB order-book endpoint returns bids, asks, last trade price, minimum order size and tick size for a token. ([Polymarket Documentation][1])
For example:
Model fair value: $0.50
Best bid: $0.46
Best ask: $0.52
Spread: $0.06
A naive strategy sees $0.46 and thinks the token is cheap.
An execution-aware strategy asks:
Can I actually acquire enough inventory at a price that leaves positive expected value?
That distinction separates a backtest from a trading system.
6. A Better Entry Rule
Instead of:
Z-score < -2 → BUY
use something closer to:
Z-score < -2
AND spread < maximum_spread
AND liquidity > minimum_liquidity
AND data_age < maximum_age
AND market_is_tradeable
AND expected_edge > estimated_cost
Conceptually:
$$
ExpectedEdge =
FairValue - ExecutablePrice
- SpreadCost
- FeeCost
- Slippage
- ModelUncertainty $$
Only trade when the remaining edge is sufficiently large.
Polymarket currently charges taker fees on certain markets while makers are not charged fees; fee parameters vary by market and can be queried from market information. ([Polymarket Documentation][4])
Therefore, a mean-reversion model that ignores execution costs can produce attractive but completely artificial signals.
7. Production Failure Modes
1. Trading against a regime change
A price can move far from its historical mean because the underlying probability genuinely changed.
2. Using stale prices
A stale observation can generate a perfect-looking z-score that no longer exists in the live book.
3. Ignoring spread
Mid-price reversion does not necessarily equal executable reversion.
4. Overfitting
Changing window=20 to window=17 because it improves historical results is classic parameter overfitting.
5. Ignoring resolution
A prediction market approaching resolution can behave fundamentally differently from one with substantial time remaining.
6. Treating every market identically
Political, sports, crypto, economic and other markets can have very different liquidity and information dynamics.
8. Risk Management
The strategy should have hard limits independent of the signal engine.
For example:
MAX_POSITION = 100
MAX_ORDER_SIZE = 10
MAX_SPREAD = 0.03
def risk_check(position, order_size, spread):
if abs(position + order_size) > MAX_POSITION:
return False
if order_size > MAX_ORDER_SIZE:
return False
if spread > MAX_SPREAD:
return False
return True
Real systems should additionally track:
- per-market exposure
- portfolio exposure
- correlated positions
- daily loss limits
- order rejection rates
- outstanding orders
- partial fills
- API failures
- emergency shutdown state
9. Testing Strategy
Do not start with real capital.
Use three stages:
Backtest → Paper Trading → Limited Live Trading
The backtest should simulate executable prices rather than simply using historical midpoints.
A useful simulator should model:
- spread
- available depth
- partial fills
- fees
- order latency
- cancellations
- position limits
- resolution
- rejected orders
Then run the strategy on unseen data.
The most important test is not:
"Did the historical strategy make money?"
It is:
"Does the strategy remain positive after realistic execution assumptions?"
10. Monitoring
A live bot should expose metrics such as:
signal_count
trade_count
fill_rate
average_entry_price
average_exit_price
position_size
realized_pnl
unrealized_pnl
average_spread
data_age
order_rejections
api_errors
Log every signal and every execution decision.
When a strategy loses money, you want to determine whether the problem was:
model → data → execution → liquidity → risk → infrastructure
without guessing.
11. Advanced Improvements
A basic z-score is only the starting point.
More sophisticated systems can use:
Volatility-adjusted thresholds
Increase the entry threshold when volatility expands.
Exponentially weighted means
Give recent observations greater importance than older ones.
Regime detection
Separate stable markets from event-driven markets.
Order-book imbalance
Combine statistical deviation with bid/ask depth.
Cross-market signals
Compare related Polymarket contracts or external reference markets.
Adaptive parameters
Estimate the appropriate lookback window from recent market behavior rather than fixing it permanently.
The strongest architecture is therefore not simply a "z-score bot."
It is a conditional mean-reversion system that asks whether the deviation is statistically unusual and economically tradeable.
Frequently Asked Questions
What is Polymarket mean reversion?
It is a trading approach that attempts to identify outcome-token prices that have moved unusually far from their recent statistical mean and may subsequently move back toward it.
Is mean reversion profitable on Polymarket?
There is no guaranteed profitability. Market selection, execution costs, liquidity, model error and information events can overwhelm a statistical signal.
What indicator should I use?
A rolling z-score is a useful starting point, but it should be combined with market microstructure and risk filters.
Should I trade every ±2 z-score event?
No. A large deviation may represent new information rather than temporary dislocation.
Can Python be used to build the bot?
Yes. Polymarket currently provides an official Python SDK, although its documentation currently identifies the SDK as beta. ([GitHub][2])
Conclusion
A useful Polymarket mean reversion bot is not simply:
price < moving average → buy
The real system is:
Market Data
↓
Statistical Model
↓
Regime Filter
↓
Order-Book Validation
↓
Expected-Value Check
↓
Risk Manager
↓
Execution
↓
Fill Reconciliation
↓
Monitoring
The statistical signal tells you where a potential opportunity exists. The order book tells you whether you can actually trade it. Risk management determines whether one bad assumption can damage the entire portfolio.
That is the difference between a Python strategy script and production trading infrastructure.
Trading-risk disclaimer: This article is for educational and software-development purposes only. Automated prediction-market trading involves financial risk. No strategy, model, backtest, or implementation guarantees profits.
Related Articles / Internal Linking
| Article | Suggested anchor | Why link it |
|---|---|---|
| How to Build a Polymarket Trading Bot in Python | build a Polymarket trading bot | Broad implementation foundation |
| Build a Real-Time Polymarket Order Book Monitor | real-time Polymarket order book | Supports execution-aware signals |
| Polymarket Market Discovery | automated market discovery | Explains market selection |
| Polymarket Paper Trading Bot | paper trading system | Natural next step before deployment |
| Polymarket CLOB Explained | Polymarket CLOB | Explains execution infrastructure |
| Polymarket Limit Orders vs Market Orders | Polymarket order execution | Connects signals to fills |
| Polymarket API Explained for Developers | Polymarket API | API implementation reference |
Useful Resources
- Official Polymarket: Polymarket — the live prediction-market platform.
- Official Documentation: Polymarket Developer Documentation — primary technical authority.
- Order Book API: Get Order Book — CLOB order-book structure and fields.
- Price History API: Get Prices History — useful for strategy research.
- Fees: Polymarket Fees Documentation — important when calculating executable edge.
- Official Python SDK: Polymarket py-sdk — current unified Python SDK.
- Official developer GitHub: Polymarket GitHub — official open-source developer resources.
- Medium: Building a 15-Minute Mean Reversion Strategy for Polymarket Trading Bot — useful third-party comparison; verify implementation details against official documentation.
- DEV.to: Polymarket CLOB: How the Order Book and Trading API Work — useful third-party implementation perspective.
- YouTube:
Polymarket API Tutorial — Build a Python Trading Bot from Zero
— visual implementation reference, not an authoritative API source.
Top comments (0)