PolymarketPolymarketDeveloper18 min read2025-12-11

Polymarket Python Tutorial: Complete Developer Guide 2025

AL - Founder of PolyTrack, Polymarket trader & analyst

AL

Founder of PolyTrack, Polymarket trader & analyst

Polymarket Python Tutorial: Complete Developer Guide 2025 - Developer Guide for Polymarket Traders | PolyTrack Blog

Python is the most popular language for building Polymarket trading bots and analytics tools. This comprehensive guide covers everything from initial setup to placing your first trade using the official py-clob-client library. Whether you're building a market maker, arbitrage bot, or portfolio tracker, this tutorial has you covered.

Getting Started: Installation and Setup

Install the Official Python Client

# Core dependencies
pip install py-clob-client
pip install web3==6.14.0  # Pin version to avoid dependency conflicts
pip install python-dotenv

# Optional: Better async support
pip install aiopolymarket

# Optional: Retry logic
pip install tenacity

Version Note

Pin web3==6.14.0 to avoid dependency conflicts with eth-typing. The latest py-clob-client version is v0.29.0 (released December 2025) with HTTP2 and Keep Alive support.

Requirements

  • Python: 3.9.10 or higher
  • Wallet: Ethereum-compatible wallet with USDC on Polygon
  • Private Key: Exported from Polymarket (for authenticated trading)

Authentication: Two Methods

Polymarket uses two authentication levels:

L1 Authentication (Private Key)

Uses your wallet's private key to sign EIP-712 messages. This proves ownership without custodial control.

L2 Authentication (API Key)

Derived from L1 authentication, uses HMAC-SHA256 signatures for faster request signing. Requests expire after 30 seconds.

Step 1: Export Your Private Key

  1. Log in to Polymarket.com
  2. Navigate to "Cash" in the menu
  3. Click the 3-dot menu
  4. Select "Export Private Key"
  5. Remove the '0x' prefix before storing

Step 2: Create Environment File

# keys.env - NEVER commit this file to git!

# Your private key (without 0x prefix)
PK=your_private_key_here

# These will be generated - leave blank initially
API_KEY=
API_SECRET=
API_PASSPHRASE=

# For browser/Magic wallets, add funder address
FUNDER_ADDRESS=

Step 3: Generate API Credentials

import os
from py_clob_client.client import ClobClient
from dotenv import load_dotenv

load_dotenv('keys.env')

def generate_api_credentials():
    host = "https://clob.polymarket.com"
    key = os.getenv("PK")
    chain_id = 137  # Polygon Mainnet

    if not key:
        raise ValueError("Private key not found. Set PK in keys.env")

    # Initialize client with private key
    client = ClobClient(host, key=key, chain_id=chain_id)

    # Create or derive API credentials
    try:
        api_creds = client.create_or_derive_api_creds()
        print(f"API Key: {api_creds.api_key}")
        print(f"Secret: {api_creds.api_secret}")
        print(f"Passphrase: {api_creds.api_passphrase}")
        return api_creds
    except Exception as e:
        print(f"Error: {e}")
        return None

if __name__ == "__main__":
    generate_api_credentials()

Save Your Credentials

Add the generated API Key, Secret, and Passphrase to your keys.env file. You only need to do this once - credentials are deterministically derived from your private key.

Client Initialization Patterns

Read-Only Access (No Authentication)

from py_clob_client.client import ClobClient

# Level 0 - public data only
client = ClobClient("https://clob.polymarket.com")

# Test connection
ok = client.get_ok()
server_time = client.get_server_time()
print(f"Connected: {ok}, Server Time: {server_time}")

Standard EOA Wallet (MetaMask Export)

from py_clob_client.client import ClobClient
import os
from dotenv import load_dotenv

load_dotenv('keys.env')

HOST = "https://clob.polymarket.com"
CHAIN_ID = 137
PRIVATE_KEY = os.getenv("PK")

# signature_type=0 for standard EOA
client = ClobClient(
    HOST,
    key=PRIVATE_KEY,
    chain_id=CHAIN_ID,
    signature_type=0
)

# Set API credentials for L2 authentication
client.set_api_creds(client.create_or_derive_api_creds())

