Home / Solutions / Derivatives & Perps
Derivatives & Perps

Derivatives data: perp fills, realized PnL, and decoded DEX events

On Hyperliquid one execution is two fills sharing a trade id, with the fee and realized PnL on each; on an EVM perp DEX it is contract events. SQD serves the complete Hyperliquid fills tape as a dedicated dataset and the decoded event stream of protocols like GMX, from one API across 225+ networks. Volume, PnL, and market share are rollups over those rows, not vendor aggregates.

225+ Networks
Fills Both sides of every trade
750M Fills start block
NDJSON Streaming
The problem

A perps dashboard is an aggregation over raw fills, and those fills arrive in two incompatible shapes

Volume and realized PnL both roll up from individual fills, and those fills come from two very different venues. Hyperliquid runs its order book on its own L1, so an execution is not a log: it is a pair of fills that share a trade id, one for the maker and one for the taker. On an EVM perp DEX the executions are contract events, but the protocols that matter obfuscate them: GMX V2 funnels every event through one generic emitter, so an off-the-shelf indexer keyed on typed signatures cannot even name what it is reading. The rows are all there; the work is reading both venues through one query shape.

The Hyperliquid tape

One execution is two fills that share a trade id

A BTC filter over the single block 1,036,000,001 (2026-06-15) returns exactly one execution, and you get both halves of it: 0.02679 BTC at 65,685.0, a $1,759.70 notional.

Read the pair: same tid, same price and size. The resting maker (0x7dd6…cf0d, crossed: false) was paid a 0.052791 USDC rebate, so its fee is negative; the taker (crossed: true) paid 1.376085 USDC. closedPnl is 0.0 on both because both sides opened positions; the realized number books on the closing fill, so net PnL over any window is sum(closedPnl) - sum(fee). Timestamps are milliseconds, not seconds.

The query is one coin filter over one pinned block. Run it and you get exactly the row shown:

your terminal
curl -s -X POST https://portal.sqd.dev/datasets/hyperliquid-fills/stream \
-H 'content-type: application/json' \
-d '{
"type": "hyperliquidFills",
"fromBlock": 1036000001, "toBlock": 1036000001,
"fills": [{ "coin": ["BTC"] }],
"fields": {
"block": { "number": true, "timestamp": true },
"fill": {
"user": true, "coin": true, "px": true, "sz": true,
"side": true, "dir": true, "closedPnl": true,
"fee": true, "feeToken": true, "crossed": true, "tid": true
}
}
}'
the row it returns
{
"header": { "number": 1036000001, "timestamp": 1781496830924 },
"fills": [
{
"user": "0x7dd6f02fef939cea86f0243358255f6b57a6cf0d",
"coin": "BTC", "px": 65685.0, "sz": 0.02679,
"side": "B", "dir": "Open Long", "closedPnl": 0.0,
"crossed": false, "fee": -0.052791,
"tid": 1079924434640118, "feeToken": "USDC"
},
{
"user": "0x7414033ea96b832de9a869e05164af734c70d5ff",
"coin": "BTC", "px": 65685.0, "sz": 0.02679,
"side": "A", "dir": "Open Short", "closedPnl": 0.0,
"crossed": true, "fee": 1.376085,
"tid": 1079924434640118, "feeToken": "USDC"
}
]
}

One gotcha: summing px * sz over fills counts every execution twice, once per side. The same filter over blocks 1,036,000,000 to 1,036,000,100 returns 40 BTC fills but only 20 distinct tid values: $19,164.18 summed across fills, $9,582.09 actually traded. Dedupe on tid before quoting volume.

This is the part that is hard to assemble elsewhere. Hyperliquid is not an EVM contract, so there are no logs to decode and nothing for eth_getLogs to return; the venue's info API serves fills per address behind a rate limit, one account at a time. The hyperliquid-fills dataset is the whole tape as a single queryable source, from block 750,000,000 to head.

The EVM leg

GMX position events: decoded logs, one topic filter

On EVM chains, derivatives activity is contract events, with a trap of its own. GMX V2 routes every protocol event through one EventEmitter contract (0xC8ee91A54287DB53897056e12D9819156D3822Fb on Arbitrum) as generic EventLog1 and EventLog2 records, and the actual event name travels as an indexed keccak hash. An indexer keyed on typed signatures sees opaque blobs; the right filter is the emitter address plus the name hash. Every position change on GMX Arbitrum, across all its markets, is then one query:

your terminal
curl -s -X POST https://portal.sqd.dev/datasets/arbitrum-one/stream \
-H 'content-type: application/json' \
-d '{
"type": "evm",
"fromBlock": 482000000, "toBlock": 482010000,
"logs": [{
"address": ["0xc8ee91a54287db53897056e12d9819156d3822fb"],
"topic1": ["0xf94196ccb31f81a3e67df18f2a62cbfb50009c80a7d3c728a3f542e3abc5cb63",
"0x07d51b51b408d7c62dcc47cc558da5ce6a6e0fd129a427ebce150f52b0e5171a"]
}],
"fields": { "log": { "topics": true, "transactionHash": true },
"block": { "number": true, "timestamp": true } }
}'

The two filter values are keccak256("PositionIncrease") and keccak256("PositionDecrease"), computed from the event names in the GMX source. The first row back:

a PositionIncrease log
{
"header": { "number": 482000195, "timestamp": 1783591220 },
"logs": [{
"transactionHash": "0xcec68ef152f58a6921970f26e374273fbf1479304d401b80ed1118d111ef5e5b",
"topics": [
"0x137a44067c8961cd7e1d876f4754a5a3a75989b4552f1843fc69c3b372def160",
"0xf94196ccb31f81a3e67df18f2a62cbfb50009c80a7d3c728a3f542e3abc5cb63",
"0x0000000000000000000000009bb408b74d75452eeea79b3750845fc742d5e812"
]
}]
}

