Archive file index
The index of the Hyperliquid Parquet file archive — every UTC day that has a fills or positions file, with rows, bytes and the snapshot count, the column schema of both datasets, and the entry for the 5-minute latest positions file.
GET https://data.vike.io/v1/hyperliquid/archive/datasetsThe index of the Hyperliquid file archive: every UTC day that has a file, per dataset, with the file's row
count and size, the column schema of both datasets, and the entry for the latest positions file. It is the
only way to see what exists. There is no folder to browse and no daily or latest file has a URL of its own: a file
is obtained from /archive/url, which answers with a temporary link. The
one open folder is the free samples; samples_base in the response is its address (Free samples).
Two datasets, one Parquet file per UTC day each, from 2026-05-01:
| Dataset | What one file holds | First day |
|---|---|---|
fills | Every fill of every wallet that day, sorted by asset, fill_ts, trade_id, wallet. | 2026-05-01 |
positions | Every 5-minute snapshot of every open position that day, sorted by asset, wallet, snapshot_ts. | 2026-05-08, a partial day |
Positions start on 2026-05-08 because that is the first day the 5-minute snapshots exist. A third file,
latest/positions.parquet, holds the current open positions of every asset and is replaced every 5 minutes. How to
download and read all three is in Download the Hyperliquid file archive.
# what the archive holds: every day with its rows and bytes, the schema of both datasets, and the latest positions file
curl -s "https://data.vike.io/v1/hyperliquid/archive/datasets" \
-H "X-API-KEY: $VIKE_API_KEY"
# the newest day that has a positions file, with its snapshot count
curl -s "https://data.vike.io/v1/hyperliquid/archive/datasets" \
-H "X-API-KEY: $VIKE_API_KEY" \
| jq '[.dates[] | select(.streams.positions)][0]'
# the days whose positions file holds fewer than 250 snapshots: the source has them, the file is not padded
curl -s "https://data.vike.io/v1/hyperliquid/archive/datasets" \
-H "X-API-KEY: $VIKE_API_KEY" \
| jq -r '.dates[] | select(.streams.positions) | select(.streams.positions.snapshots < 250) | "\(.date) \(.streams.positions.snapshots)"'
# how fresh the latest positions file is, and how big
curl -s "https://data.vike.io/v1/hyperliquid/archive/datasets" \
-H "X-API-KEY: $VIKE_API_KEY" \
| jq '.latest.positions | {snapshot_ts, generated_at, rows, bytes}'The route takes no parameters. This is the capture of the index, cut for the page: dates held 173 entries, so
the newest two are kept, and each dataset's schema list is cut to its first two columns (the full lists are
under The columns). The envelope and the latest entry are complete. The capture is from 2026-10-21;
samples_base was added to the index after it, with the value shown.
{
"dates": [
{
"date": "2026-10-20",
"streams": {
"fills": {
"rows": 13405172,
"bytes": 401098335
}
}
},
{
"date": "2026-10-19",
"streams": {
"fills": {
"rows": 12022655,
"bytes": 358509915
},
"positions": {
"rows": 102738790,
"bytes": 1639446104,
"snapshots": 253
}
}
}
],
"schema": {
"fills": [
{
"name": "fill_ts",
"type": "DateTime64(3, 'UTC')",
"meaning": "Execution time of the fill, UTC, millisecond precision."
},
{
"name": "wallet",
"type": "String",
"meaning": "Trader address, lowercase 0x-hex."
}
],
"positions": [
{
"name": "snapshot_ts",
"type": "DateTime('UTC')",
"meaning": "Snapshot instant, UTC, whole minutes: the START of the ingestion cycle that wrote the row, not the instant of the node state it reads (typically 5-10 minutes earlier). Cycles are usually 5-7 minutes apart and irregular; a source outage leaves a longer gap. The day's `snapshots` count in the manifest says how many there are."
},
{
"name": "wallet",
"type": "String",
"meaning": "Trader address, lowercase 0x-hex."
}
]
},
"url_endpoint": "/v1/hyperliquid/archive/url",
"samples_base": "https://data.vike.io/archive/hl-samples/",
"latest": {
"positions": {
"snapshot_ts": "2026-10-21T10:13:00Z",
"generated_at": "2026-10-21T10:17:15Z",
"rows": 427884,
"bytes": 29578173,
"assets": 341,
"note": "The current open positions of every asset, one row per (wallet, asset, direction), refreshed about every 5 minutes. The columns are those of the daily `positions` file (meanings under `schema.positions`). `snapshot_ts` is per row: the ingestion cycle that last wrote the position. A position that closed within the last 15 minutes can still be present with an older `snapshot_ts`, the same rule as /v1/hyperliquid/positions; keep the rows at the file's `snapshot_ts` for the newest cycle only. There is no `opened_at`: /v1/hyperliquid/positions fills it per page, and joining it here costs 3x the rest of the run. Sorted by (asset, wallet, direction) in row groups of about 65,000 rows with min/max statistics (one asset is 1-2 of them). The file is REPLACED every ~5 minutes: download it whole (about 30 MB); a ranged read can straddle a replacement and fail, so retry it.",
"url_endpoint": "/v1/hyperliquid/archive/url?dataset=positions&date=latest"
}
}
}Reading the index
datesis newest first. Each entry has the day and astreamsobject with one key per dataset that has a file that day.rowsis the number of rows in the file andbytesits size, so you can budget a download before asking for the link.snapshotsappears onpositionsonly: the number of distinctsnapshot_tsvalues in that day's file, counted from the file itself. Read it before you aggregate. A day holds roughly 250 to 290 snapshots, and some hold far fewer because the source has fewer (see the callout on this page).reconstructed_hoursappears on apositionsentry only when that day has hours the source rebuilt by replaying fills instead of reading the venue's state: a list of hour starts such as2026-10-23T11:00:00Z. Rows in those hours are reconstructed, not measured:margin_usedandliquidation_priceare 0 andstate_tsis 1970-01-01. Their sizes matched the next real snapshot at 97% or better, except the hours also listed inreconstructed_lower_match_hours, which matched at 83 to 97%. Both lists are refreshed whenever the index is written, while a published day file is not rewritten, so an hour rebuilt after its day was published can be listed while that day's file still holds the gap: check thesnapshot_tsvalues in the file. On 2026-10-24, 52 of 169 positions days listed rebuilt hours.- A day appears once it is complete. Yesterday's files are published in the early UTC morning; the newest day
can therefore carry a
fillsfile before itspositionsfile, as the capture shows for 2026-10-20. latest.positionsis present while that file exists.snapshot_tsis the newest ingestion cycle in it andgenerated_atis when the file was written;rows,bytesandassetsdescribe the file as of that moment. The file is replaced about every 5 minutes, so these values move: ask the index again rather than caching them.url_endpointis where a file is asked for. The index carries no URL for any daily orlatestfile, because none exists.samples_baseis the public folder of the free samples. It is the one address in the index that you can request as it stands; see Free samples.
Fewer than 250 snapshots means a gap in the source, not a missing piece of the file
A positions file is never padded. Ten days hold fewer than 250 snapshots: 2026-05-08 (71, a partial first day),
2026-06-08 (226), 2026-06-26 to 2026-06-29 (154, 138, 125 and 124, a snapshot about every 12 minutes), 2026-06-30 (248),
2026-08-12, 2026-08-13 and 2026-08-17 (236 to 245). The source wrote fewer on those days. The snapshots field is how a
client tells a thin day from a normal one without opening the file; the
download guide lists the other facts worth
knowing about the data.
Free samples
samples_base is https://data.vike.io/archive/hl-samples/. It needs no API key and holds three files:
| File | What it holds |
|---|---|
fills-sample.parquet | Every BTC fill in the first UTC hour (00:00 to 01:00) of the sample day. |
positions-sample.parquet | One instant: every open BTC position of every wallet at the sample day's first snapshot, the first snapshot_ts in 00:00 to 01:00 UTC. |
manifest.json | The sample day and asset, and per dataset its description, sort order, published range (from, to, days), the full column schema, and which part of the day its sample file covers. |
The sample day is the newest day for which both datasets are published, and the samples are rebuilt about once a week,
so the day moves; read it from manifest.json. Each sample is cut with the same query as the daily file, so its
columns, their order and types and its sort order are those of the daily files, and positions-sample.parquet has all
19 columns. A sample file is at most 2 MB (fills) or 4 MB (positions). The folder cannot be listed, only GET and
HEAD are answered, and it carries none of the daily files: those come only from
/archive/url.
The columns
Both lists are the schema key of the response, in file order.
fills
| Column | Type | Meaning |
|---|---|---|
fill_ts | DateTime64(3, 'UTC') | Execution time of the fill, UTC, millisecond precision. |
wallet | String | Trader address, lowercase 0x-hex. |
asset | String | Instrument as Hyperliquid names it: BTC on the main dex, dex:NAME (e.g. xyz:SP500) for a builder-deployed perp. |
side | String | buy or sell: the direction of THIS wallet's order. |
size_token | Float64 | Fill size in base-asset units, unsigned (the direction is side). |
price | Float64 | Execution price, USD. |
size_usd | Float64 | Notional of the fill, size_token * price, USD. |
fee | Float64 | Fee charged in fee_token; negative is a maker rebate. |
fee_token | String | Token the fee is denominated in, e.g. USDC. |
is_maker | Bool | True when this wallet's order was resting on the book. |
order_id | UInt64 | Hyperliquid order id (oid) of this wallet's order. |
trade_id | UInt64 | Hyperliquid trade id (tid). Both counterparties of one trade carry the same value; a fill is identified by (wallet, fill_ts, trade_id). |
crossed | Bool | True when this fill crossed the book (the taker side). |
closed_pnl | Float64 | Realized PnL in USD the node booked on this fill; 0 for a fill that opens or adds to a position. |
dex_name | String | Perp dex the asset trades on: HL for the main dex, else the builder dex (e.g. XYZ). |
start_position | Float64 (nullable) | Signed position in the asset immediately BEFORE this fill (negative is short). NULL for fills before 2026-09-29, when the column was added; 0.0 is a real value (flat before the fill). |
positions
| Column | Type | Meaning |
|---|---|---|
snapshot_ts | DateTime('UTC') | Snapshot instant, UTC, whole minutes: the START of the ingestion cycle that wrote the row, not the instant of the node state it reads (typically 5-10 minutes earlier). Cycles are usually 5-7 minutes apart and irregular; a source outage leaves a longer gap. The day's snapshots count in the manifest says how many there are. |
wallet | String | Trader address, lowercase 0x-hex. |
asset | String | Instrument as Hyperliquid names it: BTC on the main dex, dex:NAME (e.g. xyz:SP500) for a builder-deployed perp. Called symbol in /v1/hyperliquid/positions. The prefix is authoritative: judge the dex by it, not by dex_name. |
direction | Int8 | 1 long, -1 short. The only place the side is stored: size_token and size_usd are never negative. |
size_token | Float64 | Position size in base-asset units, unsigned (the side is direction). |
size_usd | Float64 | Notional of the position at mark_price, size_token * mark_price, USD, unsigned. |
entry_price | Float64 | Average entry price of the position, USD. |
mark_price | Float64 | Mark price when the row was written, USD. |
liquidation_price | Float64 | Liquidation price, USD; 0 when the position has none (e.g. a well-collateralised cross-margin position). |
unrealized_pnl | Float64 | Unrealized PnL in USD, direction * (mark_price - entry_price) * size_token. |
leverage | Float32 | Leverage of the position as a multiple (10 = 10x). 0 when none was recorded, which happens on cross-margin rows. |
margin_used | Float64 | Margin the position ties up, USD: size_usd / leverage, or size_usd itself where leverage is 0. |
size_cohort | String | Account-value size tier of the wallet WHEN THE ROW WAS WRITTEN (shrimp, 2x shrimp, fish, ... up to 4x whale: 12 absolute-dollar thresholds assigned at ingestion), as stored: a point-in-time label, not today's grading. The same field and vocabulary as size_cohort in /v1/hyperliquid/positions. |
leverage_type | String | cross or isolated. |
dex_name | String | Perp dex the asset trades on: HL for the main dex, else the builder dex (e.g. XYZ). Rows written while a clearinghouse was not yet registered hold the literal clsN (e.g. cls10) and keep it; the asset prefix is authoritative. |
state_ts | DateTime('UTC') | The instant the state-derived columns (size, entry, mark, unrealized_pnl, leverage, margin_used, direction) describe, read from the node's state file; snapshot_ts is the WRITE time of the ingestion cycle, typically 5-10 minutes later (liquidation_price is re-read from the node at write time and belongs to snapshot_ts). 1970-01-01 00:00:00 means the row came from no state file (the per-wallet API fallback) or was written before 2026-08-22, when the column was added. Do not anchor a projection of the row on it: use snapshot_ts. |
liq_progress | Float64 | How far the mark has moved from entry toward liquidation, clamped to 0..1: 0 at or in profit versus entry (or no liquidation price), 1 at or through the liquidation price. When a cross-margin liquidation price has drifted past entry it falls back to liquidation_price / mark_price (long) or mark_price / liquidation_price (short). The same SQL as liq_progress in /v1/hyperliquid/positions. |
account_value | Float64 (nullable) | Native Hyperliquid perp account value of the wallet, USD (the quantity /v1/hyperliquid/wallets/{address} serves as equity.account_value), AS OF THE START OF THE ROW'S CLOCK HOUR: the wallet's last snapshot of the previous hour (a row at 10:37 carries the 09:5x value). Builder-DEX account equity is NOT included, so a wallet trading only dex:NAME assets usually reads 0. In latest, as of the start of the hour of the file's newest snapshot (an older hour while the hourly rollup lags), so on the rows of positions that closed in the last 15 minutes it can be up to 15 minutes later than the row. NULL when unknown: the wallet had no snapshot in that previous hour (e.g. its first position opened in the row's hour); the stored value is a reconstruction, not a measurement (hours rebuilt from fills, and the values the 2026-08-10 repair rewrote); or the row is a builder-DEX position (dex_name other than HL) whose value comes from an hour up to 2026-08-10 00:48 UTC (the repair seam): until then a builder-DEX-only wallet's empty native account was stored as a non-equity figure the repair did not catch every time, and a genuine balance cannot be told apart from a fabricated one, so genuine values are withheld on those rows too. The same wallet's HL rows in the same snapshot keep the value; only its builder-DEX rows read NULL. |
pnl_cohort | String | Realized-PnL percentile cohort of the wallet AS OF THE START OF THE ROW'S CLOCK HOUR: graded on fills strictly before the row's hour (the hourly label of the previous hour). This is ONE HOUR EARLIER than the label /v1/hyperliquid/positions returns for the same row in historical mode (start given), where a row graded from the hourly label table carries pnl_cohort_basis = point_in_time: that label is the row's own hour and so counts the fills of up to 59 minutes after the row. In latest, as of the start of the hour of the file's newest snapshot (an older hour while the label rollup lags), so on the rows of positions that closed in the last 15 minutes it can count up to 15 minutes of fills after the row. unknown for a wallet with fewer than 10 closed trades then, or with no realized record that hour; never empty. |
opened_at, which /v1/hyperliquid/positions fills in per page, is not in these files. The latest file has
the same 19 columns.
Related
/archive/url— the temporary link to one of these files.- Download the Hyperliquid file archive — fetch a file and read it.
/positions— the same positions through the API, current or by window, cursor-paged./wallets/{address}/fills— one wallet's fills through the API.
Download the Hyperliquid file archive
Ask for a temporary link, download one whole Parquet file, then read it locally with DuckDB, pyarrow or pandas — fills and 5-minute position snapshots by UTC day, and the latest positions file — with the traps that cost a wrong number.
Archive download link
Asks for a temporary download link to one Hyperliquid archive file — a fills or positions day, or the 5-minute latest positions file. The link needs no key, names exactly one file and works for 300 seconds.