Email/Magic Wallet

# signature_type=1 for email/Magic wallet
client = ClobClient(
    HOST,
    key=PRIVATE_KEY,
    chain_id=CHAIN_ID,
    signature_type=1,  # POLY_PROXY
    funder=os.getenv("FUNDER_ADDRESS")  # Proxy wallet address
)
client.set_api_creds(client.create_or_derive_api_creds())

Browser Wallet (Coinbase Wallet, etc.)

# signature_type=2 for browser wallets
client = ClobClient(
    HOST,
    key=PRIVATE_KEY,
    chain_id=CHAIN_ID,
    signature_type=2,  # GNOSIS_SAFE
    funder=os.getenv("FUNDER_ADDRESS")
)
client.set_api_creds(client.create_or_derive_api_creds())

See What Whales Are Trading Right Now

Get instant alerts when top traders make moves. Track P&L, win rates, and copy winning strategies.

Track Whales Free

Free forever. No credit card required.

Fetching Market Data

Get All Markets

from py_clob_client.client import ClobClient

client = ClobClient("https://clob.polymarket.com")

# Get first page of markets
markets = client.get_markets()
print(f"Found {len(markets['data'])} markets")

# Print first market
first = markets['data'][0]
print(f"Market: {first.get('question')}")
print(f"Condition ID: {first.get('condition_id')}")

Fetch All Markets with Pagination

import csv
import json
from py_clob_client.client import ClobClient

client = ClobClient("https://clob.polymarket.com")

markets_list = []
next_cursor = None

while True:
    try:
        if next_cursor is None:
            response = client.get_markets()
        else:
            response = client.get_markets(next_cursor=next_cursor)

        if 'data' not in response:
            break

        markets_list.extend(response['data'])
        next_cursor = response.get("next_cursor")
        print(f"Fetched {len(markets_list)} markets...")

        if not next_cursor:
            break

    except Exception as e:
        print(f"Error: {e}")
        break

print(f"Total markets: {len(markets_list)}")

# Export to CSV
with open("markets.csv", 'w', newline='') as f:
    if markets_list:
        writer = csv.DictWriter(f, fieldnames=markets_list[0].keys())
        writer.writeheader()
        writer.writerows(markets_list)

Get Prices and Order Book

from py_clob_client.clob_types import BookParams

token_id = "YOUR_TOKEN_ID_HERE"

# Get midpoint price
mid = client.get_midpoint(token_id)
print(f"Midpoint: $" + str(mid))

# Get best bid/ask
bid_price = client.get_price(token_id, side="BUY")
ask_price = client.get_price(token_id, side="SELL")
print(f"Bid: $" + str(bid_price) + ", Ask: $" + str(ask_price))

# Get full order book
book = client.get_order_book(token_id)
print(f"Bids: {book['bids'][:3]}")
print(f"Asks: {book['asks'][:3]}")

# Get multiple order books at once
books = client.get_order_books([
    BookParams(token_id=token_id),
    BookParams(token_id="ANOTHER_TOKEN_ID")
])

# Get last trade price
last_price = client.get_last_trade_price(token_id)
print(f"Last Trade: $" + str(last_price))

Placing Orders

Market Order (Dollar Amount)

from py_clob_client.clob_types import MarketOrderArgs, OrderType
from py_clob_client.order_builder.constants import BUY, SELL

# Buy $25 worth of shares at market price
market_order = MarketOrderArgs(
    token_id="YOUR_TOKEN_ID",
    amount=25.0,          # Dollar amount
    side=BUY,             # BUY or SELL
    order_type=OrderType.FOK  # Fill-or-Kill
)

# Sign and submit
signed_order = client.create_market_order(market_order)
response = client.post_order(signed_order, OrderType.FOK)
print(f"Order response: {response}")

Limit Order (Price and Quantity)

from py_clob_client.clob_types import OrderArgs, OrderType
from py_clob_client.order_builder.constants import BUY, SELL

# Buy 100 shares at $0.45 each
limit_order = OrderArgs(
    token_id="YOUR_TOKEN_ID",
    price=0.45,           # Price per share (0.00 - 1.00)
    size=100.0,           # Number of shares
    side=BUY
)

