Market data
Market data comes from
InfoClient, which needs no
keys. Coins are named as in Markets:
"BTC" for perps, "PURR/USDC" or "@107" for spot pairs and "xyz:TSLA"
for builder-dex perps. Prices and sizes are
Decimal strings and
timestamps are Unix milliseconds.
info := hyperliquid.NewInfoClient(hyperliquid.Mainnet)For live updates, subscribe to the same data over the WebSocket instead of polling.
Mid prices
AllMids returns the
mid price of every perp and spot coin, keyed by coin name. Set Dex for a
builder dex:
mids, err := info.AllMids(ctx, hyperliquid.AllMidsRequest{})
if err != nil {
log.Fatal(err)
}
fmt.Println("BTC:", mids["BTC"], "HYPE/USDC:", mids["@107"])Perp metadata and asset contexts
Meta lists the perps of
a dex: name, size decimals, maximum leverage and margin table. An asset’s
position in Universe is its asset ID on the main dex.
MetaAndAssetCtxs
adds the live state of each asset (mark, oracle and mid price, funding, open
interest, volume) in AssetCtxs, parallel to Universe:
m, err := info.MetaAndAssetCtxs(ctx, hyperliquid.MetaAndAssetCtxsRequest{})
if err != nil {
log.Fatal(err)
}
for i, asset := range m.Meta.Universe {
if asset.IsDelisted {
continue
}
c := m.AssetCtxs[i]
fmt.Printf("%-6s mark=%s funding=%s oi=%s maxLev=%d\n",
asset.Name, c.MarkPx, c.Funding, c.OpenInterest, asset.MaxLeverage)
}MidPx, Premium and ImpactPxs are pointers because they are null for
illiquid assets. Delisted assets stay in Universe so that the indexes, and
with them the asset IDs, do not shift.
Order book
L2Book returns up to
20 levels per side, best first: bids in Levels[0], asks in Levels[1]. It
returns nil for a coin that does not exist. Set NSigFigs (2 to 5) to
aggregate levels into coarser price buckets:
book, err := info.L2Book(ctx, hyperliquid.L2BookRequest{Coin: "ETH"})
if err != nil {
log.Fatal(err)
}
if book == nil {
log.Fatal("unknown coin")
}
bids, asks := book.Levels[0], book.Levels[1]
fmt.Printf("bid %s x %s | ask %s x %s\n", bids[0].Px, bids[0].Sz, asks[0].Px, asks[0].Sz)
sigFigs := 3
coarse, err := info.L2Book(ctx, hyperliquid.L2BookRequest{Coin: "BTC", NSigFigs: &sigFigs})
if err != nil {
log.Fatal(err)
}
fmt.Println("BTC bucketed best bid:", coarse.Levels[0][0].Px)Candles
CandleSnapshot
returns the candles whose open time falls in a range. Only the 5000 most
recent candles of each interval are available:
candles, err := info.CandleSnapshot(ctx, hyperliquid.CandleSnapshotRequest{
Coin: "BTC",
Interval: hyperliquid.Candle1h,
StartTime: time.Now().Add(-24 * time.Hour).UnixMilli(),
// EndTime zero means now.
})
if err != nil {
log.Fatal(err)
}
for _, c := range candles {
fmt.Println(time.UnixMilli(c.OpenTime).UTC().Format(time.DateTime), c.Open, c.High, c.Low, c.Close, c.Volume)
}Recent trades
RecentTrades
returns the latest public trades of a coin. Side is the aggressor’s side
and Users holds the buyer and the seller:
trades, err := info.RecentTrades(ctx, hyperliquid.RecentTradesRequest{Coin: "BTC"})
if err != nil {
log.Fatal(err)
}
for _, t := range trades {
fmt.Println(t.Side, t.Sz, "@", t.Px, time.UnixMilli(t.Time).UTC().Format(time.TimeOnly))
}Funding
FundingHistory
returns historical funding rates of a perp, oldest first, at most 500 per
call. Page forward from the last timestamp:
start := time.Now().Add(-30 * 24 * time.Hour).UnixMilli()
var rates []hyperliquid.FundingRate
for {
page, err := info.FundingHistory(ctx, hyperliquid.FundingHistoryRequest{Coin: "ETH", StartTime: start})
if err != nil {
log.Fatal(err)
}
rates = append(rates, page...)
if len(page) < 500 {
break
}
start = page[len(page)-1].Time + 1
}
fmt.Println(len(rates), "hourly rates, latest", rates[len(rates)-1].FundingRate)PredictedFundings
returns the next funding rate of each coin on Hyperliquid and on other venues,
keyed by coin and then by venue ("HlPerp", "BinPerp", "BybitPerp", …).
A nil entry means the venue has no prediction for that coin:
predicted, err := info.PredictedFundings(ctx)
if err != nil {
log.Fatal(err)
}
for venue, p := range predicted["BTC"] {
if p != nil {
fmt.Println(venue, p.FundingRate, "next at", time.UnixMilli(p.NextFundingTime).UTC())
}
}The response’s JSON arrays of [key, value] pairs decode into a
TupleMap, an ordinary Go map.
Spot metadata
SpotMeta lists the
spot tokens and pairs. A pair names its base and quote tokens by token index;
its asset ID is 10000 + Index and its coin name is Name:
spot, err := info.SpotMeta(ctx)
if err != nil {
log.Fatal(err)
}
tokens := make(map[int]hyperliquid.SpotTokenMeta, len(spot.Tokens))
for _, t := range spot.Tokens {
tokens[t.Index] = t
}
for _, p := range spot.Universe[:5] {
base, quote := tokens[p.Tokens[0]], tokens[p.Tokens[1]]
fmt.Printf("%-10s %s/%s asset=%d\n", p.Name, base.Name, quote.Name, 10000+p.Index)
}SpotMetaAndAssetCtxs
adds prices, volume and supply per pair. To resolve names to asset IDs, use
LoadMarkets
rather than building your own index.
Builder-deployed perp dexes
PerpDexs lists the
HIP-3 dexes. Element 0 is nil and stands for the main dex; the others
describe each dex, and their index is the dexIndex in their asset IDs.
Requests that cover a dex, such as Meta, MetaAndAssetCtxs and AllMids,
take its name in Dex.
AllPerpMetas
fetches the Meta of every dex in one call, indexed like PerpDexs:
dexs, err := info.PerpDexs(ctx)
if err != nil {
log.Fatal(err)
}
for i, d := range dexs {
if d == nil {
continue // the main dex
}
meta, err := info.Meta(ctx, hyperliquid.MetaRequest{Dex: d.Name})
if err != nil {
log.Fatal(err)
}
fmt.Printf("%d %-5s %-22s %d perps, asset IDs from %d\n",
i, d.Name, d.FullName, len(meta.Universe), 100000+10000*i)
}Explorer
The explorer requests go to the network’s RPCURL over HTTP, even when the
client sends its other requests over the WebSocket.
UserDetails
returns a user’s recent transactions,
TxDetails one
transaction by hash, and
BlockDetails
an L1 block with its transactions:
txs, err := info.UserDetails(ctx, hyperliquid.UserDetailsRequest{User: user})
if err != nil {
log.Fatal(err)
}
if len(txs) == 0 {
log.Fatal("no transactions")
}
for _, tx := range txs {
if tx.Error != nil {
fmt.Println(tx.Hash, "failed:", *tx.Error)
}
}
tx, err := info.TxDetails(ctx, hyperliquid.TxDetailsRequest{Hash: txs[0].Hash})
if err != nil {
log.Fatal(err)
}
fmt.Println(tx.Hash, "in block", tx.Block, string(tx.Action))
block, err := info.BlockDetails(ctx, hyperliquid.BlockDetailsRequest{Height: tx.Block})
if err != nil {
log.Fatal(err)
}
fmt.Println("block", block.Height, "has", block.NumTxs, "txs, proposer", block.Proposer)ExplorerTx.Action is the raw action JSON, such as {"type":"order",...}.
To follow new blocks and transactions as they happen, use
DialExplorerWebSocket.