Skip to main content

Hyperliquid (HyperCore) Data

Bitquery provides Hyperliquid Core data dumps in Parquet format, designed for backtesting, market microstructure research, and data lake integrations. These datasets can be hosted directly in your own cloud storage (for example, AWS S3) and queried using engines like Snowflake, BigQuery, Athena, Spark, etc.

This dataset covers HyperCore, the L1 order-book exchange, not HyperEVM state. It is an event stream, not a state chain: there are no blocks, transactions or transfers tables. Every row is an exchange event (a fill, an order status change, a book delta, an oracle price, a funding payment), and every row carries Block_Number and Block_Time, so tables join on block without a separate blocks table.

Coverage & Freshness​

  • History: a rolling window of the last 30 days, across all seven tables. Older blocks are trimmed by whole UTC day.
  • Same window as the API: the Hyperliquid GraphQL API and streams also keep the last 30 days. The difference is shape and delivery, not depth.
  • Freshness: the archive is written from the same pipeline as our live streams, so the cloud export can follow new blocks as they are produced. A Data Store purchase is a one-time set of files covering the 30 days up to the day before we prepare them.
  • Markets: plain perpetuals, HIP-3 builder-deployed perps, spot pairs, and outcome/prediction tokens. See Markets for how they share one column.

How Much History Is Included?​

The last 30 days, on every table. The window rolls forward each UTC day, so at any moment you can replay roughly a month of live HyperCore, including any HIP-3 market that launched inside that window. Blocks older than 30 days are not in the dataset.

The Hyperliquid cube on the streaming API has the same 30-day window, and a query for anything earlier returns an empty result. If you need to keep more than 30 days, land the Parquet files in your own bucket as they arrive and they stay there for as long as you want.

How Is This Different From Hyperliquid's Free S3 Archive?​

Hyperliquid's own archive (and free mirrors of it) publishes L2 snapshots and asset contexts. This dataset is a different shape:

Free archives (HL S3, Reservoir)Bitquery cloud dataset
Order bookL2 snapshots (price levels, fixed cadence)L4 per-order updates with owner address and order id, every change
OrdersNot includedFull lifecycle: opens, cancels, every reject reason, TP/SL children
FillsNot includedBoth sides of every match, realized PnL, fees, builder and deployer fees
LiquidationsNot includedBoth sides, with the liquidated account, mark price and method
FundingNot includedEvery account's payment at each hourly settlement
OracleNot includedMark, oracle and external perp prices per coin, plus the inputs behind them
HistoryVaries by bucket, no completeness guaranteeRolling last 30 days (keep your own copies to build a longer archive)
FreshnessRoughly monthly uploadsFollows the chain

Queue position, order lifetime, maker behaviour, spoofing patterns, and why a liquidation fired are only recoverable from this shape of data.

Hyperliquid Data for Tax Reporting​

Tax reports need every trading event a wallet produced. The dataset carries the last 30 days of fills, liquidations, TWAP fills and funding, so you, your accountant or your tax software can compute gains, losses and income for any wallet inside that window. To cover a full tax year, keep the files as they land in your bucket and the archive builds itself.

Tax inputBitquery table
Realized PnL on every closed positiontrades and perp_liquidations: *_Position_RealizedPnl
Trading fees, including builder and HIP-3 deployer feestrades and perp_liquidations: *_Fees_Fee, _FeeToken, _BuilderFee, _DeployerFee
Funding paid and receivedperp_fundings: Funding_Amount
Liquidationsperp_liquidations
TWAP executions, fill by filltrades where Trade_IsTwap = 1, with twaps for the parent order
Spot buys and sells for cost basistrades where Trade_Market_Kind = 'spot'

Deposits, withdrawals and transfers between accounts are not in the export today.

Why teams use it for tax work:

  • Nothing dropped from trading. Funding, TWAP child fills and liquidations are included alongside regular trades, so PnL reconciles.
  • Exact amounts. Prices, sizes, PnL and fees are stored as decimal strings, so no precision is lost to floating point.
  • Works with your stack. Delivered to S3, GCS, Snowflake or BigQuery. Query one wallet or thousands with SQL, then export to CSV for tax software.

Built for tax platforms, accountants and funds reconciling Hyperliquid activity, as well as individual traders with high trade counts. To get the full dataset, buy it from the Bitquery Data Store, fill the API form or email sales@bitquery.io.

Get Full Access​

The full dataset is delivered into your own cloud storage (S3, GCS) or warehouse share (Snowflake, BigQuery). To buy or trial it, go to the Bitquery Data Store, fill the API form or contact sales@bitquery.io.

Datasets you can buy on the Data Store, as one-time files covering the last 30 days:

Available Hyperliquid Tables​