# Sign and submit as Good Till Cancelled
signed_order = client.create_order(limit_order)
response = client.post_order(signed_order, OrderType.GTC)
print(f"Order ID: {response.get('id')}")

Order Types Explained

  • GTC (Good Till Cancelled): Stays open until filled or cancelled
  • FOK (Fill or Kill): Must fill entirely or cancel immediately
  • GTD (Good Till Date): Expires at specified time

Managing Orders and Positions

Get Open Orders

from py_clob_client.clob_types import OpenOrderParams

# Get all open orders
open_orders = client.get_orders(OpenOrderParams())
print(f"Open orders: {len(open_orders)}")

for order in open_orders:
    print(f"  {order['id']}: {order['side']} {order['original_size']} @ {order['price']}")

Cancel Orders

# Cancel specific order
order_id = "YOUR_ORDER_ID"
client.cancel(order_id)

# Cancel all open orders
client.cancel_all()
print("All orders cancelled")

Get Trade History

# Get your trades
trades = client.get_trades()

for trade in trades:
    print(f"Trade: {trade['side']} {trade['size']} @ {trade['price']}")
    print(f"  Status: {trade['status']}")

Error Handling and Rate Limits

Rate Limits

  • Public endpoints: ~100 requests/minute
  • Authenticated endpoints: Higher limits based on trading volume
  • HTTP 429: Rate limit exceeded - implement backoff

Exponential Backoff Pattern

from tenacity import retry, wait_random_exponential, stop_after_attempt

@retry(
    wait=wait_random_exponential(min=1, max=60),
    stop=stop_after_attempt(5)
)
def fetch_with_retry(client, token_id):
    """Fetch data with automatic retry and exponential backoff."""
    return client.get_midpoint(token_id)

# Usage
try:
    price = fetch_with_retry(client, token_id)
except Exception as e:
    print(f"Failed after 5 retries: {e}")

Safe Order Placement

import time

def place_order_safe(client, order_args, max_retries=3):
    """Place order with error handling and retry logic."""
    for attempt in range(max_retries):
        try:
            signed = client.create_order(order_args)
            response = client.post_order(signed, OrderType.GTC)
            return response
        except Exception as e:
            error_str = str(e)

            if "429" in error_str:
                # Rate limited - exponential backoff
                wait_time = 2 ** attempt
                print(f"Rate limited. Waiting {wait_time}s...")
                time.sleep(wait_time)
            elif "insufficient" in error_str.lower():
                # Insufficient funds
                print("Insufficient funds for order")
                return None
            else:
                print(f"Order failed: {e}")
                if attempt == max_retries - 1:
                    return None
                time.sleep(1)

    return None

Complete Trading Bot Example

import os
import time
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import OrderArgs, OrderType, OpenOrderParams
from py_clob_client.order_builder.constants import BUY, SELL
from dotenv import load_dotenv

load_dotenv('keys.env')

