Guides

Polymarket order book and data guides

API endpoints, rate limits, authentication, Python workflows, and when to use price history vs order books.

API guides

Workflow guides

Analysis guides

Strategy guides

Frequently asked questions

What resolution does the order book API use?

250ms on every plan, including the free Starter tier. Coarser query grids (1s–1d) are also supported. The capture cadence is uniform — you choose the grid at query time.

Does the API include resolved markets?

Yes. Resolved markets stay queryable with the winning outcome on every row. Prices and books for the full history are available after resolution — nothing is deleted.

What is in a book snapshot?

Full bid/ask ladders — every level, not just the top of book. Each row carries aligned bids, asks, spread, depth, and a timestamp. Prices and metrics come on separate endpoints with the same timestamps.

How does this differ from Polymarket's own /book endpoint?

Polymarket's CLOB /book endpoint serves the live order book at the current moment. PolyOrderbooks captures and stores the complete book state at regular intervals, so you can query the exact book that existed at any point in a market's history.

Can I get the full market lifecycle in one request?

Yes. Omit start_ts and end_ts to get the full lifecycle from market open to resolution. The response includes every 250ms snapshot, which for a 5-minute market is approximately 1,200 snapshots.

What is the maximum time range I can query?

The maximum range depends on your plan. Starter gives 3 days, paid plans give 30–120 days. Within that window, you can query any contiguous range. Large ranges return more data and count more against your daily limit.

What happens if I hit the rate limit?

The API returns a 429 status. Pause and retry with exponential backoff. Your daily counter resets at UTC midnight. Rate limits are per API key — creating additional Starter accounts does not bypass them.

How do rate limits compare to Polymarket's own API?

Polymarket's CLOB /prices-history allows ~1,000 requests per 10 seconds but is IP-throttled with undocumented caps. PolyOrderbooks limits are per key and documented on the pricing page — you know exactly what you get.

Can I increase my rate limit?

Upgrade your data window plan for higher base throughput (300 rpm on paid), then add the Fast (+$19/mo) or Heavy (+$39/mo) speed add-on for 1,000 or 2,500 rpm respectively. Enterprise plans have custom limits.

Do rate limits apply to the free Starter plan?

Yes. Starter gets 60 rpm and 1,000 requests per day. This is enough for exploration and small projects. If you consistently hit the limit, it's a signal to upgrade.

How many requests does a typical backtest need?

It depends on the time range and resolution. A 5-minute market at 250ms resolution returns ~1,200 snapshots in one request. Backtesting 100 markets requires 100 requests. At 300 rpm (paid plan), this takes about 20 seconds.

Are there separate limits for different endpoints?

No. The rate limit is global across all API endpoints. Whether you're fetching markets, books, prices, or metrics, every request counts toward the same per-minute and per-day limits.

Is there a free API key?

Yes. The Starter plan is free, includes order books, prices, and metrics at 250ms resolution with 3 days of history. No credit card required to sign up.

Where do I find my API key?

After signing in, go to Dashboard and open the API keys section. Generate a key there. The key is shown once on creation — store it securely.

How is the API key authenticated?

Pass it as an X-API-Key header on requests to the PolyOrderbooks REST API. The header is per-request, not per-IP.

Can I have multiple API keys?

Yes. You can generate multiple keys from the dashboard. Each key has its own rate limit pool. This is useful for separating development and production traffic.

What happens if I lose my API key?

Revoke the lost key from the dashboard immediately, then generate a new one. The old key is invalidated instantly. Any in-flight requests using the revoked key will fail with 401.

Do I need a different key for the Python SDK?

No. The same key works with the Python SDK, raw requests, curl, and any HTTP client. Set it via the POLYORDERBOOKS_API_KEY environment variable or pass it directly to the client.

How do I install the Python SDK?

pip install polyorderbooks. The SDK wraps the REST API and handles authentication, pagination, and retries. Set your API key via the POLYORDERBOOKS_API_KEY environment variable or pass it directly.

Can I use requests instead of the SDK?

Yes. All endpoints are REST and documented at docs.polyorderbooks.com. Pass your API key as an X-API-Key header. The SDK is a convenience wrapper — raw requests work identically.

What is the simplest way to get started?

Sign up for the free Starter plan, grab your API key from the dashboard, pip install polyorderbooks, and call client.markets() to list available markets. From there, pull books or prices for any slug.

Does the SDK support async?

The current SDK uses synchronous requests. For async workflows, use aiohttp or httpx directly with the REST API. The endpoints and authentication are the same.

Can I use the SDK with Jupyter notebooks?

Yes. The SDK works in Jupyter notebooks, Google Colab, and any Python environment. Set the API key as an environment variable before importing the client.

Can I use Polymarket's free /prices-history instead?

For simple price charts and implied probabilities, yes — /prices-history is free and requires no API key. Use PolyOrderbooks when you need full L2 depth, spread, aligned metrics, or historical book snapshots for fill simulation.

What is the difference in resolution?

The CLOB /prices-history returns minute-level or sub-minute intervals at best, and older data may only be hourly. PolyOrderbooks captures at 250ms resolution and lets you query grids from 1d down to 250ms.

Do I need both?

Many users start with /prices-history for quick price checks and move to PolyOrderbooks /books when they need depth for backtesting, slippage analysis, or microstructure research. The free Starter tier gives you 3 days to test the difference.

