Skip to main content
Pull one bounded window of historical rows, page by page, and save it with the cursor chain, request IDs, and quality decision that make it reproducible. The example pulls an hour of Hyperliquid core BTC trades; the same steps apply to any venue family and data type. For an overview of Hyperliquid core history and its route families, see the Hyperliquid core coverage and route-family overview.

Prerequisites

  • Know the namespace and symbol. Venues and market types maps a market to its namespace.
  • Load the API key from the runtime environment.
  • Set a page budget and output path before the first request.
  • For a window older than the most recent 30 days, check the Free tier history boundary: Free serves the most recent rolling 30 days, and Build and above keep the full retained archive.
A venue-wide first served date, or the end of a known backfill period, does not show that every row in your window was captured. Check the window itself, as in the first step below.

Inputs

Fix the window once and reuse it for every call. It sits inside every plan’s history, including Free’s most recent 30 days:

Steps

1

Check the window

Check symbol-specific historical coverage and known gaps for the same bounds:
Read the trades entry (reported as fills) for completeness, gaps, and cadence. Freshness is not historical completeness: recency and capture of the historical window are different checks. Data quality explains how to read each signal.
2

Pull the first page

3

Follow the cursor within bounds

If the response has meta.next_cursor, send that exact opaque string as cursor on the next request. Keep the original start, end, limit, and every other filter unchanged. A page-budget stop with a remaining continuation is partial output, not a completed pull. Pagination shows the loop in shell and Python.
4

Save each page

Store the full query, response status, returned rows, cursor value, and request ID for every page. Keep the raw response separate from any transformed table.

Expected state

The first response has success, a data array of trade rows, and route metadata. meta.next_cursor is absent when the window is exhausted. A completed pull has no remaining cursor inside the requested window and a request ID for each page.

Verification

Pass each returned cursor unchanged; do not parse, calculate, or increment it. Check that the final row stays inside the requested window, the cursor chain is recorded, and the historical coverage and gap decision is attached to the output. A successful response or a recent record alone does not describe the window’s historical gaps.

Failure and recovery

  • 400: correct the named parameter, symbol, or time window before retrying.
  • 401: repair the key source or header.
  • 403 with historical_depth_exceeded (history_window_exceeded without the version header): the window is older than your plan’s history; move it forward or use a plan that keeps the full archive.
  • 404: return to Venue coverage and check the family namespace.
  • 429: honor Retry-After when present, otherwise use capped exponential backoff with jitter and lower concurrency.
  • A remaining cursor at the page budget: mark the output partial and resume with the saved cursor under a new bounded run.
  • A quality or incident failure: narrow, delay, or mark the output. Do not add synthetic rows.

Saved run metadata

The zero UUID is a shape placeholder only. Replace it with the UUID returned by each response or client wrapper, and write the numeric START and END you used. Append each real cursor to cursor_chain; do not invent an opaque cursor.

Next step

Turn the saved window into a research run with Prepare data for a reproducible backtest.
Last modified on October 6, 2026