TableGrainWhat it holds
tradesone row per side of each match, liquidations exceptedPrice, size, direction, taker flag, fees, signed position before the fill, realized PnL, TWAP link
perp_liquidationsone row per side of each liquidation matchThe same fields as trades, plus the liquidated account, mark price and method
twapsone row per TWAP status changeTotal size, executed size and notional, duration, status and error text
order_updatesone row per order status changeFull lifecycle: open, canceled, filled, triggered and every *Rejected state, with TIF, triggers and TP/SL children
book_updatesone row per L4 change of a single ordernew, update or remove, each with the owning address, order id, price and size
price_updatesone row per coin and price kind in each oracle pushResulting mark, oracle and external perp prices, and the inputs behind them
perp_fundingsone row per account and market at each hourly settlementFunding rate, signed position size, USDC paid or received

Pick trades for executed volume and realized PnL, order_updates for intent and rejection analysis, and book_updates when you need to rebuild the book at an arbitrary block.

Why L4 Matters​

An L2 snapshot tells you the book was 12 deep at a price; an L4 stream tells you which order moved and whose it was. Likewise, order_updates includes orders that never traded. Rejects and cancels are invisible in any trades-only dataset, and in the sample below they are most of the order events.

Sample Hyperliquid Cloud Dataset​

You can explore schemas and validate your tooling using the public Hyperliquid sample datasets:

GitHub reference (schemas & examples) https://github.com/bitquery/blockchain-cloud-data-dump-sample/tree/main/hyperliquid

Sample Parquet downloads (public S3)

Every sample is written by the same exporter that produces a delivery, with every column.

TableRowsSourceDownload
trades100first rows of pack 1165214000–11652149991165214001_1165214024.parquet
twaps7every TWAP status in the same pack1165214012_1165214910.parquet
perp_fundings100the settlement in block 11652144671165214467_1165214467.parquet
order_updates100first rows from block 10780000001078000000_1078000000.parquet
book_updates100first rows from block 10780000001078000000_1078000001.parquet
price_updates100first rows from block 10780000001078000012_1078000012.parquet

perp_liquidations has no public sample; liquidations are rare, and its columns match trades plus Liquidation_MarkPx, Liquidation_Method and Liquidation_LiquidatedUser.

The figures on this page come from the full export of two 1,000-block packs, not only the small samples: pack 1165214000–1165214999 (29 September 2026) held 11,082 trade rows, 7 TWAP statuses and one funding settlement of 411,880 rows across 327 markets, and pack 1078000000–1078000999 (19 July 2026) held 321,282 order updates, 193,903 book updates and 22,696 price updates.

Hyperliquid Dataset Directory Structure​

bitquery-blockchain-dataset/
└── hyperliquid/
├── trades/
├── perp_liquidations/
├── twaps/
├── order_updates/
├── book_updates/
├── price_updates/
└── perp_fundings/
├── <start_block>_<end_block>.parquet
└── ...

Each file name gives the first and last block it holds. HyperCore produces roughly 14 blocks per second. File sizes track activity rather than block count, so size a download from the delivery manifest rather than from the block range.

A range with no events produces no file. Sparse tables such as twaps, perp_liquidations and perp_fundings (one settlement an hour) skip ranges, so discover files under a prefix rather than generating names from a stride.

Common Columns​

Every table starts with the same block columns and ends with the same bookkeeping columns:

ColumnTypeDescription
ChainIdstringAlways hyperliquid-core
Block_Numberuint64HyperCore block height; the join key across tables
Block_Timeint64Block timestamp, epoch nanoseconds
Indexing_Timeint64When our pipeline indexed the block, epoch nanoseconds
Indexing_OnTree, Indexing_OnTrunkuint81 when the block was on our block tree and finalized chain
Recording_Timeuint32When the row was written, epoch seconds
Recording_Hashuint64Row hash used to drop duplicates
Block_DatedateUTC date of the block, handy for partitioning

Each table then prefixes its own fields with its entity name: Trade_*, Liquidation_*, Twap_*, Order_*, BookUpdate_*, PriceUpdate_*, Funding_*. Nested structures are flattened with _, for example Trade_Execution_Price and Order_Market_CoinRaw. The trading tables share these groups:

GroupColumns
_Trader_*Address, Signer, Vault, Broadcaster, SignedAt
_Market_*Symbol, Kind, Protocol, CoinRaw, IsPerp, MaxLeverage
_Position_*Side, Size, SizeBefore, EntryPrice, RealizedPnl, Funding, Leverage, IsCross, Closed

Some of these are never filled in a given table (for example Trade_Position_EntryPrice or Trade_MarkPx), and signer, vault and leverage fields are filled only when the source data carries them. The listing on the Data Store says, per column, when it can be empty.