Is Polymarket's /prices-history reliable for backtesting?

It's reliable for price-level analysis, but it doesn't give you order book depth. For backtesting that includes fill simulation and slippage, you need the L2 data that only PolyOrderbooks provides.

Which is better for building a trading dashboard?

For a simple price chart, /prices-history is free and fast. For a dashboard that shows depth, spread, and liquidity metrics, PolyOrderbooks /books gives you all the data you need in one endpoint.

How many markets does Polymarket have?

Thousands. New 5-minute markets are created every 5 minutes, and longer timeframes (1h, 1d) are created regularly. The /markets endpoint is the authoritative source for the current count.

What is a slug?

A slug is a unique identifier for each market, like btc-updown-5m-1787486400. You use it to query order books, prices, and metrics. Slugs encode the coin, timeframe, and resolution timestamp.

How often should I refresh my market index?

For active trading, every 5 to 15 minutes. For batch analysis, every hour is fine. The /markets endpoint is lightweight and does not count heavily against your rate limit.

Can I get only resolved markets?

Yes. Pass ?status=resolved to see only markets that have already settled. Each resolved market includes the winning outcome, which is useful for historical analysis and backtesting.

How are metrics computed?

Metrics are derived from the same L2 order book data used by the /books endpoint. Spread is best_ask minus best_bid. Depth is the sum of all size values on each side. VWAP weights each price level by its size.

Are metrics aligned with book snapshots?

Yes. Metrics, books, and prices share the same timestamps, so you can join them in a DataFrame or analysis tool without any time alignment logic.

Can I get metrics without pulling raw books?

Yes. The metrics endpoint is separate from the books endpoint. If you only need summary statistics, skip the books endpoint and use metrics directly. This saves processing time and reduces data transfer.

What does VWAP tell me that spread doesn’t?

Spread tells you the gap between the best bid and best ask. VWAP tells you the average execution price across all levels, weighted by size. A market can have a tight spread but a high VWAP if there is thin depth beyond the top of book.

What is the base URL?

https://api.polyorderbooks.com/v1. All endpoints are relative to this base. There is no versioning beyond v1; breaking changes will get a v2 path.

How do I authenticate?

Include an X-API-Key header on every request. Get your key from the dashboard after signing up. There is no OAuth or token refresh flow.

What format are the responses?

All responses are JSON. Error responses have a consistent {"error": "<message>"} structure. Success responses are arrays or objects depending on the endpoint.

What happens on a bad request?

The API returns HTTP 400 with a JSON error message explaining what went wrong. Common causes: missing required parameters, invalid slug, or out-of-range time values.

Can I use Google Colab?

Yes. The polyorderbooks SDK works in Google Colab with no special setup. Install it with !pip install polyorderbooks and set the API key as an environment variable.

How do I handle large datasets in notebooks?

Use coarser resolutions (1m or higher) for initial exploration, then drill into 250ms data for specific time windows. Pandas handles tens of thousands of rows well.

Can I export notebook results to CSV?

Yes. After building a DataFrame, use df.to_csv("output.csv") to export. This works for any analysis you want to share or use outside the notebook.

How do I share notebook results with my team?

Export DataFrames to CSV or Parquet with df.to_csv() or df.to_parquet(). For interactive charts, export as HTML with fig.write_html(). You can also share the notebook itself as a .ipynb file or convert it to a static HTML report.

Which format should I use?

Parquet for analysis and backtesting (fastest queries, smallest files). CSV for sharing with non-technical stakeholders. JSON for API ingestion and debugging.

How much smaller is Parquet than JSON?

Typically 3 to 5x smaller for order book data. The exact ratio depends on the number of price levels and the compression ratio.

Can I query Parquet files without loading them into memory?

Yes. DuckDB and Polars can query Parquet files directly without loading them into memory. This is useful for large datasets.

Do PolyOrderbooks datasets come in Parquet?

Yes. Sample datasets are provided in Parquet format for optimal file size and query performance. You can convert to CSV or JSON as needed.

How many API requests does a daily pipeline need?

It depends on how many markets you track. Each market requires one request per endpoint (books, prices, metrics). Tracking 500 active markets means ~1,500 requests per run.

Should I use the SDK or raw requests?

The SDK handles retries and pagination automatically, which saves code. Raw requests give you more control over error handling and logging. For production pipelines, raw requests with explicit retry logic are often preferred.

How do I handle new markets appearing?

Refresh your market index at the start of each pipeline run. New markets appear in the /markets list before they start trading.

What if the API is down during a scheduled run?

Log the failure and retry on the next scheduled run. Do not retry immediately because if the API is down for maintenance, immediate retries waste rate limit budget.

What is the difference between L1 and L2 data?

L1 shows only the best bid and best ask (top of book). L2 shows every price level with its size. L2 is essential for depth analysis, fill simulation, and slippage estimation.

How do I identify liquidity zones?

Look for price levels with disproportionately large size compared to neighboring levels. These concentrations act as support/resistance.

Does depth predict price direction?

Depth imbalances are a directional signal but not definitive. Use depth as one input alongside spread, volume, and other indicators.

How does depth differ between BTC and ETH markets?

BTC markets typically have deeper books and tighter spreads than ETH markets. This reflects higher trading volume and more market maker participation.

What is a good spread on Polymarket?