The first topic is the generic EventLog1 signature, the second is the PositionIncrease name hash the filter matched, and the third is the trader's account, left-padded to 32 bytes; the transaction is 0xcec6…5e5b. Over blocks 482,000,000 to 482,010,000 (10,001 blocks, roughly 42 minutes of chain time on 2026-07-09) the filter returns 43 position events: 28 increases, 15 decreases. GMX runs its multichain perp data on SQD; the Hyperliquid tape and this stream come from the same API with the dataset swapped, and the rest of the 225+ networks work like this one.

Playground

Try the Portal API

Live queries against real blockchain data. Pick a network, choose a query, hit run.

The public endpoint is free for development. See plans for dedicated portals and higher limits.

Network+200 more
Query
curl --compressed -X POST \
'https://portal.sqd.dev/datasets/hyperliquid-fills/stream' \
-H 'Content-Type: application/json' \
-d '{
"type": "hyperliquidFills",
"fromBlock": 900000000,
"toBlock": 900000100,
"fields": {
"block": {"number":true,"timestamp":true},
"fill": {
"user": true,
"coin": true,
"px": true,
"sz": true,
"side": true,
"closedPnl": true
}
},
"fills": [{"coin":["BTC"]}]
}'
Hyperliquidhyperliquid-fills/stream
BTC perpetual fills and PnL
Capabilities

Built for Derivatives & Perps at scale

The complete Hyperliquid fills tape

The hyperliquid-fills dataset serves every fill on the venue by block range, from block 750,000,000 to head, filtered by coin, user, or side. Each execution appears as two fills sharing a tid: crossed: true marks the taker, and a maker rebate shows up as a negative fee. Hyperliquid's own info API returns fills per address; this is the whole market in one source.

EVM perp protocols, decoded

GMX and other EVM perp and options protocols emit their activity as contract events, served as logs filtered by address and topic, with traces and state diffs alongside. GMX V2 routes everything through a generic EventEmitter, so position changes across all its markets are one filter on the indexed event-name hash. GMX runs its multichain perp data on SQD.

Realized PnL from the tape alone

closedPnl is non-zero only on closing fills, and fee is signed, negative for a maker rebate. Net realized PnL for any trader over any window is sum(closedPnl) minus sum(fee), a rollup over rows the query already returns. No price oracle and no account snapshot are involved in the realized number.

Crypto, TradFi, and HIP-3 in one stream

Hyperliquid lists equities, commodities, and permissionless HIP-3 markets alongside crypto perps, mixed in the same fills feed. The coin field separates them: plain tickers are crypto, an xyz: or cash: prefix is TradFi, an @ prefix is HIP-3, and a short list of bare tickers (HOOD, GOOGL, TSM) are equities. One classifier on that field splits venue volume by market type.

Why SQD

What you would build yourself

The executions are all there; what a provider saves you is the reading, and on derivatives that means two very different venues collapsed into one query shape.

  • Hyperliquid history
    Yourself The venue's own info API returns fills per address behind a rate limit, one account at a time, which fits checking a single trader, not a market-wide history.
    With SQD The hyperliquid-fills dataset serves every fill on the venue by block range, from block 750,000,000 to head, filtered by coin, user, or side in one request.
  • GMX event decoding
    Yourself GMX V2 funnels every event through a generic emitter with the name as an indexed keccak hash, so an indexer keyed on typed signatures reads opaque blobs.
    With SQD One filter on the emitter address plus the event-name hash returns every position change across all of GMX's markets.
  • Cross-venue coverage
    Yourself Hyperliquid's L1 order book and each EVM DEX's contract events are a separate integration per venue.
    With SQD The Hyperliquid tape and the EVM event stream come from the same API with the dataset name swapped, across 225+ networks.

See this on your own contracts

Tell us the chains and contracts you care about, and we will show you the query that returns them.

Use cases

What teams build with SQD

  • Trader PnL leaderboards from the fills tape
  • Perp DEX dashboards across Hyperliquid and EVM venues
  • Liquidation and position monitoring on EVM perp protocols
  • Fee-revenue and maker-rebate accounting from signed fees
  • Crypto versus TradFi and HIP-3 market-share splits
  • Copy-trading and trader-tracking feeds keyed by address

Frequently asked questions

How do I get Hyperliquid perps data over a historical range?
The hyperliquid-fills dataset serves every fill on the venue by block range, from block 750,000,000 to head, filtered by coin, user, or side in one request. Hyperliquid's own info API returns fills per address behind a rate limit, which fits a trader checking one account, not a market-wide history. The full field walkthrough is in the Hyperliquid perps data guide.
How is realized PnL computed from perp fills?
Each fill carries closedPnl, which is non-zero only on closing trades, and a signed fee, where a negative value is a maker rebate. Net realized PnL over any window is sum(closedPnl) minus sum(fee); rebates, being negative fees, add back. The two sides of one execution share a tid and crossed: true marks the taker, so maker and taker economics separate cleanly per trade.
Does the same API cover EVM derivatives DEXs like GMX?
Yes. Perp and options protocols on EVM chains emit their activity as contract events, and the Portal serves those logs filtered by address and topic, with transactions, traces, and state diffs alongside. GMX V2 routes every protocol event through a generic EventEmitter contract, so position changes across all its markets are one topic filter on the event-name hash. GMX runs its multichain perp data on SQD: see the GMX case study.
Get started

Your blockchain data infrastructure, handled.

Private Portal. Dedicated. Validated. Managed. Tell us what you're building, we'll show you what it looks like on SQD.