---
title: "Closed Trades Aggregate"
method: GET
path: "/gateway/v1/hyperliquid/trades/aggregate"
tags: ["Hyperliquid"]
---

# Closed Trades Aggregate

`GET /gateway/v1/hyperliquid/trades/aggregate`

Returns a wallet's closed trades rolled up server-side into one row per group — so the P&L calendar, per-symbol / direction / size attribution, and the realized equity curve are one call each instead of paging the whole trade history.

**`group_by`:** `day` (UTC calendar day — the calendar and equity-curve source), `symbol` (per market), `direction` (long vs short), `size_bucket` (notional-USD tiers: `<1k`, `1k-10k`, `10k-100k`, `100k-1m`, `1m+`), or `hold_bucket` (holding-time tiers: `<5m`, `5m-1h`, `1h-1d`, `1d-1w`, `1w+`). Tiers with no trades are omitted — render the full ladder client-side and zero-fill. One dimension per call.

**Per group:** trade_count, gross_pnl, net_pnl (funding-excluded — gross − fees, matching `/trades` and `/performance`), fees, funding_pnl (live tail only), win_rate, volume_usd (notional), avg_win, avg_loss.

`from`/`to` (Unix seconds or a date) bound close_time; omit for full history. Totals reconcile to `/trades` and `/performance` — all three read the same `episodes` universe (warehouse ≤ watermark plus the live gap-fill past it) through one shared watermark; only the live gap-fill contributes trades past the watermark, and `funding_pnl` is populated on that tail alone. `dex` scopes to one market (omit to aggregate across markets). For `group_by=day`, `fill_gaps=true` emits zero rows for no-trade days (a dense calendar; requires `from`). Not paginated — every group in the window is returned in one response.

## Query parameters

- `address` string, required — Wallet address: a 0x EVM address or an ENS name (e.g. vitalik.eth). Solana addresses are not supported.
- `group_by` 'day' | 'symbol' | 'direction' | 'size_bucket' | 'hold_bucket' — Dimension to roll up by. day = UTC calendar day (the P&L calendar / equity-curve source); symbol = per market; direction = long vs short; size_bucket = notional-USD tiers; hold_bucket = holding-time tiers.
- `from` string — Window start, bounds close_time: Unix seconds, an ISO datetime (2026-03-01T12:00:00Z), or a bare date (= midnight UTC). Omit for full history.
- `to` string — Window end, inclusive, bounds close_time: Unix seconds, an ISO datetime, or a bare date — a bare date means the END of that UTC day, so from=X&to=X covers the whole day X. Defaults to now.
- `dex` 'main_dex' | 'xyz' | 'flx' | 'vntl' | 'hyna' | 'km' | 'abcd' | 'cash' | 'para' | 'mkts' — Market scope: main_dex for the native market only, omit to aggregate across ALL markets, or a builder market — one of: xyz, flx, vntl, hyna, km, abcd, cash, para, mkts. NOTE: the omit default differs from /leaderboard, where omitting dex means the native market only.
- `fill_gaps` boolean — group_by=day only: emit a zero row for every no-trade UTC day in the window so the calendar is dense. Requires from (a bounded window); ignored for other group_by values.

## Response `200`

OK

- DataResponseHyperliquidTradeGroup
  - `$schema` string, uri — A URL to the JSON Schema for this object.
  - `data` HyperliquidTradeGroup[], nullable, required
    - `avg_loss` number, double — Average net_pnl of losing trades, USD (negative); omitted when this group has no losses
    - `avg_win` number, double — Average net_pnl of winning trades, USD; omitted when this group has no wins
    - `fees` number, double, required — Sum of episode fees, USD
    - `funding_pnl` number, double, required — Sum of separately-attributed episode funding, USD (positive = received). Never included in net_pnl; check funding_status before use.
    - `funding_status` 'complete' | 'partial' | 'unavailable', required — Coverage of funding_pnl for episodes in this group.
    - `gross_pnl` number, double, required — Sum of episode gross_pnl, USD (before fees)
    - `key` string, required — Group identifier: a UTC date (YYYY-MM-DD) for group_by=day; the market id for symbol; long/short for direction; or the tier label (e.g. 10k-100k, 1h-1d) for size_bucket / hold_bucket
    - `net_pnl` number, double, required — Sum of episode net_pnl, USD (funding excluded — gross_pnl − fees)
    - `trade_count` integer, required — Closed episodes (trades) in this group
    - `volume_usd` number, double, required — Notional volume traded, USD (sum of opened_sz × entry price)
    - `win_rate` number, double, required — Share of trades with net_pnl > 0 (0-1)
  - `meta` OffsetMeta, required
    - `cached` boolean, required — Whether this response was served from cache
    - `credits_used` integer, required — Credits deducted for this request
    - `empty_reason` string — Hint explaining why the data array is empty, when applicable
    - `has_more` boolean — Whether more items may exist beyond this response. For offset-paged endpoints, continue with a larger offset. For time-series endpoints without offset/cursor controls, true means the requested time range hit an upstream cap; narrow from/to to continue. Omitted when exhaustion cannot be proven.
    - `limit` integer, required — Maximum number of items returned in this response
    - `offset` integer, required — Number of items skipped (pagination offset)
    - `total` integer — Total number of matching items (before pagination). Omitted when total is unknown.
    - `watermark` integer — Warehouse watermark (Unix seconds) this response was computed at, on warehouse-backed endpoints (e.g. Hyperliquid /trades/aggregate) — rows up to this time come from the warehouse, newer rows from the live tail. Omitted elsewhere.

## Other responses

- `default` — Error

---

[API](https://skmtc.dev/asksurf/apis/asksurf-public-rest-api.md) · [All operations](https://skmtc.dev/asksurf/apis/asksurf-public-rest-api/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/asksurf/asksurf-public-rest-api/revisions/498f461e81c4/schema)