For active BTC 5-minute markets, spreads of 1 to 2 cents during steady-state trading indicate good liquidity. Wider spreads (5+ cents) suggest low participation.

Why do spreads widen near resolution?

Market makers widen spreads to protect against adverse selection. As resolution approaches, the risk of being on the wrong side of a binary outcome increases.

Can I trade at the spread?

Yes. Placing a limit order at the best bid or best ask means you are providing liquidity, not crossing the spread. You earn the spread instead of paying it.

How does spread relate to slippage?

Spread is the minimum cost of immediate execution. Slippage is the additional cost when your order walks through multiple price levels.

How much slippage should I expect?

For a 500-share buy in a liquid BTC 5-minute market, expect 0.5 to 2 cents of slippage. Larger orders or thinner markets will see more.

Can slippage be negative?

In theory, yes, if the book moves in your favor between signal and execution. In practice, slippage is almost always positive (unfavorable).

How do I reduce slippage?

Use limit orders instead of market orders. Split large orders into smaller pieces over time. Trade in liquid markets (BTC 5-minute) where depth is deepest.

Does slippage affect backtest results?

Significantly. A strategy that appears profitable on midpoint data may be unprofitable after accounting for spread and slippage. Always include execution cost modeling.

What determines the outcome of a market?

A Chainlink oracle reads the cryptocurrency price at the resolution timestamp and compares it to the opening price. If the price is higher, the market resolves Up.

Can the outcome be challenged?

No. The oracle price is final. Chainlink decentralized network is designed to produce a single, tamper-resistant price that cannot be disputed.

What happens to my orders at resolution?

All outstanding orders are cancelled instantly at the resolution timestamp. Your positions are settled at $1 (winning) or $0 (losing).

Can I still query resolved market data?

Yes. Resolved markets remain fully queryable via the API. Every row reflects the winning outcome.

Are BTC and ETH markets correlated on Polymarket?

Yes, typically 0.7 to 0.9 during normal conditions. The correlation reflects the underlying relationship between Bitcoin and Ethereum prices.

Can I trade correlation directly?

You can trade relative value by going long one market and short the correlated market when the spread deviates from its mean. This is a pairs-trading approach.

How do I detect lead-lag relationships?

Compute cross-correlation between two price series at different time offsets. BTC typically leads ETH during volatile periods.

Does correlation persist across market lifecycles?

Correlation is strongest during steady-state trading. It can break down near resolution when individual market factors dominate.

How many markets do I need for a reliable backtest?

At least 20 to 50 markets of the same type (e.g., BTC 5-minute) to get statistical significance.

Should I use fine or coarse resolution for backtesting?

250ms for the most accurate fill simulation. Coarser buckets are acceptable for strategies that do not depend on fine-grained timing.

How do I avoid overfitting?

Use walk-forward analysis, keep parameter counts low (2 to 3 at most), test on out-of-sample data, and validate on markets not used in optimization.

What P&L should I expect from a good strategy?

After accounting for spread and slippage, even modest positive P&L is good. Watch for strategies that are only profitable when ignoring execution costs.

Is arbitrage common on Polymarket?

Logic arbitrage is rare because market makers actively monitor quotes. Cross-market arbitrage between platforms is more common but requires multi-platform access.

Can I automate arbitrage detection?

Yes. Monitor the sum of Up and Down ask prices in real-time. When it drops below $1 minus your threshold, trigger a buy signal for both outcomes.

What profit should I expect from arbitrage?

Logic arbitrage on Polymarket typically yields 0.5 to 2 cents per trade before transaction costs. Volume and speed matter more than per-trade profit.

What are the main risks?

Execution risk, liquidity risk, market maker reaction, and counterparty risk. Automated systems with low latency help mitigate execution risk.

How much can market makers earn?

It depends on spread width and volume. In active BTC 5-minute markets, market makers can earn 0.5 to 2 cents per round-trip trade, multiplied by volume.

What is the minimum capital to market make?

You need enough capital to provide meaningful quotes on both sides. For Polymarket prediction markets, $500 to $1,000 is a reasonable starting point.

How do I manage inventory risk?

Adjust your quotes to attract the opposite flow when your inventory is one-sided. Widen your spread as inventory grows. Consider hedging on correlated markets.

What are the biggest risks for market makers?

Adverse selection (trading against informed flow), inventory risk (market moves against your position), and operational risk (latency, system failures).

What programming language should I use?

Python is the most common choice due to its ecosystem (pandas, requests, asyncio). JavaScript/TypeScript works well for real-time bots using Node.js. Choose what you are most productive in.

How do I test my bot without risking money?

Run in paper trading mode: generate signals and log them without placing actual orders. Compare your signals against actual market outcomes to validate your strategy.

What are the biggest risks for automated trading on Polymarket?

API rate limits (use exponential backoff), slippage (account for spread in signals), and bugs (circuit breakers prevent runaway losses).

How do I handle API downtime?

Log the failure and pause trading. Do not retry aggressively. Resume automatically when the API recovers. Most profitable opportunities can wait a few minutes.

Was Polymarket V2 a breaking change for order books?

Yes, at the cutover: matching stopped, all resting limit orders were canceled, and every order book was rebuilt. Account balances and open positions carried over automatically, and conditional token IDs did not change.

Does my historical order-book dataset break across the V2 cutover?

