Backtest Contract
Every run should declare the market family, symbol, data family, time window, route or channel, cursor behavior, freshness gate, and output schema before it starts. That turns a notebook into an executable research artifact instead of a one-off query.Build The First Run
1
Choose one venue family
Start with the exact family: Hyperliquid core perps, Hyperliquid Spot, HIP-3 builder perps, HIP-4 outcome markets, or Lighter. Do not normalize symbols before you know which namespace they belong to.
2
Select the data family
Trades, order books, candles, funding, open interest, liquidations, L3/L4, and replay answer different research questions. Pick the narrowest one that can test the hypothesis.
3
Check quality before the pull
Call
/v1/data-quality/status and any route-specific freshness endpoint before using the window. Store that result with the run.4
Pull a bounded window
Use
start, end, limit, and cursor handling. Avoid unbounded loops. Save request IDs and pagination state.5
Freeze the run manifest
Store the run manifest beside the output. Include the OpenAPI/spec version, code version, and any data-quality notes.
REST Window Example
success, data, and meta.request_id, then decide whether the route returns meta.next_cursor for pagination. Store the exact query string. Backtests often become impossible to debug because the dataset kept the rows but not the request that produced them.
Replay Example
Use WebSocket replay when the order of messages is part of the strategy. REST history can answer “what trades happened in this window?” Replay is better for “what would the book handler have seen as events arrived?”gap_detected messages as part of the backtest result. A gap is not just a transport event; it changes the meaning of the derived metrics. Mark the run incomplete, narrow the window, or rebuild from a checkpoint.