Skip to content

OrderBookTrade/Prediction_Market_MarketMaker_Tools

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Prediction Market Market-Making Tools

A Python toolkit for automated market-making on Polymarket, a decentralised binary-outcome prediction market built on Polygon.

Features

Module Description
order_book Local CLOB mirror with bid/ask depth, spread, and own-order tracking
pricing Avellaneda-Stoikov inventory-adjusted quotes + simple fixed-spread fallback
inventory Position accounting, average entry price, realised/unrealised P&L
risk Pre-trade and post-trade risk checks (position limits, daily loss cap)
client Async facade over the Polymarket CLOB REST API
market_maker Main event loop that ties all modules together

Architecture

┌──────────────────────────────────────────────────────────────────┐
│                         MarketMaker                              │
│  ┌──────────────┐   ┌──────────────┐   ┌─────────────────────┐  │
│  │  OrderBook   │   │   Pricing    │   │   InventoryTracker  │  │
│  │  (per token) │   │  (A-S model) │   │   (all positions)   │  │
│  └──────┬───────┘   └──────┬───────┘   └──────────┬──────────┘  │
│         │                  │                       │             │
│         └──────────────────▼───────────────────────▼─────────┐  │
│                         RiskManager                           │  │
│                  (pre/post-trade checks)                      │  │
│                              │                                │  │
│                              ▼                                │  │
│                     PolymarketClient                          │  │
│               (async CLOB API wrapper)                        │  │
└──────────────────────────────────────────────────────────────────┘

Pricing model — Avellaneda-Stoikov

The bot uses the Avellaneda-Stoikov (2008) stochastic-control model:

reservation_price = mid − q · γ · σ² · T
optimal_spread    = γ · σ² · T + (2/γ) · ln(1 + γ/κ)

where:

  • q — signed inventory (shares long)
  • γ — risk-aversion coefficient (controls how aggressively inventory is unwound)
  • σ — price volatility
  • T — time horizon
  • κ — order-arrival intensity

As inventory grows long the reservation price falls, widening the ask and tightening the bid to attract sellers. The reverse holds for a short inventory.


Installation

Requirements: Python 3.10+

git clone <this-repo>
cd Prediction_Market_MarketMaker_Tools
pip install -e ".[dev]"

Credentials

cp .env.example .env
# fill in POLYMARKET_API_KEY, POLYMARKET_API_SECRET,
# POLYMARKET_API_PASSPHRASE, and POLYMARKET_PRIVATE_KEY

Obtain API credentials from Polymarket's API portal and generate a CLOB API key using your EVM wallet's private key.


Quick Start

# Dry run (no real orders placed)
python examples/basic_mm.py \
  --token-id   0xYOUR_TOKEN_ID \
  --condition-id 0xYOUR_CONDITION_ID \
  --order-size 10 \
  --interval   15 \
  --dry-run

# Live trading
python examples/basic_mm.py \
  --token-id   0xYOUR_TOKEN_ID \
  --condition-id 0xYOUR_CONDITION_ID \
  --order-size 10 \
  --interval   15 \
  --gamma      0.1 \
  --sigma      0.05 \
  --max-position 200 \
  --max-daily-loss 100

Usage as a Library

import asyncio
from pm_mm import MarketMaker
from pm_mm.client import PolymarketClient, PolymarketCredentials
from pm_mm.market_maker import MarketConfig, MarketMakerConfig
from pm_mm.risk import RiskLimits

config = MarketMakerConfig(
    markets=[
        MarketConfig(
            token_id="0x...",
            condition_id="0x...",
            order_size=10.0,
            quote_interval_secs=15.0,
        )
    ],
    risk_limits=RiskLimits(
        max_position_shares=500,
        max_position_usd=500,
        max_daily_loss_usd=200,
    ),
    pricing_gamma=0.1,
    pricing_sigma=0.05,
    dry_run=False,
)

async def main():
    creds = PolymarketCredentials.from_env()
    async with PolymarketClient(creds) as client:
        mm = MarketMaker(config, client)
        await mm.run()

asyncio.run(main())

Using individual components

from pm_mm.order_book import OrderBook, Side
from pm_mm.pricing import AvellanedaStoikov, FixedSpread
from pm_mm.inventory import InventoryTracker, Fill
from pm_mm.risk import RiskManager, RiskLimits

# Order book
book = OrderBook(token_id="0x...")
book.update_snapshot(bids=[(0.50, 100)], asks=[(0.52, 100)])
print(book.mid_price)   # 0.51
print(book.spread_pct)  # ~0.039

# Pricing
model = AvellanedaStoikov(gamma=0.1, sigma=0.05)
quote = model.quote(mid=0.51, inventory=50)
print(quote.bid, quote.ask)

# Fixed-spread fallback
fs = FixedSpread(half_spread=0.02)
quote = fs.quote(mid=0.51)

# Inventory tracking
tracker = InventoryTracker()
tracker.record_fill(Fill("order-1", "0x...", "BUY", price=0.50, shares=100))
pos = tracker.position("0x...")
print(pos.unrealised_pnl(mark_price=0.60))  # 10.0

# Risk management
rm = RiskManager(limits=RiskLimits(max_daily_loss_usd=50), inventory=tracker)
rm.check_daily_loss()   # raises RiskLimitBreached if over limit

Configuration Reference

All parameters can be set via .env or passed programmatically.

Variable Default Description
POLYMARKET_API_KEY CLOB API key
POLYMARKET_API_SECRET CLOB API secret
POLYMARKET_API_PASSPHRASE CLOB API passphrase
POLYMARKET_PRIVATE_KEY EVM wallet private key (no 0x prefix)
CLOB_HOST https://clob.polymarket.com CLOB endpoint
MAX_POSITION_SHARES 1000 Max shares per side per market
MAX_POSITION_USD 500 Max USD notional per market
MAX_DAILY_LOSS_USD 200 Daily loss hard stop
MIN_SPREAD_PCT 0.02 Minimum bid-ask spread (2%)
RISK_AVERSION 0.1 A-S gamma parameter
VOLATILITY 0.05 A-S sigma parameter
ORDER_SIZE_SHARES 10 Default order size

Risk Controls

The RiskManager enforces the following checks before and after each quote cycle:

  • Position size — won't place an order that would push shares beyond max_position_shares
  • Notional exposure — won't exceed max_position_usd per market
  • Daily loss cap — halts the bot and cancels all orders if max_daily_loss_usd is breached
  • Spread floor — won't quote spreads narrower than min_spread_pct
  • Order size cap — single-order size is capped at max_order_size_shares

On a hard halt, the bot issues cancel_all_orders() before exiting.

Warning: This is experimental software. Use --dry-run to test your configuration before committing real capital. Prediction markets carry unique risks including resolution uncertainty and illiquidity.


Development

# Run tests
pytest

# Lint
ruff check src tests

# Type check
mypy src

Project Structure

Prediction_Market_MarketMaker_Tools/
├── src/pm_mm/
│   ├── __init__.py
│   ├── order_book.py      # local CLOB mirror
│   ├── pricing.py         # Avellaneda-Stoikov + fixed-spread models
│   ├── inventory.py       # position & P&L tracking
│   ├── risk.py            # risk checks and limits
│   ├── client.py          # async Polymarket CLOB client
│   └── market_maker.py    # main loop
├── tests/
│   ├── test_order_book.py
│   ├── test_pricing.py
│   ├── test_inventory.py
│   └── test_risk.py
├── examples/
│   └── basic_mm.py
├── .env.example
├── pyproject.toml
└── README.md

References

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages