Skip to main content

Hyperliquid Snapshots API

About every 12.5 minutes, Bitquery takes a snapshot of the full Hyperliquid exchange state and serves it through eleven Snapshot* cubes: every open position with its entry price, leverage, margin and unrealized PnL, every account, every resting order with its owner, every waiting stop and take-profit order, every spot balance, every leverage setting, every vault with its depositors, and Earn. All accounts at once, kept for 7 days.

Hyperliquid's own info API returns this state one address at a time (clearinghouseState, openOrders, spotClearinghouseState), so you have to know the address first. Snapshots answer the market-wide questions: who holds the biggest positions and at what entry, how the crowd is positioned against the whales, where the stops sit, who owns the walls in the book, who holds a token.

Window and update rate

Snapshots are kept for about 7 days. A new snapshot appears about every 12.5 minutes. The cubes are query-only: there is no subscription, so poll at that pace and compare Block.Number to see whether a new snapshot has arrived.

API Key Required

To query or stream data outside the Bitquery IDE, you need an API access token.

Follow the steps here: How to generate Bitquery API token ➤

The snapshot cubes​

CubeOne row perUse it for
Snapshotssnapshotthe list of snapshots in the window: Block { Number Time }
SnapshotMarketsmarketmark, oracle and external perp prices, best bid and ask, last trade, open interest, number of positions, margin tiers, halts, prediction market names
SnapshotPositionsopen perp position (trader × market)side, size, entry price, leverage, margin, position value, unrealized PnL, cumulative funding
SnapshotAccountsaccount × perp dexaccount value, margin used, maintenance margin, notional, number of positions
SnapshotOrdersresting order or waiting trigger orderthe order book with owners (L4), queue position, stop-loss and take-profit orders
SnapshotBalancesnon-zero spot balance (trader × token)token holders, spot portfolios, entry notional
SnapshotLeverageSettingstrader × perp market the trader touchedleverage and margin mode set, and what the next trade gets
SnapshotVaultsvaultname, leader, equity, number of followers, commission, parent and child vaults
SnapshotVaultFollowersdepositor × vaultshare, equity, net deposit, all-time PnL, lockup
SnapshotEarnReservesEarn tokensupplied, borrowed, utilization, rate model
SnapshotEarnPositionstrader × Earn tokensupply and borrow, basis and value

A vault trades as its own account: its positions, margin and orders are the rows whose Trader.Address is the vault address, and IsVault: true marks them.

Which snapshot a query reads​

The time filter on Block.Time decides which snapshots answer:

FilterReads
no Block.Time filterthe latest complete snapshot
Block: {Time: {at: "..."}} with a time in the last 7 daysthe latest complete snapshot at or before that time: the state at that moment
Block: {Time: {since: "...", till: "..."}} (or any other range)every complete snapshot in the range: a history

A query only ever sees complete snapshots. All rows of one snapshot share Block.Number and Block.Time, so add Block { Number Time } to know which one answered. A Block.Number filter narrows what Block.Time selected: on its own it meets only the latest snapshot, so for an older height add Time too, or use at.

List the snapshots of the last few hours:

query {
Hyperliquid {
Snapshots(
where: {Block: {Time: {since_relative: {hours_ago: 3}}}}
orderBy: {descending: Block_Time}
) {
Block { Number Time }
}
}
}

Biggest positions with entry price and unrealized PnL​

The largest positions on BTC by value, long and short, with entry price, leverage, margin mode, unrealized PnL and the funding paid since the position was opened. Position.Size is signed (negative = short), so rank by Valuation.PositionValue, the position's USD value at the snapshot's mark price.

query {
Hyperliquid {
SnapshotPositions(
where: {Market: {CoinRaw: {is: "BTC"}}}
orderBy: {descending: Valuation_PositionValue}
limit: {count: 20}
) {
Block { Number Time }
Trader { Address }
IsVault
Position { Side Size EntryPrice Leverage IsCross }
Valuation { EntryNotional PositionValue UnrealizedPnl MarkPx }
CumFunding { SinceOpen AllTime }
Margin { MarginUsed MaintenanceMargin }
}
}
}
  • CumFunding is positive when the account paid funding and negative when it received it: the opposite sign to Funding.Amount on PerpFundings.
  • Position.Leverage is the leverage of the position, so grouping by it shows how leveraged a market is. SnapshotLeverageSettings is the per-account setting, including markets with no open position.
  • Filter Position: {Side: {is: "Short"}} for the shorts alone, or Trader: {Address: {is: "0x..."}} for one account.

Crowd vs whales: the long / short split of a market​

Group the positions of one market by side: how many accounts are long and short, the total size and value of each side, and their unrealized PnL. A side with most of the accounts but a smaller share of the value is the crowd; the other is where the large positions are.