Correctness Notes​

Five things about this dataset will silently produce wrong numbers if you treat it like an EVM chain export.

1. Money Is Strings​

Prices, sizes, PnL, fees and funding amounts are stored as decimal strings, not numerics. This is deliberate: exchange decimals must not pass through a float. Block numbers, ids and timestamps are integers. Use Decimal rather than float for money:

from decimal import Decimal
df["px"] = df.Trade_Execution_Price.map(Decimal)

Summing Trade_Execution_Price as float across a large export will drift; Decimal will not.

2. Every Match Appears Twice​

trades carries one row per side, so a single match produces two rows, one taker and one maker. In the 29 September pack, 11,082 trade rows are 5,548 with Trade_Execution_IsAggressor = 1 and 5,534 with 0, resolving to 5,555 unique (Block_Number, Trade_Market_CoinRaw, Trade_Execution_Tid) keys.

Summing Trade_Execution_Size across the raw table double-counts volume. Filter to one side:

SELECT SUM(CAST(Trade_Execution_Size AS DECIMAL(38,8)))
FROM hyperliquid_trades
WHERE Trade_Execution_IsAggressor = 1 -- taker side only

Liquidation fills are not in trades; they are only in perp_liquidations. Include both tables for complete volume and PnL.

3. Trade_Execution_Hash Is Not a Join Key​

One L1 transaction spans many matches, and TWAP fills carry 32 zero bytes. In the same pack, 11,082 rows share only 2,938 distinct hashes, and 1,296 rows (the TWAP fills, Trade_IsTwap = 1) have an all-zero hash.

Key matches on (Block_Number, Trade_Market_CoinRaw, Trade_Execution_Tid) instead.

4. Rejected Orders Dominate order_updates​

order_updates is a record of intent, and most intent never trades. The 19 July pack's 321,282 order events break down as:

StatusRecords
badAloPxRejected108,952
open95,735
canceled91,148
perpMarginRejected15,373
reduceOnlyCanceled3,875
iocCancelRejected3,505
insufficientSpotBalanceRejected1,299
filled1,118
minTradeNtlRejected121
reduceOnlyRejected101
selfTradeCanceled48
tooManyOpenOrdersRejected6
triggered1

Only 1,118 of 321,282 events, about 0.35%, are filled. badAloPxRejected alone is a third of the file: post-only (Alo) orders priced through the book, rejected rather than crossed. Alo is 313,186 of the 321,282 Order_Tif values, so this table is dominated by market makers quoting and requoting. Order_IsReject = 1 flags every *Rejected state.

Filter on Order_Status for whatever you are measuring; never treat row count as order flow.

5. Time Units Differ by Field​

Two different epochs are in play, and mixing them is a factor-of-a-million error:

FieldUnit
Block_Time, Order_EventTime, Twap_Interval_EventTimenanoseconds
Trade_Execution_EventTime, Liquidation_Execution_EventTimemilliseconds
Order_PlacedTime, Twap_Interval_StartTimemilliseconds
Recording_Timeseconds

In the sample, the same fill carries Block_Time = 1790672366376122193 and Trade_Execution_EventTime = 1790672366376.

Markets​

*_Market_CoinRaw covers four market types in one column, and *_Market_Kind names the type so you do not have to parse the prefix:

CoinRawKindMeaningTrade rows (29 Sep pack)Order events (19 Jul pack)
HYPE, BTCperpPlain perpetual6,406258,980
xyz:DRAMhip3HIP-3 builder-deployed perp4,04450,963
@107spotSpot pair, by index52410,603
#1890outcomeOutcome / prediction token108736

*_Market_Protocol is hypercore for plain perps, spot and outcome tokens, and the deploying dex (such as xyz) for HIP-3 markets. HIP-3 perps were 36% of trade rows in the 29 September pack, so leaving them in a "Hyperliquid perps" aggregate will not give you the numbers you expect.

Table Notes​

The full column list for every table, with a description of each column, is on the Data Store listings. The points below are the ones that matter when you query.

trades​

  • Trade_Execution_Side is Buy or Sell for this side; Trade_Execution_Direction is the node's label: Open Long, Close Short, Long > Short, Buy, Sell and so on.
  • Trade_Position_SizeBefore is the signed position before the fill (negative is short), not money. Trade_Position_RealizedPnl is the realized PnL of the fill in USDC. It was non-zero on 5,277 of the 11,082 rows in the 29 September pack.
  • Trade_Fees_Fee is negative when the maker received a rebate. Trade_Fees_FeeToken was USDC on 10,743 of those rows.
  • Trade_TwapId joins to Twap_TwapId.

