Hyperliquid Vaults API
Hyperliquid vaults are accounts that trade with pooled deposits: HLP, the protocol's own liquidity vault, and user vaults run by individual traders. With Bitquery you can rank vaults by volume and PnL, read each fill a vault made, follow deposits and withdrawals as they happen, and see when a vault position was liquidated. A fill or liquidation of an order placed for a vault carries the vault's address in Trader.Vault (equal to Trader.Address). Hyperliquid uses the same mechanism for sub-accounts, so Trader.Vault is set on sub-account fills too: a Vault: {not: ""} filter returns vaults and sub-accounts together. An address that receives vaultTransfer deposits (below) is a vault; to keep vaults only, list such addresses with Vault: {in: [...]}. Everything below runs on the Hyperliquid cube at https://streaming.bitquery.io/graphql over the rolling window described on the Hyperliquid API overview.
The worked vault is 0xc179e03922afe8fa9533d3f896338b9fb87ce0c8, one of the most active user vaults, and the HLP vault is 0xdfc24b077bc1425ad1dea75bcb6f8158e10df303.
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 ➤
Which Hyperliquid vaults trade the most?
Filter fills to those with a vault set and group by Trader.Vault. Each row is one vault or sub-account with its fills, markets traded, USD volume and realized PnL over the last day.
Run it in the IDE: Hyperliquid Top Vaults by Volume ➤
query HyperliquidTopVaultsByVolume {
Hyperliquid {
Trades(
limit: {count: 25}
orderBy: {descendingByField: "volumeUsd"}
where: {
Trade: {Trader: {Vault: {not: ""}}}
Block: {Time: {since_relative: {hours_ago: 24}}}
}
) {
Trade {
Trader {
Vault
}
}
fills: count
markets: uniq(of: Trade_Market_CoinRaw)
volumeUsd: sum(of: Trade_Execution_NotionalUSD)
realizedPnl: sum(of: Trade_Position_RealizedPnl)
}
}
}
Sub-accounts often fill the top of this list, so check an address against the deposits below before calling it a vault. A vault with hundreds of thousands of fills and PnL near zero is a market-making vault. HLP trades through child vaults, so its activity appears under those addresses rather than the HLP address itself.
Which vaults are the most profitable?
Every closing fill carries Position.NetPnl (realized PnL minus the fee) and Position.IsWin. Group by Trader.Vault over a week to rank vaults and sub-accounts by net realized PnL and count winning closes.
Run it in the IDE: Hyperliquid Vault PnL Leaderboard ➤
query HyperliquidVaultPnlLeaderboard {
Hyperliquid {
Trades(
limit: {count: 25}
orderBy: {descendingByField: "netPnl"}
where: {
Trade: {Trader: {Vault: {not: ""}}, Position: {IsClosing: true}}
Block: {Time: {since_relative: {days_ago: 7}}}
}
) {
Trade {
Trader {
Vault
}
}
closes: count
wins: count(if: {Trade: {Position: {IsWin: true}}})
netPnl: sum(of: Trade_Position_NetPnl)
volumeUsd: sum(of: Trade_Execution_NotionalUSD)
}
}
}
Win rate is wins / closes. Order by ascendingByField: "netPnl" for the biggest losers.
What did one vault trade?
Filter on the vault address. Each row is a fill with market, price, size, direction, leverage, fee and realized PnL; Trader.Vault equals Trader.Address. Fills of one block share Block.Time, so the query orders them by Execution.Index inside it.
Run it in the IDE: Hyperliquid Vault Fills ➤
query HyperliquidVaultFills {
Hyperliquid {
Trades(
limit: {count: 50}
orderBy: {descending: [Block_Time, Trade_Execution_Index]}
where: {
Trade: {Trader: {Vault: {is: "0xc179e03922afe8fa9533d3f896338b9fb87ce0c8"}}}
Block: {Time: {since_relative: {hours_ago: 24}}}
}
) {
Block {
Time
}
Trade {
Market {
Symbol
Kind
}
Execution {
Price
Size
Side
Direction
NotionalUSD
}
Position {
Leverage
RealizedPnl
}
Fees {
Fee
}
Trader {
Address
Vault
}
}
}
}
}
Change query to subscription and drop limit and orderBy to stream a vault's fills live.
Who deposits into and withdraws from a vault?
Deposits and withdrawals are vaultTransfer actions in the SignedActions cube, which keeps about the last 7 days on the API (for older data, ask about a Data Store export). The Action payload holds the vault address, isDeposit and the amount in usd with six decimals, so 100000000 is 100 USDC. User is the depositor. The example follows the HLP vault; swap in any vault address.
Run it in the IDE: Hyperliquid Vault Deposits and Withdrawals ➤
query HyperliquidVaultDepositsAndWithdrawals {
Hyperliquid {
SignedActions(
limit: {count: 50}
orderBy: {descending: Block_Time}
where: {
ActionType: {is: "vaultTransfer"}
Action: {includes: "0xdfc24b077bc1425ad1dea75bcb6f8158e10df303"}
Block: {Time: {since_relative: {days_ago: 1}}}
}
) {
Block {
Time
}
User
Action
Status
Bundle {
Hash
}
}
}
}
Status is ok for accepted transfers. Rejected ones stay in the data with an error status, which is useful for spotting withdrawals that hit a lock-up.
Live vault deposits and withdrawals
The same action as a WebSocket stream, across every vault, filtered to successful transfers.
Run it in the IDE: Hyperliquid Vault Transfers Stream ➤
subscription HyperliquidVaultTransfersStream {
Hyperliquid {
SignedActions(where: {ActionType: {is: "vaultTransfer"}, Status: {is: "ok"}}) {
Block {
Time
}
User
Action
Bundle {
Hash
}
}
}
}
Parse Action on the client to alert on large deposits or on any transfer into a vault you follow.
Which vault positions were liquidated?
PerpLiquidations carries Trader.Vault too, but a liquidation is recorded for both sides of the forced fill, so this list holds two kinds of rows: those where Trader.Address equals LiquidatedUser are the vault's (or sub-account's) own position being liquidated; the rest are vaults or sub-accounts taking the other side of someone else's liquidation, which market makers such as HLP's child vaults do all the time.
Run it in the IDE: Hyperliquid Vault Liquidations ➤
query HyperliquidVaultLiquidations {
Hyperliquid {
PerpLiquidations(
limit: {count: 50}
orderBy: {descending: Block_Time}
where: {
Liquidation: {Trader: {Vault: {not: ""}}}
Block: {Time: {since_relative: {days_ago: 7}}}
}
) {
Block {
Time
}
Liquidation {
Market {
Symbol
}
Method
MarkPx
LiquidatedUser
Execution {
Price
Size
Side
}
Position {
Leverage
SizeBefore
Size
}
Trader {
Address
Vault
}
}
}
}
}
To list only the liquidations of one vault's own positions, filter Liquidation: {LiquidatedUser: {is: "0x..."}, Trader: {Address: {is: "0x..."}}} with the vault address in both, or turn it into a subscription for live alerts.
Related
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.