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 Now

John Lee
Published: April 11, 2026
Updated: April 11, 2026
11 min read