No. Prices stay quoted 0-1, the L2 snapshot shape is unchanged, and archives read as one continuous series. The only adjustment is fee modeling: apply V1 fee semantics before April 28, 2026 and V2 taker-only fees after it.

Do I need py-clob-client-v2 or @polymarket/clob-client-v2 to trade?

Yes. V1 packages and V1-signed orders are no longer accepted on production; pre-V2 clients received HTTP 503 cancel-only responses. The constructor also changed to an options object with chain instead of chainId.

Is collateral still USDC on Polymarket?

You still deposit and withdraw USDC, but settle on-chain in pUSD, Polymarket's ERC-20 redeemable 1:1 for native USDC. API traders must wrap USDC.e into pUSD before placing V2 orders and approve the V2 exchange contracts.

Did Polymarket V2 reduce slippage?

No. V2 fixed nonce- and balance-related failed fills, but it did not change order-book depth. Spreads and slippage are structurally the same after the upgrade.

How tight is the BTC order book on Polymarket?

Averaged over the trailing three days the spread is 0.0115, with a median of 0.0100 - about a one-cent touch on a 0-1 contract, the tightest of the eight tracked crypto assets.

Why do BTC books cross so often?

About 2.79% of the last 24 hours of BTC snapshots had best bid above best ask. It reflects fast repricing in the busiest contract rather than bad data; the next tick usually clears the cross.

What resolution does the BTC book data use?

Capture is uniform 250ms. You can query coarser grids (1s up to 1d) but the underlying cadence is always 250ms, on every plan including the free Starter tier.

How do BTC markets settle?

All 833 BTC Up/Down markets resolve on a Chainlink TWAP reference price (settlement_source chainlink_twap), and the archive stores the spot and TWAP observations used for grading.

Is the ETH order book as good as BTC's?

Close but not equal. ETH's average spread is 0.0139 versus 0.0115 for BTC, and its three-day average top-of-book liquidity is about $27k versus $57k. Both are top-tier.

Why is the ETH crossed-book rate the highest tracked?

2.94% of the last 24 hours of ETH snapshots were crossed. ETH reprices about as fast as BTC while carrying roughly half the depth, so momentary crosses are slightly more common.

What should I assume for ETH transaction costs in a backtest?

Target a spread near 0.01 and filter crossed snapshots. Assuming a zero spread or ignoring crosses will overstate fills on ETH more than on BTC.

How do ETH markets settle?

Every ETH Up/Down market resolves on a Chainlink TWAP (chainlink_twap), and the archive holds the spot and TWAP observations used for grading.

Where does SOL rank in Polymarket book quality?

Mid-pack. Its average spread is 0.0262 versus 0.0115 for BTC, and its three-day average top-of-book liquidity is about $18k - above XRP and below ETH.

Is Solana's crossed-book rate high?

It is 2.63% over the last 24 hours, third-highest of the eight assets and close to BTC and ETH even though SOL's spread is wider.

Is the SOL sample directionally balanced?

Yes - 49.2% of resolved SOL markets resolved up (146 of 297), the closest to even in the basket, which makes it useful for testing non-directional edges.

How do SOL markets settle?

All 687 Solana Up/Down markets settle on chainlink_twap Chainlink reference prices, with the spot and TWAP observations archived for verification.

How does XRP's book compare to Solana's?

Almost identical spread (0.0259 vs 0.0262) with slightly less depth ($16,649 vs $18,132 three-day average liquidity). Treat them as the same quality tier.

Is XRP heavily crossed?

No. 1.90% of the last 24 hours of XRP snapshots were crossed, below BTC, ETH and SOL, making XRP one of the calmer majors to model.

Does XRP resolve up or down more often?

In this sample XRP leans slightly down: 46.8% up (131 of 280 resolved). Over a short window that is likely noise, but worth checking for directional strategies.

How do XRP markets settle?

All 672 XRP Up/Down markets settle on chainlink_twap Chainlink reference prices, with spot and TWAP observations archived.

Is the BNB book thin on Polymarket?

It is mid-thin. The three-day average top-of-book liquidity is about $11,710 per market, similar to Dogecoin and roughly a fifth of Bitcoin's, with a 0.0415 average spread.

Why does BNB resolve down so often in the sample?

Resolved BNB markets are 41.2% up (105 of 255), the most down-leaning in the basket. Over one window that is likely noise, but directional strategies should verify rather than assume.

How often is the BNB book crossed?

1.30% of the last 24 hours of snapshots - less than half the rate seen on Solana, consistent with a wider book that reprices less often.

When did BNB reference-price capture start?

BNB reference coverage in this archive begins at 11:52 UTC on the measurement day, shorter than the BTC/Ethereum series that starts at 07:38, so older BNB books predate the reference capture.

Is Dogecoin liquid on Polymarket?

More than its market count suggests. The three-day average top-of-book liquidity is about $12,054 per market, above BNB's $11,710, with a 0.0363 average spread.

How wide is the Dogecoin spread?

0.0363 average, 0.0300 median - about three ticks, the tightest of the smaller-cap books and wider than XRP and Solana.

Does Dogecoin have full reference-price coverage?

Yes. Dogecoin's reference capture started with the early 07:38 UTC cohort and held 63,498 observations on the measurement day, so market and reference series start together.

How do DOGE markets settle?

All 554 Dogecoin Up/Down markets settle on chainlink_twap Chainlink reference prices, with spot and TWAP observations archived.

