Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.predexon.com/llms.txt

Use this file to discover all available pages before exploring further.

Orderbook replay is the gold standard for backtesting, but it’s also the heaviest to iterate on. For first-pass strategy ideas, candles are much cheaper to crunch — and you can reconcile against the trade tape afterward to confirm that what your candle-based strategy “did” was actually achievable. This page covers the candle-first workflow and how to validate it against ground truth.

Two complementary endpoints

EndpointGranularityUse for
/v2/polymarket/candlesticks/{condition_id}1m, 5m, 15m, 1h, 4h, 1d (auto-fit)Fast pattern search, indicator-based strategies
/v2/polymarket/tradesPer-fillReconciliation, exact-fill simulation, VWAP checks
Both are free and unlimited.

Pass 1 — fast candle-driven backtest

Pull condition-level candles and run your strategy in pandas. This is fast enough to grid-search parameters.
import requests, pandas as pd

API_KEY = "YOUR_API_KEY"
BASE = "https://api.predexon.com"
HEADERS = {"x-api-key": API_KEY}

CONDITION_ID = "0x4c57..."

candles = requests.get(
    f"{BASE}/v2/polymarket/candlesticks/{CONDITION_ID}",
    headers=HEADERS,
    params={"interval": 60, "start_time": 1736294400, "end_time": 1736380800},
).json()

df = pd.DataFrame(candles)
df["sma_20"] = df["close"].rolling(20).mean()

# trivial example: long the YES side when close > 20-period SMA
df["signal"] = (df["close"] > df["sma_20"]).astype(int)
df["ret"] = df["close"].pct_change().shift(-1)
df["pnl"] = df["signal"] * df["ret"]
print(f"hypothetical PnL: {df['pnl'].sum():.4f}")
Candles use seconds for start_time / end_time. The orderbook and trades endpoints sometimes use milliseconds — check each endpoint’s reference page.
This gets you a quick read on whether the signal has any edge at all. But the close price is a mid — it doesn’t tell you whether you’d have actually been filled there.

Pass 2 — reconcile against the trade tape

For each candle bar where your strategy triggered, ask the trades endpoint what actually traded in that bar. Replace candle close with VWAP of executed trades, or check that there was enough volume to support your hypothetical size.
def trades_in_bar(token_id, bar_start_sec, bar_end_sec):
    return requests.get(
        f"{BASE}/v2/polymarket/trades",
        headers=HEADERS,
        params={
            "token_id": token_id,
            "start_time": bar_start_sec,
            "end_time": bar_end_sec,
            "limit": 500,
        },
    ).json()

def realized_vwap(trades):
    if not trades:
        return None
    notional = sum(float(t["price"]) * float(t["size"]) for t in trades)
    volume   = sum(float(t["size"]) for t in trades)
    return notional / volume if volume else None
Three checks worth running:
  1. Was there volume? If sum(sizes) < your_target_size, your strategy couldn’t have moved that much money without walking the book.
  2. Was the candle close achievable? Compare candle close to the realized VWAP. Large divergences mean the close was a low-volume tick — not a price you could trade at.
  3. Did your direction get hit? Filter trades by side. If your signal said “buy” but every executed trade in the bar was a sell, the book was offered down — you’d be paying through the spread.

Pass 3 — fall back to orderbook replay for the edge cases

Once you’ve reconciled against trades, you’ll find a handful of bars where:
  • Trades volume was thin
  • Realized VWAP diverged from candle close
  • Your size was a big chunk of the bar’s volume
For those bars, drop to orderbook replay and simulate the fill against the actual book. This gives you a much more realistic PnL than candle-only backtesting, without paying the orderbook-replay cost across your entire dataset.

A note on tokens vs conditions

  • Candles by condition_id give you the market-level OHLCV (usually the Yes side by convention).
  • Candles by token_id (/candlesticks/token/{token_id}) let you backtest either outcome independently. Use this if your strategy trades both sides.
  • Trades and orderbook are always per-token. Make sure all three are aligned to the same outcome when reconciling.