Skip to main content

Hyperliquid (HyperCore) Data

Bitquery provides Hyperliquid Core Parquet exports from the Bitquery Data Store, 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: the Data Store lists the last 30 days on all seven tables. Older ranges are available on request from sales@bitquery.io.
  • More order flow than the API: the Hyperliquid GraphQL API keeps about 30 days of trades, liquidations, funding, TWAPs and prices, but only about 7 days of raw order updates and book updates. The Data Store listing has order and book updates as far back as trades.
  • Freshness: a delivery covers data up to the day before the files are prepared.
  • 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 Data Store lists the last 30 days, on every table, so you can replay roughly a month of live HyperCore, including any HIP-3 market that launched inside that window. Older ranges are available on request from sales@bitquery.io. The data has known gaps of about an hour each in September and October 2026, listed on request.

The Hyperliquid API keeps about 30 days of trades, liquidations, funding, TWAPs, prices and candles, and about 7 days of raw orders, book updates and signed actions. A query for anything earlier returns an empty result. For older history, ask sales@bitquery.io for an older range as a Data Store export.

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

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

hyperliquid-archive and mirrorsBitquery Data Store export
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 HIP-3 market, plus the inputs behind them
HistoryVaries by bucket, no completeness guaranteeLast 30 days on the Data Store; older ranges on request
FreshnessRoughly monthly uploadsUp to the day before delivery

Queue position, order lifetime, maker behaviour, spoofing patterns, and why a liquidation fired are only recoverable from this shape of data. Hyperliquid's separate s3://hl-mainnet-node-data bucket does carry raw node fills and misc events (funding among them) as node JSON, but no order statuses or book diffs.

Hyperliquid Data for Tax Reporting​

Tax reports need every trading event a wallet produced. The dataset carries fills, liquidations, TWAP fills and funding, so you, your accountant or your tax software can compute gains, losses and income for any wallet. The Data Store lists the last 30 days. A full tax year or other past range can be requested from sales@bitquery.io.

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_TwapId > 0 (the TWAP owner's side; Trade_IsTwap = 1 also marks the counterparty), 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. Parquet files that load into 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, email sales@bitquery.io or fill the API form.

Get Full Access​

A Data Store purchase is downloaded from a Requester Pays S3 bucket or a Cloudflare R2 bucket, chosen at checkout. Custom exports can be delivered into your own S3, GCS or R2 bucket, or as a Snowflake or BigQuery share. To buy or trial it, go to the Bitquery Data Store, contact sales@bitquery.io or fill the API form.

For the raw HyperCore feed from 17 July 2026, which you decode and parse your own way, see the Blockchain Data Lake.

Datasets listed on the Data Store (last 30 days). Other ranges and table combinations are available on request:

Available Hyperliquid Tables​

TableGrainWhat it holds
tradesone row per side of each match, liquidations exceptedPrice, size, direction, taker flag, fees, signed position before and after the fill, execution order, 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, for HIP-3 markets only
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 has the same columns as a full delivery.

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 samples were exported on 30 September 2026, before Trade_Execution_Index, Liquidation_Execution_Index and Order_Index existed and before Trade_Position_Size was filled in. New exports carry all four.

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
_Execution_* (trades, perp_liquidations)Side, Direction, IsAggressor, Price, Size, Oid, Cloid, Tid, Hash, EventTime, Index

Some of these are never filled in a given table (for example Trade_Position_EntryPrice, Trade_Position_Funding 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​

Six 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. The maker and taker rows of a match share the Tid. It identifies the match but is not a sequence number: see note 6 for ordering.

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.

6. Order Fills Inside a Block by Index, Not Tid​

All rows of one block share Block_Time, and Trade_Execution_Tid is a hash-like identifier, so sorting by either scrambles the fills of a busy block. The index columns give the exchange's own order:

  • Trade_Execution_Index and Liquidation_Execution_Index give the row's place in the block's fills, counting from 1. They form one sequence across both tables, so trades and liquidations of a block interleave correctly. Each side of a match has its own index.
  • Order_Index does the same for the order status changes of a block, which also share Order_EventTime.
  • BookUpdate_Index is the replay order of book changes.

To replay an account's position, merge both fill tables and sort by block, then index:

SELECT * FROM (
SELECT Block_Number, Trade_Execution_Index AS idx, 'trade' AS kind, Trade_Trader_Address AS account,
Trade_Execution_Side AS side, Trade_Execution_Size AS size, Trade_Position_Size AS position_after
FROM hyperliquid_trades WHERE Trade_Market_CoinRaw = 'BTC'
UNION ALL
SELECT Block_Number, Liquidation_Execution_Index, 'liquidation', Liquidation_Trader_Address,
Liquidation_Execution_Side, Liquidation_Execution_Size, Liquidation_Position_Size
FROM hyperliquid_perp_liquidations WHERE Liquidation_Market_CoinRaw = 'BTC'
) fills
ORDER BY Block_Number, idx

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.

One exception: PURR/USDC is a spot pair, but its Kind reads perp and its IsPerp is 1. Exclude it by name when you need perpetuals only.

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_Position_Size is the signed position after the fill. For perps it is SizeBefore plus Size on a Buy, or minus it on a Sell. For spot it is the base-token balance after the fill, net of a fee charged in that token, and can be empty.
  • Trade_Execution_Index is the fill's place in its block; see note 6.
  • 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; keep the rows where Liquidation_Trader_Address = Liquidation_LiquidatedUser for the liquidated side only.
  • Sign a liquidation fill like a trade, by Liquidation_Execution_Side: a Buy adds to that row's account position and a Sell subtracts. Liquidation_Position_SizeBefore and Liquidation_Position_Size are the position before and after the fill.
  • Liquidation_MarkPx and Liquidation_Method (for example market) come from the node. Liquidation_Liquidator is always empty.

twaps​

  • Twap_State_Status is activated, waitingForTrigger, finished, terminated, stopped 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.
  • Order_Index orders the status changes inside a block, where they all share Order_EventTime.

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​

  • The table covers HIP-3 markets only: the node publishes oracle updates for builder-deployed dexes, not for plain perps such as BTC or HYPE.
  • 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 for a HIP-3 market 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 of orders that reached 'filled'
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​

Parquet exports are optimized for batch analytics and historical workloads.

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

The Parquet columns are the live stream's fields flattened with _ (Trade.Execution.Price becomes Trade_Execution_Price), so logic written against one maps field for field onto the other.

Buy the Full Dataset​

The public samples above are a few hundred rows. A Data Store purchase is downloaded from a Requester Pays S3 bucket or a Cloudflare R2 bucket, chosen at checkout. Custom exports can be delivered into your own S3, GCS or R2 bucket, or as a Snowflake or BigQuery share. A Data Store purchase covers the last 30 days. Older history and custom ranges are available through sales@bitquery.io.

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.