Why is the HYPE spread so wide?

HYPE averages 0.1025 with a 0.0600 median - about six ticks - because it is one of the thinner books in the basket. Only Zcash quotes wider.

Is HYPE's book crossed often?

Rarely. 0.94% of the last 24 hours of HYPE snapshots were crossed, the second-lowest rate tracked, consistent with a wide book that reprices slowly.

Do I need a slippage model for HYPE?

Yes. With about $5,390 three-day average top-of-book liquidity, size walks the book quickly, so a flat-spread backtest assumption will overstate fills.

When did HYPE reference-price capture start?

HYPE reference coverage begins at 11:52 UTC on the measurement day, part of the cohort (with BNB and ZEC) added after the 07:38 BTC/Ethereum/Dogecoin/Solana/XRP group.

Why is the ZEC book so wide on Polymarket?

Zcash has the fewest listed markets and the least trading activity in the basket, so a 0.4271 average spread (0.3900 median) and about $2,044 three-day average top-of-book liquidity are the natural result.

Is the ZEC book ever crossed?

Barely. 0.10% of the last 24 hours of ZEC snapshots were crossed - the lowest rate of the eight assets, because the book reprices very slowly.

Can I backtest ZEC strategies on this data?

You can, but with minimal depth and a ~39-cent median touch, most strategies will be dominated by costs. Treat ZEC results as illustrative of an illiquid regime, not a tradable edge.

How do ZEC markets settle?

All 291 Zcash Up/Down markets settle on chainlink_twap Chainlink reference prices; ZEC reference capture began at 11:52 UTC on the measurement day.

Does Polymarket settle on the last traded price?

No. Crypto Up/Down markets settle on an external reference level - currently a Chainlink 60-second TWAP - not on the final CLOB trade. The archive stores those reference observations separately from the order book.

How many reference observations does the archive hold?

459,597 as of 2026-10-17: 250,416 spot and 209,181 native 60-second TWAP rows across the eight crypto assets.

Can I get only the TWAP rows?

Yes. GET /v1/reference-prices accepts kind=spot or kind=twap along with asset and a start/end time range.

What does window_seconds tell me?

It is the averaging window for the row. Spot rows carry 0; TWAP rows carry the provider window, which is currently 60 seconds for every asset.

What price does a Polymarket crypto market settle on?

A Chainlink 60-second TWAP of the asset in US dollars. Every market records settlement_source = chainlink_twap and a resolution_source URL of the form data.chain.link/streams/<coin>-usd-twap-60s-streams.

Is the TWAP window different for 15-minute markets?

No. twap_lookback_seconds is 60 for every market, whether the horizon is 5 minutes, 15 minutes or 4 hours. The market horizon is the contract length; the TWAP window is always 60 seconds.

Why use a TWAP instead of the last price?

A 60-second TWAP makes momentary wicks at expiry ineffective, removing the easiest settlement-time manipulation. The trade-off is that a choppy minute can settle away from both the open and the last trade.

Can I reproduce the exact grade?

Yes. Pull the TWAP reference rows at the market close from /v1/reference-prices and compare to the opening strike; the archive stores both the reference series and the market books.

Does a 4-hour market settle on a 4-hour TWAP?

No. Every horizon settles on a 60-second TWAP (twap_lookback_seconds = 60). The horizon is the contract length; the settlement smoothing window is always 60 seconds.

Which horizon has the most markets?

5-minute. Of 5,005 crypto Up/Down markets on 2026-10-17, 3,467 were 5-minute, 1,436 were 15-minute and only 102 were 4-hour.

Should I mix horizons in one backtest?

Only if that matches your question. Pooling 5m, 15m and 4h weights the sample toward the shortest windows, which trade most; if you want a specific horizon, filter to it explicitly.

Is there enough 4-hour data to study?

Barely. With only 102 4-hour markets across all eight crypto assets, treat 4-hour results as case studies rather than a statistical distribution.

Are native and derived TWAPs the same number?

Usually close, but not guaranteed identical. Native is published by the provider; derived depends on your sampling cadence and boundary handling, so the two can differ at the margins.

Which one did Polymarket settle on?

The native provider TWAP. Every reference row records twap_kind and window_seconds so you can confirm the settlement input rather than guessing.

Does the archive contain derived TWAP rows?

Currently no. The measured TWAP set is entirely native over a 60-second window. The schema supports derived rows, so the field is present even when only one kind exists.

When should I build my own TWAP?

When you need a window the provider does not publish, or when you want to test how sensitive a result is to the smoothing choice. Use the native row for anything settlement-adjacent.

Why do some assets have no reference rows early in the day?

Reference feeds are added over time. On 2026-10-17, BTC, ETH, SOL, XRP and DOGE began capturing at 07:38 UTC, while BNB, HYPE and ZEC were added at 11:52 UTC, so earlier windows for those three have no rows.

Should I back-fill missing reference prices?

Not silently. Either drop markets whose window has no reference row, or carry the nearest value forward with an explicit staleness cap, and record which policy you used.

How do I know how old a reference price is?

Use the point-in-time snapshot endpoint, which returns the nearest reference observation at or before a requested time along with its age, so staleness is explicit.

Is a missing row a data error?

No. It means capture did not run for that asset at that time. The archive leaves the window empty rather than filling it with an estimate.

What timestamp format does snapshot-at accept?

