> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sqd.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Handling Hyperliquid fills

> Understand trade sides, volume, identifiers, and fill value types.

The `hyperliquid-fills` dataset records each trade from both participants' perspectives. A trade therefore has two fills with the same `tid`: one bid-side row and one ask-side row.

This affects common calculations:

* Sum `px * sz` on one side, or divide the sum across all fills by two, for single-counted volume.
* A `user` filter returns that trader's side only.
* Use `(block number, fillIndex)` as a row key. `tid` alone identifies the trade, not one row.

## Read and reshape fills

```ts theme={"system"}
import { hyperliquidFillsQuery } from '@subsquid/pipes/hyperliquid'

export const btcFills = hyperliquidFillsQuery()
  .addFields({
    block: { number: true, timestamp: true },
    fill: {
      fillIndex: true,
      user: true,
      coin: true,
      px: true,
      sz: true,
      side: true,
      tid: true,
      fee: true,
      feeToken: true,
    },
  })
  .addFillRequest({
    range: { from: 1_057_000_000 },
    request: { coin: ['BTC'] },
  })
  .build()
  .pipe((blocks) =>
    blocks.flatMap((block) =>
      block.fills.map((fill) => ({
        block: block.header.number,
        fillIndex: fill.fillIndex,
        user: fill.user,
        coin: fill.coin,
        price: fill.px,
        size: fill.sz,
        side: fill.side,
        tradeId: fill.tid,
        fee: fill.fee,
        feeToken: fill.feeToken,
      })),
    ),
  )
```

## Field semantics

* `side` is `'B'` for bid and `'A'` for ask.
* `px`, `sz`, `startPosition`, `closedPnl`, `fee`, and `builderFee` are JavaScript `number` values.
* `time` and `block.timestamp` are Unix milliseconds.
* `coin`, `dir`, and `feeToken` are strings supplied by Hyperliquid. Treat their value sets as open-ended.
* Addresses and hashes use `0x`-prefixed hex. Fill users are stored lowercase, so normalize user filters with `.toLowerCase()`.

## Block hashes and finality

The dataset currently returns all-zero `block.hash` and `block.parentHash` values. That is enough for ordered fill streaming, but it cannot identify competing blocks at the same height. Prefer the finalized stream for persistent targets:

```ts theme={"system"}
const portal = {
  url: 'https://portal.sqd.dev/datasets/hyperliquid-fills',
  finalized: true,
}
```

See the [query builder reference](../../reference/basic-components/query-builder) for every field and filter.


## Related topics

- [Hyperliquid fills query builder](/en/sdk/pipes-sdk/hyperliquid/reference/basic-components/query-builder.md)
- [Hyperliquid fills quickstart](/en/sdk/pipes-sdk/hyperliquid/quickstart.md)
- [Hyperliquid fills portal stream](/en/sdk/pipes-sdk/hyperliquid/reference/basic-components/source.md)
- [Hyperliquid](/en/data/hyperliquid/hyperliquid-fills.md)
- [Query BTC Fills](/en/portal/hyperliquid/examples/query-btc-fills.md)
