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

# Trades

> Individual perpetual and order-book trades.

A fill is one trade matched between two traders. Each of its two sides gets its own row, and a side is called a leg. Each row carries both the leg's size and the fees charged on it, so fees, volume or both read from one table.

* `facts.perp_trades`: one row per leg of a perpetual fill.
* `facts.order_book_trades`: one row per leg of a spot or outcome-market fill.

`trade_id` is shared by both legs of one fill. Within a fill, `(trader_address, crossed)` picks out a leg. `crossed` is true on the taker's leg: the trader who accepted an order that was already there. It is false on the maker's leg: the trader whose order was sitting waiting. That pair also handles a self-trade, where one address is on both sides and the two legs differ only on `crossed`.

## Tables

<Tabs>
  <Tab title="Perp trades">
    `facts.perp_trades` holds one row per leg of a perpetual fill, keyed by `block_timestamp`, `perp_market_id`, `trade_id`, `trader_address` and `crossed`.

    <table>
      <thead>
        <tr>
          <th width="200">Column</th>
          <th width="130">Type</th>
          <th>Description</th>
        </tr>
      </thead>

      <tbody>
        <tr>
          <td><code>block\_timestamp</code></td>
          <td><code>TIMESTAMP</code></td>
          <td>Time of the block this trade landed in.</td>
        </tr>

        <tr>
          <td><code>block\_number</code></td>
          <td><code>INT64</code></td>
          <td>Number of that block.</td>
        </tr>

        <tr>
          <td><code>trade\_id</code></td>
          <td><code>INT64</code></td>
          <td>Identifier shared by both legs of the same fill. Part of the row key, alongside <code>perp\_market\_id</code>, <code>trader\_address</code> and <code>crossed</code>.</td>
        </tr>

        <tr>
          <td><code>perp\_market\_id</code></td>
          <td><code>STRING</code></td>
          <td>Market the trade executed in, keyed like <code>dimensions.perp\_markets</code>.</td>
        </tr>

        <tr>
          <td><code>interface\_app\_id</code></td>
          <td><code>STRING</code></td>
          <td>The app whose front end the trade came through, read from the registry table.</td>
        </tr>

        <tr>
          <td><code>exchange\_app\_id</code></td>
          <td><code>STRING</code></td>
          <td>The venue that matched the trade.</td>
        </tr>

        <tr>
          <td><code>token\_id</code></td>
          <td><code>STRING</code></td>
          <td>The market's settlement token.</td>
        </tr>

        <tr>
          <td><code>chain\_id</code></td>
          <td><code>STRING</code></td>
          <td>Chain the trade executed on.</td>
        </tr>

        <tr>
          <td><code>project\_id</code></td>
          <td><code>STRING</code></td>
          <td>Project the exchange app belongs to.</td>
        </tr>

        <tr>
          <td><code>trader\_address</code></td>
          <td><code>STRING</code></td>
          <td>Address of the trader on this side.</td>
        </tr>

        <tr>
          <td><code>side</code></td>
          <td><code>STRING</code></td>
          <td>Which side this leg is: <code>B</code> for the buyer, <code>A</code> for the seller.</td>
        </tr>

        <tr>
          <td><code>crossed</code></td>
          <td><code>BOOL</code></td>
          <td>True on the taker's leg, the trader who accepted an order that was already there; false on the maker's.</td>
        </tr>

        <tr>
          <td><code>price</code></td>
          <td><code>BIGNUMERIC</code></td>
          <td>Price the trade filled at, in the settlement token.</td>
        </tr>

        <tr>
          <td><code>fee</code></td>
          <td><code>BIGNUMERIC</code></td>
          <td>Fee charged on this leg, in <code>fee\_token</code>, before anything is shared out.</td>
        </tr>

        <tr>
          <td><code>fee\_token</code></td>
          <td><code>STRING</code></td>
          <td>Token the fee was charged in.</td>
        </tr>

        <tr>
          <td><code>builder\_fee</code></td>
          <td><code>BIGNUMERIC</code></td>
          <td>The front end's share inside that fee.</td>
        </tr>

        <tr>
          <td><code>deployer\_fee</code></td>
          <td><code>BIGNUMERIC</code></td>
          <td>The share going to whoever listed the market, inside that fee.</td>
        </tr>

        <tr>
          <td><code>trade\_amount</code></td>
          <td><code>BIGNUMERIC</code></td>
          <td>How much was traded, in whatever the market tracks.</td>
        </tr>
      </tbody>
    </table>
  </Tab>

  <Tab title="Order book trades">
    `facts.order_book_trades` holds one row per leg of a spot or outcome-market fill, keyed by `block_timestamp`, `order_book_market_id`, `trade_id`, `trader_address` and `crossed`. `block_timestamp` has to be part of the key because events that are not trades all carry `trade_id = 0`.

    <table>
      <thead>
        <tr>
          <th width="200">Column</th>
          <th width="130">Type</th>
          <th>Description</th>
        </tr>
      </thead>

      <tbody>
        <tr>
          <td><code>block\_timestamp</code></td>
          <td><code>TIMESTAMP</code></td>
          <td>Time of the block this trade landed in. Part of the row key.</td>
        </tr>

        <tr>
          <td><code>block\_number</code></td>
          <td><code>INT64</code></td>
          <td>Number of that block.</td>
        </tr>

        <tr>
          <td><code>trade\_id</code></td>
          <td><code>INT64</code></td>
          <td>Identifier shared by both legs of the same fill. Zero on events that are not trades. Part of the row key, alongside <code>order\_book\_market\_id</code>, <code>trader\_address</code> and <code>crossed</code>.</td>
        </tr>

        <tr>
          <td><code>order\_book\_market\_id</code></td>
          <td><code>STRING</code></td>
          <td>Market the trade executed in, keyed like <code>dimensions.order\_book\_markets</code>.</td>
        </tr>

        <tr>
          <td><code>app\_id</code></td>
          <td><code>STRING</code></td>
          <td>The app running the book, read from the registry table. Empty when that table does not carry the market.</td>
        </tr>

        <tr>
          <td><code>token\_id</code></td>
          <td><code>STRING</code></td>
          <td>The market's quote token.</td>
        </tr>

        <tr>
          <td><code>chain\_id</code></td>
          <td><code>STRING</code></td>
          <td>Chain the trade executed on.</td>
        </tr>

        <tr>
          <td><code>project\_id</code></td>
          <td><code>STRING</code></td>
          <td>Project the operating app belongs to.</td>
        </tr>

        <tr>
          <td><code>trader\_address</code></td>
          <td><code>STRING</code></td>
          <td>Address of the trader on this side.</td>
        </tr>

        <tr>
          <td><code>side</code></td>
          <td><code>STRING</code></td>
          <td>Which side this leg is: <code>B</code> for the buyer, <code>A</code> for the seller.</td>
        </tr>

        <tr>
          <td><code>crossed</code></td>
          <td><code>BOOL</code></td>
          <td>True on the taker's leg, the trader who accepted an order that was already there; false on the maker's.</td>
        </tr>

        <tr>
          <td><code>match\_leg\_count</code></td>
          <td><code>INT64</code></td>
          <td>How many legs the match wrote: two on an ordinary fill, one on a mint or burn.</td>
        </tr>

        <tr>
          <td><code>price</code></td>
          <td><code>BIGNUMERIC</code></td>
          <td>Price the trade filled at, in the quote token.</td>
        </tr>

        <tr>
          <td><code>fee</code></td>
          <td><code>BIGNUMERIC</code></td>
          <td>Fee charged on this leg, in <code>fee\_token</code>, before anything is shared out.</td>
        </tr>

        <tr>
          <td><code>fee\_token</code></td>
          <td><code>STRING</code></td>
          <td>Token the fee was charged in. On these books the taker is charged in the token they received, so the fee can land on either side of the pair.</td>
        </tr>

        <tr>
          <td><code>builder\_fee</code></td>
          <td><code>BIGNUMERIC</code></td>
          <td>The front end's share inside that fee.</td>
        </tr>

        <tr>
          <td><code>trade\_amount</code></td>
          <td><code>BIGNUMERIC</code></td>
          <td>How much was traded, in the base token.</td>
        </tr>
      </tbody>
    </table>
  </Tab>