An ISO 8601 timestamp or Unix seconds in the path. It returns the nearest stored book at or before that moment, not the nearest book in either direction.

What is age_ms?

The milliseconds between the nearest stored book and the time you asked for. Small values mean the snapshot is effectively that instant; large values mean the book is an approximation.

Does snapshot-at include reference prices?

Yes. The snapshot block includes a reference object with the nearest spot and TWAP observations for the market's asset at or before the requested time.

Should I use snapshot-at instead of range queries?

For a single moment, yes. For bulk work across many markets, use the range endpoints for throughput and reserve snapshot-at for the moments where exactness matters.

How big can the book-to-expiry gap be?

Usually a few hundred milliseconds at 250ms capture. The snapshot-at endpoint reports the exact gap as age_ms so you can set and enforce a tolerance.

Should I grade on spot or TWAP?

TWAP. Markets settle on the 60-second Chainlink TWAP. Use spot to understand the path, but grade on the archived TWAP rows, especially near the money.

How should I treat markets with no winner yet?

Exclude them. Treating unresolved markets as losses biases win rate downward; they are simply not graded yet.

What does a null mid price mean?

The book was one-sided at that instant - bids but no asks, or the reverse - so there was no valid midpoint. A fill model must not assume two-sided liquidity there.

What is the most realistic fill model?

Walk-the-book, because it consumes resting depth in order and accounts for thin books. Touch-fill is acceptable for small orders on liquid assets like BTC and ETH; mid-fill should only be used as a sanity check.

Why can't I use the same fill model on every asset?

Because depth varies 28x across the measured assets, from 2,044 on ZEC to 57,147 on BTC. A fixed model overstates fills on thin assets and understates the effort on liquid ones.

Does the backtester apply the taker fee?

Yes if you set taker_fee on the strategy. Omitting it inflates results for high-turnover strategies, which is why it should always be set.

How do I model my queue position?

You cannot, from the archive alone - queue position depends on arrival order. For taker strategies it does not matter; for maker strategies assume you are behind the resting size.

What is a typical Polymarket spread?

Measured 3-day medians range from 0.0100 on BTC and ETH to 0.3900 on ZEC, with averages consistently higher because of quiet-to-wide swings.

Is a flat slippage assumption acceptable?

Rarely. Depth slippage depends on order size versus resting depth, so computing it from stored L2 levels is more accurate than any constant penalty.

Should I model average or median spread?

Median if your strategy trades mostly in calm windows; average or worse if it trades on volatility events, since those windows have the widest books.

Can execution improvements remove slippage?

Only depth slippage. The half-spread you cross is structural, so a wide-spread market stays expensive no matter how the order is sliced.

What is ladder-walking?

Filling an order across multiple price levels, consuming resting size at each, so the average fill price steps away from the best level as size grows.

Why does level spacing matter?

The gap between consecutive levels sets how much the average fill drifts. Uneven spacing across assets means a fixed level-count model misprices most ladders.

How do I handle an empty rung?

Treat it as a wall. The archive reports a null mid for one-sided books, so a walk should stop rather than fill through a level that had no resting size.

Is slicing across rungs the same as time-slicing?

No. Slicing across rungs uses the ladder's breadth to cut depth slippage; time-slicing trades sequentially and risks adverse selection. Model the one you would actually run.

What is a reference entry condition?

An entry that triggers on the underlying asset's archived reference price (spot or TWAP) rather than on the market's own contract price.

Why use a reference entry instead of a price entry?

Because Polymarket settles on the underlying reference, not the contract price. A thesis about the asset should enter on the series that decides the outcome.

Can I combine entry conditions?

Yes, with the or entry type, which fires on the first of several conditions. Keep the set small to avoid overfitting.

Can I define an entry without an exit?

No. The strategy requires both an entry list and an exit rule alongside the market, side and fee, so an incomplete plan is rejected.

What is the default exit?

hold_to_expiry, which carries the position to settlement. It defaults to true when no other exit is specified.

Should I use a stop-loss on 5-minute markets?

Usually not. On a binary that moves between 0 and 1, stops fire on noise and lock in losses settlement would have reversed. Measure the effect per horizon rather than assuming.

Take-profit or hold-to-expiry?

Compare them. A take-profit is a taker exit that pays the spread, so it must beat settlement by more than its execution cost to be worth using.

How do I know why trades closed?

The report includes exit_reasons, a count of trades ending each way, which you should read alongside total_pnl and the equity curve.

What is profit factor?

Gross profit divided by gross loss. Above 1.0 means profitable. It is scale-free but can be distorted by a single large winner, so check the trade count.

Is a high win rate good?

Not on its own. On binaries a high win rate can come from taking small wins and holding losers to expiry, so read it beside the average winner and loser.

Why does max_drawdown matter more than PnL?

Because a strategy with a large drawdown is usually abandoned before it recovers, regardless of its final PnL. Drawdown is what decides whether a strategy survives.

What are fill_sources and skips?

fill_sources shows where simulated fills came from (midpoint fills signal an optimistic model); skips lists trades that could not execute for lack of depth.

What is look-ahead bias?

Using information at decision time that would not have been available then - most often settlement results or a book snapshot timestamped after the trade.

How does snapshot-at prevent it?

It returns the nearest book at or before the requested time and reports the gap as age_ms, so a decision never reads a future snapshot.

What is the reference-price leak?