query {
Hyperliquid {
SnapshotPositions(where: {Market: {CoinRaw: {is: "BTC"}}}) {
Position { Side }
positions: count
size: sum(of: Position_Size)
value: sum(of: Valuation_PositionValue)
upnl: sum(of: Valuation_UnrealizedPnl)
}
}
}

The same split over time: with a since filter every snapshot answers, and grouping by Block.Time gives one row per snapshot.

query {
Hyperliquid {
SnapshotPositions(
where: {Market: {CoinRaw: {is: "BTC"}}, Block: {Time: {since_relative: {days_ago: 3}}}}
orderBy: {ascending: Block_Time}
limit: {count: 2000}
) {
Block { Time }
longs: count(if: {Position: {Side: {is: "Long"}}})
shorts: count(if: {Position: {Side: {is: "Short"}}})
longValue: sum(of: Valuation_PositionValue, if: {Position: {Side: {is: "Long"}}})
shortValue: sum(of: Valuation_PositionValue, if: {Position: {Side: {is: "Short"}}})
}
}
}

Open interest and prices of every market​

SnapshotMarkets has one row per market: prices, the top of the book, open interest and the number of open positions.

query {
Hyperliquid {
SnapshotMarkets(
where: {Market: {IsPerp: true}}
orderBy: {descending: Positions}
limit: {count: 50}
) {
Block { Number Time }
Market { Symbol CoinRaw Kind Protocol MaxLeverage }
Prices { MarkPx OraclePx ExternalPerpPx }
Book { BestBid BestAsk LastTradePx Orders }
OpenInterest
Positions
IsHalted
}
}
}
  • OpenInterest counts both sides: it is longs plus shorts, in coins (the sum of the absolute size of every position), so it is twice the open interest of one side. Divide by 2 for the figure most venues quote, and multiply by Prices.MarkPx for USD.
  • Margin, Prices and OpenInterest are perp-only (native and HIP-3) and empty on spot and prediction markets.
  • Margin { Tiers { LowerBound MaxLeverage MaintenanceDeduction } } are the margin tiers: from LowerBound of position notional (USD) on, MaxLeverage applies.

Stop-loss and take-profit map​

Waiting trigger orders (IsTrigger: true) are not in the public book, so no L2 feed shows them. In a snapshot every one is listed with its owner: where the stops and take-profits of a market sit, and whose they are.

query {
Hyperliquid {
SnapshotOrders(
where: {Market: {CoinRaw: {is: "BTC"}}, IsTrigger: true, TriggerPx: {ge: "70000", le: "85000"}}
orderBy: {descending: Size}
limit: {count: 1000}
) {
Block { Time }
Trader { Address }
Side OrderType TriggerPx TriggerCondition LimitPx Size OrigSz IsPositionTpsl ReduceOnly
}
}
}
  • TriggerCondition is text (Price below 76000); filter and sort on TriggerPx, the number.
  • A position TP/SL (IsPositionTpsl: true) closes the whole position, so its Size is 0: take the size from the owner's position in SnapshotPositions.
  • Group by TriggerPx and Side with count and sum(of: Size) for a histogram of stop levels; position TP/SLs add to the count but not to the size.

Order book walls and their owners​

Resting orders (IsTrigger: false) are the book at the snapshot, order by order, with the owner of each. The largest orders on each side:

query {
Hyperliquid {
SnapshotOrders(
where: {Market: {CoinRaw: {is: "BTC"}}, IsTrigger: false}
orderBy: {descending: Size}
limit: {count: 50}
) {
Block { Time }
Trader { Address }
IsVault
Side LimitPx Size OrigSz OrderType Tif QueuePosition PlacedTime Oid
}
}
}

Side is Buy (bid) or Sell (ask); Size is what remains, OrigSz what was placed. QueuePosition is the order's place at its price level, 1 being filled first. PlacedTime is epoch milliseconds. Between snapshots, follow the same orders by Oid on the Orders and BookUpdates cubes.

Token holders​

SnapshotBalances lists every non-zero spot balance. The largest HYPE holders:

query {
Hyperliquid {
SnapshotBalances(
where: {Token: {is: "HYPE"}}
orderBy: {descending: Total}
limit: {count: 100}
) {
Trader { Address }
Total
Hold
EntryNotional
}
}
}

Hold is the part of Total locked in open orders; EntryNotional is the USDC paid for Total, so EntryNotional / Total is the average entry. There is no USD value: Hyperliquid publishes none. System addresses (0x2222…2222, 0xfefe…fefe) can top the list. count with no other fields gives the number of holders.

Vaults: equity, followers and positions​

query {
Hyperliquid {
SnapshotVaults(orderBy: {descending: Summary_Equity}, limit: {count: 25}) {
Vault
Name
Leader
Summary { Equity Followers LeaderFraction }
Terms { LeaderCommission LockupSeconds AllowDeposits IsClosed }
Relationship { Type ChildVaults }
}
}
}

