Backtesting

Backtesting Framework for Polymarket with Python

Build a complete backtesting framework for Polymarket prediction markets using Python and PolyHistorical data.

Framework Architecture

A solid backtesting framework for prediction markets needs four components: data fetching, strategy logic, execution simulation, and performance evaluation. Here's how to build each with Python and PolyHistorical.

Step 1: Data Fetcher

import requests
import pandas as pd

class PolyHistoricalClient:
    def __init__(self, api_key):
        self.base = "https://api.polyhistorical.com/v1"
        self.headers = {"X-API-Key": api_key}

    def get_snapshots(self, slug, include_orderbook=True):
        resp = requests.get(
            f"{self.base}/markets/{slug}/snapshots",
            headers=self.headers,
            params={"include_orderbook": str(include_orderbook).lower()}
        )
        return pd.DataFrame(resp.json()["data"])

Step 2: Strategy Interface

class Strategy:
    def on_snapshot(self, snapshot):
        """Return 'buy_up', 'buy_down', 'sell', or None"""
        raise NotImplementedError

class SpreadStrategy(Strategy):
    def __init__(self, threshold=0.06):
        self.threshold = threshold

    def on_snapshot(self, snap):
        spread = float(snap["price_up"]) + float(snap["price_down"]) - 1
        if spread > self.threshold:
            return "buy_up" if float(snap["price_up"]) < 0.5 else "buy_down"
        return None

Step 3: Execution Simulator

def backtest(client, slug, strategy):
    df = client.get_snapshots(slug)
    trades, pnl = [], 0
    position = None

    for _, snap in df.iterrows():
        signal = strategy.on_snapshot(snap)
        if signal and not position:
            position = {"side": signal, "entry": float(snap["price_up"])}
        elif position:
            # Close at resolution
            winner = snap.get("winner")
            if winner:
                payout = 1.0 if position["side"] == f"buy_{winner.lower()}" else 0.0
                pnl += payout - position["entry"]
                trades.append(pnl)
                position = None
    return trades

Step 4: Evaluation

MetricFormulaTarget
Win RateWinning trades / Total trades> 55%
Sharpe RatioMean return / Std deviation> 1.0
Max DrawdownLargest peak-to-trough decline< 20%
Profit FactorGross profit / Gross loss> 1.5

Related Resources