The reference series is the settlement input, so reading a value at expiry when evaluating an earlier entry leaks the answer. Walk rows in time order and use only prior observations.

How do I audit a strategy for bias?

Use the report's trades table: sort by entry time and confirm every input was timestamped at or before it. An entry predating the move it trades is the tell.

What is walk-forward testing?

Choosing parameters on a train window, scoring on the next window without changes, then rolling both forward - producing a sequence of out-of-sample scores instead of one in-sample fit.

Why not just backtest once?

A single backtest can reuse the same data for fitting and scoring, so it measures fit, not generalization. Walk-forward scores on data the parameters never saw.

How long should the windows be?

Long enough to fit the parameters and short enough to adapt to regime change. Short-horizon markets allow day-scale windows; test sensitivity across window sizes.

What is a good out-of-sample result?

One that degrades only modestly from in-sample. A strategy that collapses out-of-sample was overfit; one that declines gradually is showing decay worth tracking.

Does the backtester support position sizing?

It exposes max_trades_per_market and a budget bound (5 to 10,000). Size should be set relative to the market's measured depth rather than as a fixed contract count.

Why size as a fraction of depth?

Because depth varies 28x across assets. A fixed size that is negligible on BTC can be over half the book on ZEC, so a fraction keeps market impact comparable.

What is budget for?

It bounds total simulated capital. Raising it reveals capacity limits: if the edge collapses at larger sizes, the strategy cannot absorb more capital.

Should I use full Kelly sizing?

No. Kelly assumes the win probability is known exactly, which a backtest never provides. Use half-Kelly as a starting point and reduce further based on measured drawdown.

What is the default sample size?

25 markets. That is a smoke test, not a study - it cannot separate small edges from noise.

How many trades do I need to trust a win rate?

Hundreds. The standard error on a win rate falls with the square root of the sample, so 25 trades give roughly a 10-point error and 1,000 give about 1.6.

Does a big sample prevent overfitting?

No. Large samples still overfit if you tune many parameters. Split the sample: fit on part, score on a holdout, as walk-forward testing does.

What does the days parameter do?

It bounds the lookback window - roughly 1 day on the free Starter plan and up to 30 on paid plans - which controls how much history the sample draws from.

How do I set the taker fee?

Set taker_fee on the strategy so the backtester applies it to every taker trade. Leaving it at zero is only defensible for strategies that never take liquidity.

What should trade_lag_seconds be?

At least the honest end-to-end latency of your stack, from data fetch to order submission. Zero assumes you trade at the exact price you see.

Can the backtest tell me my queue position?

No. Queue position depends on arrival order. Assume you are behind the resting size for maker orders; taker strategies are unaffected.

How much do fee and lag change results?

Often decisively for high-turnover strategies. Run the same strategy at several fee and lag settings - if the edge only survives at zero, it is not real.

What makes a backtest reproducible?

Pinning the data window, the sampled markets, the strategy parameters and the execution assumptions - fee, lag and fill model - so a fresh run returns the same numbers.

Why save the trades table?

Summary metrics alone cannot be re-derived if the underlying trades are lost. Storing the trades and exit reasons makes the result auditable.

How do point-in-time endpoints help?

They return observations at or before a recorded time, so a documented set of decision timestamps reproduces the same inputs on any later run.

What is the most-often-missing input?

The fill model. Mid and walk-the-book fills produce different results under the same strategy name, so the model and order size must be recorded.

Does the SDK return typed objects?

No. It returns plain dicts. Pydantic models add validation and typing at the boundary so shape errors surface early.

How are book ladders shaped?

Each is a list of [price, size] pairs, best price first: bids descend and asks ascend. An outcomes' value is a list of {t, bids, asks} snapshots.

Can a snapshot have no bids?

Yes. A snapshot list can also be entirely empty for a market with no captures in the window, so guard before indexing.

Pydantic v1 or v2?

Use v2. It is faster and the field_validator API shown here is v2 syntax.

How do I know there are more pages?

When metadata.next_cursor is a non-empty string. When it is absent or null, you have reached the end.

What do the iter helpers do?

iter_markets and iter_market_books yield each page and advance the cursor until it is exhausted, so you never write the loop yourself.

Can I resume a crawl after a crash?

Yes. Drive the cursor manually, persist the last cursor, and re-issue the request with it on resume rather than starting from the first page.

Why did I only get one page of data?

Because the cursor was not followed. A single call returns only the first page; always loop on metadata.next_cursor.

What shape should the DataFrame be?

One row per outcome per timestamp, with columns for best bid, best ask, mid, spread and per-side depth. That makes most microstructure metrics one line each.

How do I handle one-sided snapshots?

Keep the row but leave the missing side and the mid as null. Never average against zero, which would corrupt downstream statistics.

How do I get the touch?

Ladders are best-first, so bids[0][0] is the best bid and asks[0][0] is the best ask, after guarding for empty lists.

Should timestamps be strings or datetimes?

Parse to a datetime dtype at load time so joins, sorting and resampling work without repeated casting.

When should I use Polars over pandas?

For wide exports with many timestamps, Polars' columnar engine and expression API are faster and use less memory than row-wise loops.

What is a LazyFrame for?

It defers execution so filters and projections are pushed down before data is materialized, letting you scan exported files and read only what you need.

How do I compute rolling metrics?