perp_liquidations​

  • Each liquidation match has two rows, one for the liquidated account and one for the counterparty. Liquidation_LiquidatedUser names the liquidated account on both.
  • Liquidation_MarkPx and Liquidation_Method (for example market) come from the node. Liquidation_Liquidator is always empty.

twaps​

  • Twap_State_Status is activated, finished, terminated or error, with the error text in Twap_State_StatusError.
  • Twap_Order_Size is the total to execute; Twap_State_ExecutedSize and Twap_State_ExecutedNotional are the running totals.

order_updates​

  • Order_Oid joins to Trade_Execution_Oid and BookUpdate_Oid.
  • Order_ParentOid and Order_Leg link take-profit and stop orders to the order they are attached to.

book_updates​

  • BookUpdate_Kind is new (95,060 rows in the 19 July pack), remove (95,456) or update (3,387).
  • BookUpdate_Size is the order's size on new and the size after the change on update; BookUpdate_SizeBefore is the size before an update.
  • Replay in Block_Number then BookUpdate_Index order to reconstruct the book at any block.

price_updates​

  • PriceUpdate_Kind says which price the row is: mark, oracle or extPerp for the resulting prices, markInput, spotInput or extPerpInput for the inputs.
  • Oracle prices drive funding and liquidation, so join these to perp_liquidations on Block_Number when reconstructing why a liquidation fired.

perp_fundings​

  • Funding_Amount is the USDC the account received, negative when it paid. Funding_Size is the signed position, negative for a short. With a positive Funding_Rate, longs pay shorts.

Joining Tables​

Every table carries Block_Number, and the order id threads the trading tables together:

-- taker fills with the order that produced them
SELECT
t.Trade_Market_CoinRaw,
t.Trade_Execution_Price,
t.Trade_Execution_Size,
t.Trade_Position_RealizedPnl,
o.Order_Tif,
o.Order_ReduceOnly
FROM hyperliquid_trades t
JOIN hyperliquid_order_updates o
ON t.Trade_Execution_Oid = o.Order_Oid
AND o.Order_Status = 'filled'
WHERE t.Trade_Execution_IsAggressor = 1

Because one order produces many status events and many fills, join on the order id plus a status filter, or aggregate one side first; otherwise you get a cross product.

Reading Files with DuckDB​

No key, no client library. Point DuckDB at the public sample directly:

SELECT Trade_Market_CoinRaw,
SUM(CAST(Trade_Execution_Size AS DECIMAL(38,8)) * CAST(Trade_Execution_Price AS DECIMAL(38,8))) AS notional
FROM read_parquet('https://bitquery-blockchain-dataset.s3.us-east-1.amazonaws.com/hyperliquid/trades/1165214001_1165214024.parquet')
WHERE Trade_Execution_IsAggressor = 1 -- taker side only, see Correctness Notes
GROUP BY Trade_Market_CoinRaw
ORDER BY notional DESC
LIMIT 10;

Reading Files in Python​

import pandas as pd
from decimal import Decimal

BASE = "https://bitquery-blockchain-dataset.s3.us-east-1.amazonaws.com/hyperliquid/"

trades = pd.read_parquet(f"{BASE}trades/1165214001_1165214024.parquet")
orders = pd.read_parquet(f"{BASE}order_updates/1078000000_1078000000.parquet")

# taker side only: every match is in the file twice
taker = trades[trades.Trade_Execution_IsAggressor == 1]
taker = taker.assign(
px=taker.Trade_Execution_Price.map(Decimal),
sz=taker.Trade_Execution_Size.map(Decimal),
)
print("matches:", len(taker), "of", len(trades), "trade rows")
print("notional:", (taker.px * taker.sz).sum())

# realized PnL net of fees, by wallet
net = trades.assign(
pnl=trades.Trade_Position_RealizedPnl.map(Decimal) - trades.Trade_Fees_Fee.map(Decimal)
).groupby("Trade_Trader_Address").pnl.sum()
print(net.sort_values().tail())

# order flow is mostly rejects, not trades
print(orders.Order_Status.value_counts().head())

Real-Time vs Batch Data Access​

Cloud data dumps are optimized for batch analytics and historical workloads.

If you require low-latency or streaming Hyperliquid data, Bitquery also provides:

The Parquet exports and the live streams share the same field definitions, so a backtest reading this archive and a production consumer reading the stream decode with the same code.

Buy the Full Dataset​

The public samples above are a few hundred rows. The full product is the rolling 30-day history, delivered into your own S3/GCS bucket or as a Snowflake/BigQuery share. A Data Store purchase is a one-time set of files covering the last 30 days.

Build with Bitquery

Ready to run this in production?

Get an API key and run these queries in minutes, or talk to us about plans and enterprise delivery.