How to Build a Polymarket Trading Bot with Python (2026 API Guide)
Build a Polymarket trading bot using Python and the CLOB API. Covers authentication, market data, order placement, and a basic strategy example.
Polymarket provides three APIs — CLOB for trading, Gamma for market data, and Data for historical snapshots — plus an official Python SDK called py-clob-client. You can build a bot that reads markets, places orders, and monitors positions with around 200 lines of Python. This guide covers the full setup from authentication through a working strategy example.
Polymarket API Architecture
Polymarket's API is split into three separate services. Understanding which one to call for what saves debugging time.
CLOB API (Central Limit Order Book) — This is the trading API. It handles order placement, cancellation, order book queries, and trade history. All buy and sell operations go through here. Base URL: https://clob.polymarket.com
Gamma API — Market metadata. Descriptions, categories, resolution sources, outcome tokens, and market status. Use this to discover markets and understand what you're trading. Base URL: https://gamma-api.polymarket.com
Data API — Historical price data, volume snapshots, and market statistics. Use this for backtesting and analysis. Provides time-series data that the other APIs don't.
Prerequisites
You need:
- Python 3.9 or higher
- An Ethereum wallet with a private key (this wallet interacts with Polymarket's smart contracts on Polygon)
- USDC on Polygon for trading
- A Polymarket account linked to this wallet
If you don't have a Polymarket account yet, follow the account creation guide.
Setting Up the Python SDK
Install the official Polymarket Python client:
pip install py-clob-client
Create your client instance:
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import OrderArgs, OrderType
from py_clob_client.order_builder.constants import BUY, SELL
# Your Polygon wallet private key — NEVER hardcode in production
# Use environment variables or a secrets manager
import os
PRIVATE_KEY = os.environ["POLYMARKET_PRIVATE_KEY"]
CHAIN_ID = 137 # Polygon mainnet
client = ClobClient(
host="https://clob.polymarket.com",
key=PRIVATE_KEY,
chain_id=CHAIN_ID
)
Generate API credentials (required for placing orders):
# First-time setup: create API key credentials
api_creds = client.create_api_key()
# Store these securely — you'll need them for authenticated requests
print(f"API Key: {api_creds.api_key}")
print(f"Secret: {api_creds.api_secret}")
print(f"Passphrase: {api_creds.api_passphrase}")
# Reinitialize client with API credentials
client = ClobClient(
host="https://clob.polymarket.com",
key=PRIVATE_KEY,
chain_id=CHAIN_ID,
creds={
"api_key": api_creds.api_key,
"api_secret": api_creds.api_secret,
"api_passphrase": api_creds.api_passphrase
}
)
Reading Market Data
Fetching Markets from Gamma API
The Gamma API provides market metadata. Use the requests library directly since the SDK focuses on the CLOB:
import requests
def get_active_markets(limit=100):
"""Fetch active markets from the Gamma API."""
url = "https://gamma-api.polymarket.com/markets"
params = {
"closed": "false",
"limit": limit,
"order": "volume24hr",
"ascending": "false"
}
response = requests.get(url, params=params)
return response.json()
markets = get_active_markets()
for market in markets[:5]:
print(f"{market['question']} — Volume: ${market.get('volume', 'N/A')}")
Reading the Order Book
def get_order_book(token_id):
"""Get the current order book for a specific outcome token."""
book = client.get_order_book(token_id)
print("--- BIDS (buyers) ---")
for bid in book.bids[:5]:
print(f" Price: {bid.price} Size: {bid.size}")
print("--- ASKS (sellers) ---")
for ask in book.asks[:5]:
print(f" Price: {ask.price} Size: {ask.size}")
return book
# token_id comes from the Gamma API market data
# Each market has outcome tokens (YES and NO)
Getting the Midpoint Price
def get_midpoint(token_id):
"""Calculate the midpoint price from the order book."""
price = client.get_midpoint(token_id)
return float(price)
Placing Orders
Market Orders
Market orders execute immediately at the best available price:
def place_market_buy(token_id, amount):
"""Buy shares at market price.
Args:
token_id: The outcome token to buy
amount: Dollar amount to spend
"""
order_args = OrderArgs(
price=1.0, # Market orders use price=1.0 for buys
size=amount,
side=BUY,
token_id=token_id
)
signed_order = client.create_order(order_args)
response = client.post_order(signed_order, OrderType.FOK) # Fill-or-Kill
print(f"Order response: {response}")
return response
Limit Orders
Limit orders sit on the book until the price is reached:
def place_limit_buy(token_id, price, size):
"""Place a limit buy order.
Args:
token_id: The outcome token to buy
price: Maximum price per share (0.01 to 0.99)
size: Number of shares to buy
"""
order_args = OrderArgs(
price=price,
size=size,
side=BUY,
token_id=token_id
)
signed_order = client.create_order(order_args)
response = client.post_order(signed_order, OrderType.GTC) # Good-til-Cancelled
print(f"Limit order placed at {price} for {size} shares")
return response
Canceling Orders
def cancel_order(order_id):
"""Cancel an open order."""
response = client.cancel(order_id)
print(f"Cancelled order {order_id}: {response}")
return response
def cancel_all_orders():
"""Cancel all open orders."""
response = client.cancel_all()
print(f"Cancelled all orders: {response}")
return response
Checking Positions and Balances
def get_positions():
"""Get all current positions."""
positions = client.get_positions()
for pos in positions:
print(f"Token: {pos['token_id'][:12]}... Size: {pos['size']} Avg Price: {pos['avg_price']}")
return positions
Basic Strategy Example: Spread Trading
Here's a simple strategy that monitors the spread on a market and places limit orders when the spread exceeds a threshold. This is not a recommendation — it's a structural example showing how to combine the API calls into a loop.
import time
def spread_strategy(token_id, spread_threshold=0.05, order_size=10, check_interval=30):
"""Place orders when the bid-ask spread exceeds a threshold.
If the spread is wide enough, place a limit buy slightly above
the best bid and a limit sell slightly below the best ask.
Args:
token_id: Outcome token to trade
spread_threshold: Minimum spread to trigger orders (e.g., 0.05 = 5 cents)
order_size: Dollar size of each order
check_interval: Seconds between checks
"""
print(f"Starting spread strategy on {token_id[:12]}...")
print(f"Spread threshold: {spread_threshold}, Order size: ${order_size}")
while True:
try:
book = client.get_order_book(token_id)
if not book.bids or not book.asks:
print("Order book empty, skipping...")
time.sleep(check_interval)
continue
best_bid = float(book.bids[0].price)
best_ask = float(book.asks[0].price)
spread = best_ask - best_bid
print(f"Bid: {best_bid:.3f} | Ask: {best_ask:.3f} | Spread: {spread:.3f}")
if spread > spread_threshold:
# Place buy order slightly above best bid
buy_price = round(best_bid + 0.01, 2)
# Place sell order slightly below best ask
sell_price = round(best_ask - 0.01, 2)
print(f"Spread wide enough. Placing buy at {buy_price}, sell at {sell_price}")
# Cancel existing orders first
cancel_all_orders()
# Place new orders
buy_args = OrderArgs(
price=buy_price,
size=order_size,
side=BUY,
token_id=token_id
)
sell_args = OrderArgs(
price=sell_price,
size=order_size,
side=SELL,
token_id=token_id
)
client.post_order(client.create_order(buy_args), OrderType.GTC)
client.post_order(client.create_order(sell_args), OrderType.GTC)
else:
print("Spread too narrow, waiting...")
time.sleep(check_interval)
except Exception as e:
print(f"Error: {e}")
time.sleep(check_interval * 2) # Back off on errors
This is a simplified example. A production-quality spread trading bot needs inventory management, position limits, multiple market support, and much more sophisticated pricing logic.
Safety and Rate Limits
Rate Limits
The Polymarket CLOB API enforces rate limits. As of early 2026:
- Read requests: approximately 100 per 10 seconds
- Write requests (orders): approximately 50 per 10 seconds
- Exceeding limits returns HTTP 429 errors
Build in backoff logic:
import time
def safe_request(func, *args, max_retries=3, **kwargs):
"""Wrapper with retry logic for rate-limited requests."""
for attempt in range(max_retries):
try:
return func(*args, **kwargs)
except Exception as e:
if "429" in str(e):
wait = (attempt + 1) * 5
print(f"Rate limited. Waiting {wait}s...")
time.sleep(wait)
else:
raise
raise Exception(f"Failed after {max_retries} retries")
Error Handling
Common errors to handle:
- Insufficient balance. Check USDC balance before placing orders.
- Invalid token ID. Markets close and tokens become invalid. Always verify market status before trading.
- Nonce errors. If you send multiple transactions quickly, nonce conflicts can occur. Implement sequential order submission or nonce management.
- Network timeouts. Polygon RPC nodes occasionally time out. Use retry logic.
Security Best Practices
Never hardcode your private key. Use environment variables or a dedicated secrets manager.
# Good
key = os.environ["POLYMARKET_PRIVATE_KEY"]
# Bad — never do this
key = "0xabc123..." # Anyone with your code has your funds
Use a dedicated wallet. Create a separate wallet for bot trading. Don't use your main wallet that holds other assets.
Start with tiny amounts. Test with $5-10 orders. Confirm the bot does what you expect before scaling up.
Log everything. Write every order, cancellation, and error to a log file. When something goes wrong (and it will), logs are how you figure out what happened.
import logging
logging.basicConfig(
filename="bot.log",
level=logging.INFO,
format="%(asctime)s %(levelname)s: %(message)s"
)
logging.info(f"Order placed: {order_id} at {price} for {size}")
Set position limits. Never let the bot accumulate more exposure than you're willing to lose.
US vs. Global Access
Polymarket restricts trading for US-based users. The API enforces the same restrictions as the web interface — if your wallet is flagged as US-based, trading endpoints will reject your requests.
Read-only APIs (Gamma and Data) are generally accessible regardless of location and can be used for research and analysis.
If you're outside the US and want to trade programmatically, the APIs above work as described. Always comply with your local regulations regarding prediction market participation.
Going Beyond the Basics
Once you have a working bot, potential next steps:
Backtesting. Use the Data API to download historical price data and test your strategy against past markets before risking real money.
Multi-market strategies. Monitor related markets (e.g., "Will candidate X win the primary?" and "Will candidate X win the general?") for arbitrage or correlation opportunities. See our arbitrage guide for the conceptual framework.
Event-driven trading. Integrate a news API and react to breaking events by adjusting positions in relevant markets.
Open-source reference. The Polymarket/agents repository on GitHub provides a more complete framework for building AI-powered trading agents. Study their architecture if you're building something sophisticated.
The gap between a working script and a profitable bot is large. Most of the work is in strategy development, risk management, and operational reliability, not in the API integration.
If you want automated trading without writing code, PolyCop lets you copy trade profitable wallets for a 0.5% fee per trade. See our PolyCop review for details.
Start Trading on Polymarket
Create Account NowRelated Articles
Bot Comparison
Compare the best Polymarket trading bots in 2026. Side-by-side analysis of PolyCop, Polycool, PolyGun, and PolyTech covering fees, features, and use cases.
PolyCop Review
Honest PolyCop review covering fees, security, performance, and limitations. Find out if this Polymarket copy trading bot is worth using in 2026.
Whale Trackers
Compare Polymarket whale trackers including Polywhaler, PolymarketScan, and PolyTrack. How to find profitable wallets and spot red flags.