Sort by timestamp and use window expressions with over() rather than manual loops, so the engine can parallelize across outcome groups.

Does Polars read Parquet?

Yes, via scan_parquet and read_parquet, which pair well with the export workload shown in the Parquet recipe.

Why DuckDB instead of pandas?

DuckDB queries Parquet in place with SQL, pushes filters into the scan, and handles joins and window functions without loading everything into memory.

Do I need a server?

No. DuckDB runs in-process inside your Python program, so there is nothing to install or connect to.

How do I compute a rolling spread?

Use a window function partitioned by outcome and ordered by timestamp, with a preceding frame; for example a 60-row average spread.

How do I join prices to books?

Export both to Parquet and join on timestamp. Match the resolutions first - if one series is coarser, aggregate the finer one to its bucket.

What is a depth chart?

Cumulative size plotted against price for bids and asks. The vertical gap at the mid is the spread; the horizontal span is depth.

Why filter empty snapshots before plotting?

A one-sided book has no valid mid. Plotting a fabricated zero creates a spike that did not occur in the data.

Should a notebook fetch data live?

Ideally not. Fetch once, cache to a local file, and have the notebook read that file so it reruns quickly and reproducibly.

How do I show the settlement effect?

Plot spread against time and annotate the settlement timestamp; the book usually tightens as maturity approaches and can spike in the final seconds.

Is the SDK async?

No, it is synchronous. For concurrency, use httpx.AsyncClient against the same REST endpoints with the X-API-Key header.

How many concurrent requests should I use?

Start small (around six) and raise it while watching for 429s. The right level depends on your plan's per-minute limit and your latency.

Will concurrency break rate limits?

It can. Cap in-flight requests with a semaphore so the concurrency level stays under your per-minute allowance.

How do I handle a slow request among many?

Set a client timeout and treat timeouts as retryable. gather() will not hang forever if each request has its own deadline.

What does RateLimitError provide?

It carries status_code, message, the parsed body and retry_after, the seconds the API asked you to wait before retrying.

Should I retry 404s?

No. NotFoundError means the id or slug does not exist; retrying it wastes quota. Retry only 429s and transient server errors.

Why add jitter?

Without it, clients that fail together retry together and re-flood the server. A small random fraction of the delay breaks the synchronization.

How many retries is right?

Three or four bounded attempts. Enough to ride out a blip, few enough that a real outage surfaces as an error rather than looping forever.

Is historical Polymarket data safe to cache?

Yes. A captured window does not change, so caching it on disk saves quota with no staleness risk - except for windows near the present.

What should a cache key include?

The endpoint plus all query parameters that affect the response: slug, start, end and resolution. Different windows must never share a key.

When should I invalidate?

Rarely for old history. Short-cache or skip caching for recent windows that may still gain rows as capture continues.

Why write the cache atomically?

A temp file plus rename prevents an interrupted write from leaving a corrupt entry that breaks later reads.

Why Parquet over JSON?

Parquet is columnar and compressed, preserves types, and is far smaller. Tools like DuckDB and Polars can scan it and read only the columns and row groups they need.

What shape should the export be?

Tidy: one row per outcome per timestamp, with timestamp as a datetime and prices as floats. Avoid nested ladders in the stored table.

How should I partition the files?

By the field you filter on most - commonly coin and date. Avoid over-partitioning, which creates many tiny files.

Which libraries read the export?

pandas read_parquet, Polars read_parquet/scan_parquet, and DuckDB read_parquet all read it natively.

Do I need to replay an event stream to build the book?

No. Each archived snapshot already carries full bids and asks ladders, so reconstruction is deriving the touch, mid and depth from one snapshot, not replaying updates.

How do I get a fill price for a given size?

Walk the opposite ladder from the best price, taking size at each level until filled. The average is the fill; if depth runs out, the order cannot fully execute.

What if one side is empty?

The mid is undefined and no fill is possible against the empty side. Keep the null rather than substituting zero.

Why does order size matter so much?

Because fills walk the ladder. A size that is trivial on a deep book expensive on a thin one, so the fill price depends on both size and depth.

What reference should I grade against?

The 60-second Chainlink TWAP for the market's asset. That is the settlement input, so a contract's final price is the wrong series.

Does the SDK expose reference prices?

Not currently. Its coverage ends at books, prices and metrics, so call /v1/reference-prices with requests using the X-API-Key header.

What if the reference window is empty?

Mark the market ungradeable. Reference capture does not cover every window, and falling back to spot would change the settlement rule.

How do I match the market's own result?

Compare your label to the market's recorded outcome. Disagreements usually indicate a boundary or timezone error in the join, not a data problem.

What are the plan limits?

Starter: 60 requests/min and 1,000/day with 3 days of history. Pro: 300/min and 50,000/day with 31 days. Scale: 1,000/min and 200,000/day with 90 days.

How do I check my remaining quota?

Call get_usage, which returns the plan, the limits, and current quota usage for your API key.

What should I do on a 429?

Read RateLimitError.retry_after, sleep that many seconds, then retry once. Do not retry immediately, which compounds the limit.

How do I spend less quota?

Cache responses locally so you never re-fetch, and choose the coarsest resolution that answers your question - one-second books cost far more pages than one-minute.

New to PolyOrderbooks?

Start with a free Starter plan — 250ms L2 books, 3 days of history, 1 free AI backtest, and 3 strategy backtests. No credit card required.