The depositors of a vault are in SnapshotVaultFollowers (filter Vault: {is: "0x..."}: Trader { Address }, IsLeader, Share { Fraction Equity NetDeposit AllTimePnl }, Times { EntryTime LockupUntil }), and its open positions are SnapshotPositions with the vault address as Trader.Address. See the Vaults API for vault fills, deposits and liquidations.

One account: its portfolio at a moment and its history​

Several cubes can go in one query: the account's margin per dex, its open positions, spot balances and orders at the latest snapshot. For the state at a past moment, add Block: {Time: {at: "..."}} with a time from the last 7 days to each cube, so all of them read the same snapshot.

query {
Hyperliquid {
SnapshotAccounts(
where: {Trader: {Address: {is: "0x5b5d51203a0f9079f8aeb098a6523a13f298c060"}}}
) {
Block { Number Time }
Protocol
Collateral
Total { AccountValue MarginUsed TotalNotional }
Positions
}
SnapshotPositions(
where: {Trader: {Address: {is: "0x5b5d51203a0f9079f8aeb098a6523a13f298c060"}}}
) {
Market { Symbol CoinRaw }
Position { Side Size EntryPrice Leverage IsCross }
Valuation { PositionValue UnrealizedPnl }
}
SnapshotBalances(
where: {Trader: {Address: {is: "0x5b5d51203a0f9079f8aeb098a6523a13f298c060"}}}
) {
Token
Total
EntryNotional
}
SnapshotOrders(
where: {Trader: {Address: {is: "0x5b5d51203a0f9079f8aeb098a6523a13f298c060"}}}
) {
Market { CoinRaw }
Side OrderType LimitPx TriggerPx Size IsTrigger
}
}
}

The native exchange (Protocol hypercore) and each HIP-3 dex keep separate margin, each in its own Collateral token, so an account has one SnapshotAccounts row per dex. Total is the account's margin summary, Cross the cross-margin part.

The account value over the last week, one point per snapshot:

query {
Hyperliquid {
SnapshotAccounts(
where: {Trader: {Address: {is: "0x5b5d51203a0f9079f8aeb098a6523a13f298c060"}}, Protocol: {is: "hypercore"}, Block: {Time: {since_relative: {days_ago: 7}}}}
orderBy: {ascending: Block_Time}
limit: {count: 1000}
) {
Block { Time }
Total { AccountValue MarginUsed TotalNotional }
Positions
}
}
}

The account's vault shares are in SnapshotVaultFollowers and its Earn supply and borrow in SnapshotEarnPositions, both filtered by Trader: {Address: {is: "0x..."}}.

Earn: supply, borrow and utilization​

query {
Hyperliquid {
SnapshotEarnReserves {
Block { Time }
Token
TotalSupplied
TotalBorrowed
Utilization
Ltv
RateModel { BaseRate KinkUtilization MaxRate ProtocolShare }
}
}
}

Amounts are in the token. The borrow rate is BaseRate up to KinkUtilization, then rises linearly to MaxRate at full utilization; suppliers earn the borrow rate × Utilization × (1 − ProtocolShare).

Snapshots vs CurrentPositions​

SnapshotPositionsCurrentPositions
Freshnessthe state at the latest snapshot, up to ~12.5 minutes oldupdated with every fill and hourly funding
Contententry price, margin, position value, unrealized PnL, cumulative funding over the position's lifesize, leverage, margin mode; funding and realized PnL summed over the data window
Historyevery snapshot of the last 7 days, or the one at a momentthe latest state only
Sorting by sizenumericSize sorts as text

Use snapshots for the full state and its history, and the event cubes (Trades, Orders, PerpLiquidations) for what happened between two snapshots.

Pitfalls​

  • Open interest is doubled. SnapshotMarkets.OpenInterest adds longs and shorts; one side is half of it.
  • Shorts are negative. Position.Size is signed; sort by Valuation.PositionValue to rank by size, and do not sum Position.Size across both sides expecting open interest.
  • Ranges multiply rows. A since filter returns every snapshot in it, about 115 a day: aggregate (count, sum) per Block.Time, or use at for one moment.
  • Only the address. Snapshots carry the trader's address alone: Trader { Signer Vault Broadcaster SignedAt } are not available, except on SnapshotOrders, where they come from Bitquery's order attribution and can be empty.
  • No liquidation price. Positions carry margin and maintenance margin, but not the liquidation price or the withdrawable amount.
  • Numbers are strings at native precision, but filters, sorting and sums on them are numeric.
  • Timestamps. Block.Time is a date-time; the other time fields are raw epoch integers: PlacedTime in milliseconds, CreateTime, Prices.UpdateTime, UpdateTime and Times.* in nanoseconds.
  • No subscription, 7 days. Poll about every 12.5 minutes; snapshots older than 7 days are not in the API.
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.