class SimplePolymarketBot:
    def __init__(self):
        self.client = ClobClient(
            "https://clob.polymarket.com",
            key=os.getenv("PK"),
            chain_id=137,
            signature_type=1,
            funder=os.getenv("FUNDER_ADDRESS")
        )
        self.client.set_api_creds(self.client.create_or_derive_api_creds())

    def get_market_price(self, token_id):
        """Get current bid/ask spread."""
        try:
            bid = float(self.client.get_price(token_id, side="BUY") or 0)
            ask = float(self.client.get_price(token_id, side="SELL") or 1)
            mid = (bid + ask) / 2
            return {"bid": bid, "ask": ask, "mid": mid, "spread": ask - bid}
        except Exception as e:
            print(f"Error fetching price: {e}")
            return None

    def place_limit_buy(self, token_id, price, size):
        """Place a limit buy order."""
        try:
            order = OrderArgs(
                token_id=token_id,
                price=price,
                size=size,
                side=BUY
            )
            signed = self.client.create_order(order)
            response = self.client.post_order(signed, OrderType.GTC)
            print(f"Buy order placed: {size} @ {price}")
            return response
        except Exception as e:
            print(f"Buy order failed: {e}")
            return None

    def place_limit_sell(self, token_id, price, size):
        """Place a limit sell order."""
        try:
            order = OrderArgs(
                token_id=token_id,
                price=price,
                size=size,
                side=SELL
            )
            signed = self.client.create_order(order)
            response = self.client.post_order(signed, OrderType.GTC)
            print(f"Sell order placed: {size} @ {price}")
            return response
        except Exception as e:
            print(f"Sell order failed: {e}")
            return None

    def cancel_all_orders(self):
        """Cancel all open orders."""
        try:
            self.client.cancel_all()
            print("All orders cancelled")
        except Exception as e:
            print(f"Cancel failed: {e}")

    def run_market_maker(self, token_id, spread=0.02, size=10):
        """Simple market making strategy."""
        print(f"Starting market maker for {token_id}")

        while True:
            try:
                # Cancel existing orders
                self.cancel_all_orders()

                # Get current price
                prices = self.get_market_price(token_id)
                if not prices:
                    time.sleep(5)
                    continue

                mid = prices["mid"]

                # Place orders on both sides
                buy_price = round(mid - spread/2, 2)
                sell_price = round(mid + spread/2, 2)

                self.place_limit_buy(token_id, buy_price, size)
                self.place_limit_sell(token_id, sell_price, size)

                print(f"Orders placed: Buy {buy_price} / Sell {sell_price}")

                # Wait before refresh
                time.sleep(30)

            except KeyboardInterrupt:
                print("Stopping bot...")
                self.cancel_all_orders()
                break
            except Exception as e:
                print(f"Error: {e}")
                time.sleep(10)

if __name__ == "__main__":
    bot = SimplePolymarketBot()
    # bot.run_market_maker("YOUR_TOKEN_ID", spread=0.02, size=10)

Risk Warning

Automated trading carries significant risks. Always test with small amounts first, implement proper risk controls, and never trade more than you can afford to lose. Review common mistakes before deploying.

Alternative Python Libraries

aiopolymarket (Async Client)

# pip install aiopolymarket

from aiopolymarket import GammaClient, MarketNotFoundError, RateLimitError

async with GammaClient() as client:
    try:
        market = await client.get_market("market-id")
        print(f"Market: {market.question}")
    except MarketNotFoundError as e:
        print(f"Market not found: {e.market_id}")
    except RateLimitError:
        print("Rate limit exceeded")

quantpylib (Async SDK)

# Fully asynchronous Polymarket wrapper
# Docs: quantpylib.hangukquant.com/wrappers/polymarket/

from quantpylib.wrappers.polymarket import PolymarketClient

async def main():
    client = PolymarketClient()
    markets = await client.get_markets()
    print(f"Found {len(markets)} markets")

Security Best Practices

  • Never commit keys: Add keys.env and *.env to .gitignore
  • Use environment variables: Load credentials with python-dotenv
  • Rotate credentials: Periodically regenerate API keys
  • Minimize permissions: Only enable trading when needed
  • Monitor activity: Log all API calls and responses
  • Production secrets: Use AWS Secrets Manager, Azure Key Vault, or similar

Resources and Documentation

Official Resources

  • py-clob-client GitHub: github.com/Polymarket/py-clob-client
  • Polymarket Docs: docs.polymarket.com
  • API Authentication: docs.polymarket.com/developers/CLOB/authentication
  • Your First Order: docs.polymarket.com/quickstart/orders/first-order

Example Bots on GitHub

  • poly-maker: github.com/warproxxx/poly-maker - Market making bot
  • Polymarket Agents: github.com/Polymarket/agents - Official AI trading framework
  • Polymarket Spike Bot: github.com/Trust412/Polymarket-spike-bot-v1

Track Your Bot's Performance

PolyTrack provides portfolio tracking, P&L analytics, and whale alerts. Monitor your bot's performance alongside the smartest traders on Polymarket.

Next Steps

Frequently Asked Questions

Run: pip install py-clob-client web3==6.14.0 python-dotenv. Pin web3 to version 6.14.0 to avoid dependency conflicts with eth-typing.

12,400+ TRADERS

Stop Guessing. Start Following Smart Money.

Get instant alerts when whales make $10K+ trades. Track P&L, win rates, and copy winning strategies.

Track Whales FreeNo credit card required