# How to get Hyperliquid positions and trade history as data

Hyperliquid serves any address's positions and fills to anyone, without a key. The catch is that its history endpoints stop at your 10,000 most recent fills.

*https://cryptomarkets.tools/how-to/get-hyperliquid-positions-and-trade-history · next to Crypto Trading Terminals*

**Answer:** POST to Hyperliquid's own info endpoint — clearinghouseState for open perp positions, spotClearinghouseState for balances, userFillsByTime for fills, userFunding for funding. No key is needed, only the account's address. The official Python SDK and CCXT wrap the same calls. The limit to plan around: only the 10,000 most recent fills are served, so a long history means archiving as you go or reading the venue's S3 dumps.

## Approaches

*In the author’s order. Paid placement does not affect it.*

1. [Hyperliquid Python SDK](https://cryptomarkets.tools/tools/hyperliquid-python-sdk.md) — Info.user_state, user_fills_by_time, user_funding_history and query_sub_accounts map one-to-one onto the info endpoint — no key needed for any of them.
2. [CCXT](https://cryptomarkets.tools/tools/ccxt.md) — fetch_positions and fetch_my_trades in the shape every other venue uses, with walletAddress set and a dex parameter for builder-deployed markets.
3. [Dune](https://cryptomarkets.tools/tools/dune.md) — SQL over HyperCore fills, funding and per-account daily tables back past the API's window — gated behind an enterprise entitlement or a trial.
4. [0xArchive](https://cryptomarkets.tools/tools/0xarchive.md) — Positions, order history and TWAP events by wallet address over REST, plus webhook alerts on a named wallet's fills — past 30 days needs Build, $49 a month.

## The short way

Every read goes to one URL, `https://api.hyperliquid.xyz/info`, as a JSON POST whose `type` field
picks the query. There is no key and no signature. What identifies the account is its address.

```python
import requests

INFO = "https://api.hyperliquid.xyz/info"
ADDRESS = "0xYOUR_ACCOUNT_ADDRESS"

positions = requests.post(INFO, json={"type": "clearinghouseState", "user": ADDRESS}).json()
balances = requests.post(INFO, json={"type": "spotClearinghouseState", "user": ADDRESS}).json()

fills, start = [], 0
while True:
    page = requests.post(INFO, json={"type": "userFillsByTime", "user": ADDRESS, "startTime": start}).json()
    new = [f for f in page if f["tid"] not in {x["tid"] for x in fills}]
    if not new:
        break
    fills += new
    start = max(f["time"] for f in page)
```

`clearinghouseState` returns open perp positions — size as `szi`, entry price, leverage type,
liquidation price, unrealised PnL and cumulative funding — with an account margin summary.
`userFillsByTime` returns fills from `startTime`, and the docs' instruction for paging is to pass
the last timestamp you received as the next `startTime`. That bound is inclusive, which is why the
loop above deduplicates on the trade id `tid`: fills sharing a millisecond otherwise arrive twice.

Then fetch funding the same way, with `userFunding` and a `startTime`, and deposits, withdrawals and
transfers with `userNonFundingLedgerUpdates`. Those three streams together are the account's
history; any one of them alone is not.

## What the options are

**The info endpoint directly**, as above. Nothing to install, and nothing between you and what
the venue serves.

**The official [Python SDK](https://cryptomarkets.tools/tools/hyperliquid-python-sdk).** Its `Info` class is a thin wrapper
over the same calls — `user_state` posts `clearinghouseState`, `user_fills_by_time` posts
`userFillsByTime`, `user_funding_history` posts `userFunding`, and `query_sub_accounts`,
`user_vault_equities`, `historical_orders` and `portfolio` cover the rest. It adds no pagination,
no retries and no rate limiting, so the loop above is still yours to write.

**[CCXT](https://cryptomarkets.tools/tools/ccxt)**, if Hyperliquid is one venue among several and you want its positions and
fills in the same structures as the others. Its Hyperliquid class implements `fetch_positions`
over `clearinghouseState`, `fetch_my_trades` over `userFills` or `userFillsByTime` depending on
whether you pass `since`, and `fetch_funding_history` and `fetch_ledger` over the two ledger
streams. Set `walletAddress` rather than an API key for reads; a `subAccountAddress` parameter
reads a sub-account, and a `dex` parameter reaches builder-deployed markets. The unified shape
costs you the venue's own fields, such as `startPosition` and `dir`, unless you read `info` on
each record.

**[Dune](https://cryptomarkets.tools/tools/dune)**, for history past what the API will serve. Its curated Hyperliquid tables
carry per-fill trades with fees and realised PnL from 27 July 2025, and per-account daily rows with
funding and collateral flows; decoded node fills go back to January 2025. All of it is gated — an
enterprise entitlement or a trial account — so this is the route when the question is a closed
year rather than this morning.

**[0xArchive](https://cryptomarkets.tools/tools/0xarchive)**, a third-party market-data API for Hyperliquid and Lighter that
also answers by wallet address — positions, order history, take-profit and stop-loss orders and
TWAP events. Its free key covers the latest 30 days; the full archive, and webhook alerts on fills
by a wallet you name, start at Build for $49 a month. Coverage starts on a different date for each
data type, so check its coverage routes for the one you need before planning on a date.

## Where this breaks

**The history window is 10,000 fills.** The docs on 4 October 2026: `userFillsByTime` returns at
most 2,000 fills per response "and only the 10000 most recent fills are available". `userFills`
without a time range returns the latest 2,000 and stops; `historicalOrders` and
`userTwapSliceFills` stop at 2,000 as well. An active account passes 10,000 fills in weeks, and
then its first trades are simply no longer served. Beyond that the venue points to S3 —
`node_fills_by_block` in the `hl-mainnet-node-data` bucket, with older data in a different
format, and transfers, staking and funding in `misc_events_by_block`. The requester pays the
transfer, and the dumps cover the whole venue rather than one address. If you need your own
history, archive it while it is still inside the window.

**Funding is a separate record.** It is paid every hour, and it arrives through `userFunding` as a
ledger entry with the coin, the position size, the rate and the USDC amount — not in the fills.
Fills carry `closedPnl` for the trade alone. A realised-PnL figure assembled from fills will be
wrong by every funding payment, and on a position held for days that is not a rounding error.

**Builder fees are inside `fee`.** When an order went through a front-end that charges a builder
code, the fill's `fee` is the total, inclusive of the builder's share, and a separate
`builderFee` field appears only when it is non-zero. Builder fees can run to 0.1% on perps and 1%
on spot. [Velo](https://cryptomarkets.tools/tools/velo) and [Insilico Terminal](https://cryptomarkets.tools/tools/insilico-terminal) each charge one
basis point on Hyperliquid orders, [WunderTrading](https://cryptomarkets.tools/tools/wundertrading) 0.035%, and orders placed
through [CCXT](https://cryptomarkets.tools/tools/ccxt) carry one basis point by default unless it is switched off. A
fee audit that treats `fee` as the venue's fee will overstate what Hyperliquid charged.

**Sub-accounts and vaults are separate addresses.** A sub-account has its own address, its own
positions and its own fills; the master's queries do not include it. List them with
`subAccounts` and query each one. A vault is also its own address — `userRole` returns `vault` —
while a depositor's stake in it shows up through `userVaultEquities`, not as positions. And the
common failure in the docs' own words: querying an API wallet's address returns an empty result,
because an agent key signs for an account and holds nothing itself.

**Perp and spot are different calls and different names.** Perp positions come from
`clearinghouseState`; spot balances from `spotClearinghouseState`. Spot fills name the pair as
`@107` — an index into `spotMeta` — except for `PURR/USDC`, and the docs note that some pairs are
remapped on the interface: what the app shows as BTC/USDC is `UBTC/USDC` on HyperCore. Map coins
through `spotMeta` before you join anything to a price. Under unified-account or portfolio
margin, the docs say `clearinghouseState` is no longer the account balance and the spot endpoint
is the source of truth.

**Builder-deployed markets need one call per venue.** HIP-3 markets live on separate perp dexes,
and their fills come back with the dex as a prefix — `xyz:XYZ100`. Fills from every dex arrive in
one list, but `clearinghouseState` takes a `dex` parameter and defaults to the first one, so an
account's full position picture is one call per dex. `perpDexs` returned eleven entries on 4
October 2026: the first perp dex and ten deployer dexes. A position on any of the ten is invisible
to a script that never passes `dex`.

**The rate limit is weight, not requests.** Each IP gets 1,200 weight a minute. `clearinghouseState`
and `spotClearinghouseState` weigh 2, `userRole` 60, most other info requests 20 — and the fill,
order and funding history endpoints add further weight for every 20 items they return. The docs
do not print the increment; at one unit per 20, a full 2,000-fill page costs about 120, or ten
full pages a minute from one IP — so a backfill is paced by the response size, not the call count.

**It is public in both directions.** No key also means no privacy: anyone who knows an address
can read its positions, liquidation price and full recent history with the same calls. That is
why the address matters more than any key here, and why sub-accounts do not hide anything from a
reader who can see the master's `subAccounts` list.

## If you outgrow this

Once the 10,000-fill window is the constraint, the choice is between running your own archive —
poll `userFillsByTime`, `userFunding` and the ledger stream on a schedule and keep everything —
and reading somebody else's. The venue's S3 dumps are complete but arrive in node formats, for
the whole venue, with transfer costs on you. A warehouse that has already ingested them, like
[Dune](https://cryptomarkets.tools/tools/dune), trades that work for an enterprise conversation. For the venue's market data
rather than one account's, [Tardis.dev](https://cryptomarkets.tools/tools/tardis-dev) has recorded Hyperliquid since 29
October 2024.

## FAQ

### Do I need an API key to read my Hyperliquid positions?

No. Info requests are unauthenticated and take the account's address, so a script needs nothing secret to read positions, balances, fills or funding. The same is true for everyone else — any address's positions and history can be read by anyone who knows it.

### How far back does Hyperliquid's API return fills?

To your 10,000 most recent fills and no further, per the info endpoint documentation on 4 October 2026, at up to 2,000 per response. userFills without a time range returns the latest 2,000 only. Anything older has to come from your own archive, the venue's requester-pays S3 dumps of node fills, or a warehouse that ingested them.

### Why does my Hyperliquid query return nothing?

Usually because it was sent with an API wallet's address. The docs call this out as a common pitfall — an agent key signs for an account but holds nothing, so the query must use the master account's or sub-account's own address. userRole tells you which kind of address you have.

### Is funding included in the fills?

No. Funding is paid hourly as its own ledger entry and comes back from userFunding, separate from fills. Deposits, withdrawals and transfers are a third stream, userNonFundingLedgerUpdates. A PnL built from fills alone leaves out every funding payment on every position held across the hour.

## Sources

1. [Info endpoint](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint) — Hyperliquid, read 2026-10-04
2. [Info endpoint — Perpetuals](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint/perpetuals) — Hyperliquid, read 2026-10-04
3. [Rate limits and user limits](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/rate-limits-and-user-limits) — Hyperliquid, read 2026-10-04
4. [Historical data](https://hyperliquid.gitbook.io/hyperliquid-docs/historical-data) — Hyperliquid, read 2026-10-04
5. [Builder codes](https://hyperliquid.gitbook.io/hyperliquid-docs/trading/builder-codes) — Hyperliquid, read 2026-10-04
6. [Hyperliquid Perpetuals — curated tables](https://docs.dune.com/data-catalog/curated/perpetuals/hyperliquid/overview) — Dune, read 2026-10-04

*Last updated 2026-10-07. Corrected in place — an endpoint that moves is a bug here, not a new post.*