</Tabs>

## Sample queries

<Warning>
  Put a filter on `block_timestamp` in every query. Both tables are partitioned on it, and leaving the filter out reads the whole history.
</Warning>

<Tabs>
  <Tab title="One market, one day">
    **Read one perpetual market's trades on a single day.** `trade_amount` is how much was traded, measured in whatever the market tracks, and `price` is the price it filled at. Multiply them for the trade's notional value: the value of the contracts traded, which is not the same as cash changing hands.

    ```sql theme={null}
    select
        block_timestamp,
        trade_id,
        trader_address,
        side,
        crossed,
        price,
        trade_amount,
        fee
    from `facts.perp_trades`
    where perp_market_id = 'hlbtc-hypercore'
      and block_timestamp >= timestamp('2026-08-01')
      and block_timestamp < timestamp('2026-08-02')
    order by block_timestamp
    limit 100
    ```
  </Tab>

  <Tab title="Order-book volume">
    **Total one order-book market's volume over a window.** Both legs of an ordinary fill describe the same trade, so venue volume counts only the taker's leg. A match that wrote a single leg, a mint or a burn, is counted in full. That is what the `(crossed or match_leg_count = 1)` filter does.

    ```sql theme={null}
    select
        timestamp_trunc(block_timestamp, day) as day,
        sum(price * trade_amount) as trading_volume
    from `facts.order_book_trades`
    where order_book_market_id = '@107-hypercore'
      and (crossed or match_leg_count = 1)
      and block_timestamp >= timestamp('2026-08-01')
      and block_timestamp < timestamp('2026-08-08')
    group by day
    order by day
    ```
  </Tab>
</Tabs>

## Notes

A fee is charged on each side separately, so a fee total adds up every row. Volume is different. Both legs of an ordinary fill describe one trade at one value, so counting both doubles the venue's volume. Count one leg per fill.

Both tables carry token amounts and no dollar column. Amounts become dollars once, on the market-and-token daily tables described on [Metrics](/docs/catalog/perpetuals/metrics), which is what makes every broader total agree with the ones beneath it.
