BlogDeveloper

How to Build a Hyperliquid Portfolio Tracker

Build a portfolio tracker for Hyperliquid: perps on every DEX, spot balances, vaults and staking, and the account modes that change what a balance means.

HydromancerTeam
How to Build a Hyperliquid Portfolio Tracker

A portfolio tracker shows a user everything they own in one place: positions, balances, what it was worth yesterday. Wallet apps have made this the front page of crypto.

Why people use one:

• One number for net worth, across every account, market and coin.
• Risk at a glance: leverage, and how close each position is to liquidation.
• Performance over time, not just today's balance.
• Watching other wallets, such as a fund's or a known trader's.

Why should you choose to build a portfolio tracker on Hyperliquid?

• Hyperliquid accounts are hard to read. Money can sit in spot or in perps, positions can be spread across the main DEX and 10 HIP-3 DEXs run by other teams, and the account mode changes where the balance shows up.
• Getting it right is valuable. One wrong read and a user's money looks missing. A tracker that gets it right gets opened every day.
• It's the screen users open first. The trade button sits right next to it.
• Wallets prove it. Phantom, MetaMask, Trust Wallet and Rabby have collected $43.21M in builder fees between them, Flowscan's 2 October 2026 snapshot shows (top builders by revenue), and a wallet's perps tab starts with the user's own positions and balances.
• All you need is an address. Every balance and position is public, so there's no login or exchange key to ask users for.

This is different from a whale tracker, which watches other people. A portfolio tracker reads your users' own wallets, so it has to be complete: a missing balance looks like lost money.

How we tested. The job: every perp position and spot balance for 20 wallets, across every DEX. We ran it on both APIs on 31 October 2026 and checked the two outputs matched line for line. The examples that read a .txt file expect one full wallet address per line.

Where a Hyperliquid account keeps things

One address can hold value in several places, and each has its own request on the official API:

Where Official request
Perp positions on the main DEXclearinghouseState
Perp positions on each HIP-3 DEXclearinghouseState with dex, once per DEX
Spot balancesspotClearinghouseState
Vault depositsuserVaultEquities
Staked HYPEdelegatorSummary
Lending and borrowingborrowLendUserState
Sub-accountssubAccounts, then all of the above per sub-account

The HIP-3 row is the easy one to miss. Hyperliquid had 10 HIP-3 DEXs alongside the main one when we tested, and a position on any of them only shows when you ask that DEX.

Read 20 wallets across every DEX

Hyperliquid API

One clearinghouseState request per DEX per wallet, plus one for spot:

code
import requests

URL = "https://api.hyperliquid.xyz/info"
dexs = [""] + [d["name"] for d in requests.post(
    URL, json={"type": "perpDexs"}).json() if d]
for u in open("wallets.txt").read().split()[:20]:
    n = 0
    for dex in dexs:                               # one request per DEX
        st = requests.post(URL, json={"type": "clearinghouseState",
                                      "user": u, "dex": dex}).json()
        n += len(st["assetPositions"])
    spot = requests.post(URL, json={"type": "spotClearinghouseState",
                                    "user": u}).json()
    print(u[:10], n, "positions,", len(spot["balances"]), "spot balances")

Hydromancer API

batchPortfolioStates with "dex": "ALL_DEXES" returns perps on every DEX, spot balances and the account mode for up to 100 wallets in one request (500 for the main DEX only). Hydromancer added this endpoint for builder convenience; it isn't part of Hyperliquid's original API, and orders still go through Hyperliquid. Here it is:

code
import os, requests

H = {"Authorization": "Bearer " + os.environ["HYDROMANCER_API_KEY"]}
users = open("wallets.txt").read().split()[:20]
r = requests.post("https://api.hydromancer.xyz/info", headers=H, json={
    "type": "batchPortfolioStates", "users": users, "dex": "ALL_DEXES"})
for u, st in r.json()["successful_states"]:
    n = sum(len(s["assetPositions"])
            for s in st["clearinghouseState"].values())
    print(u[:10], n, "positions,",
          len(st["spotClearinghouseState"]["balances"]), "spot balances")

Both printed the same 20 lines, wallet for wallet. The first few:

code
0x46921f69 22 positions, 1 spot balances
0xf5d81a13 28 positions, 2 spot balances
0xecb63caa 132 positions, 40 spot balances
0xcf3f419d 1 positions, 0 spot balances
0x25773676 180 positions, 165 spot balances
... (15 more lines)

Side by side

Hyperliquid API Hydromancer API
Result20 wallets, every DEXThe same 20 lines
Worked3 of 3 runs3 of 3 runs
Time to finish (median)42 s0.2 s
Requests2411
Rate-limit cost500 weight (limit: 1,200 a minute per IP)200 points (limit: 20,000 a minute on the Growth plan)
Data received over REST (uncompressed)0.5 MB0.4 MB

Identical output, so the choice is about scale. For one user's live screen, the official API has a faster route than the loop: the allDexsClearinghouseState subscription streams one user's state on every DEX at once (Hyperliquid stopped at 15 users per IP in our tests). For a tracker with many users, the loop's request count is the limit: at 25 weight per wallet, one IP can refresh about 48 wallets a minute. A Hyperliquid node you run yourself with --serve-info answers these requests locally without that limit; Hyperliquid recommends 16 CPU cores, 128 GB of memory and 500 GB of disk for one.

Read the account mode first

Hyperliquid accounts work in different modes, and the mode changes what the numbers mean. In a unified or portfolio-margin account, the balance sits in spot, and clearinghouseState alone shows only the margin in open positions. Of the 500 most active traders we checked for the delta-neutral guide, 224 (45%) used one of those modes. A tracker that adds up perps account value without spot will show almost half of active traders with a near-empty balance.

userAbstraction returns the mode on the official API.

What to show for each position

Each perp position in clearinghouseState already carries what a trader looks at first: size, entry price, unrealized PnL, return on equity, leverage, liquidation price, margin used and funding paid since it opened. Show the distance to the liquidation price as a percentage; it's the number users act on. Add alerts on top: a position within 10% of liquidation, a large unrealized loss, or a new position on a wallet they follow.

Value over time

Users want to see yesterday and last month, not just now. For the chart, Hyperliquid's portfolio request gives you account value and PnL over four windows, from a day to all time. For your own daily snapshots, store the totals once a day. For history from before a user joined, Reservoir has daily account value snapshots for every wallet from August 2025 (Reservoir is free; you pay only AWS download charges).

The money comes from what sits next to the numbers. Put a "trade" or "close" button beside each position and attach your builder code to those orders, the same model the wallets above use.

FAQ

How do I get every position a Hyperliquid wallet holds?

Ask each perp DEX with clearinghouseState and dex, plus spotClearinghouseState for spot: 12 requests per wallet in our test. Or stream allDexsClearinghouseState for one user, or use Hydromancer's batchPortfolioStates with ALL_DEXES for up to 100 wallets in one request. Vaults, staking and lending are separate requests on both APIs.

Why does a wallet show almost no balance on Hyperliquid's API?

Check whether it's a unified or portfolio-margin account, where the balance sits in spot. Read spotClearinghouseState too, and check the mode with userAbstraction.

Do I need the user's keys to track their portfolio?

No. A wallet address is enough; everything is public.

• Hyperliquid whale tracker
• Hyperliquid vaults API
• HyperCore vs HyperEVM
• How to query Reservoir's Hyperliquid data

Sources

- Hyperliquid docs: Info endpoint, Subscriptions
- Hydromancer docs: portfolioState, batchPortfolioStates

Continue