Skip to main content
Glama

Hyperliquid Cohort Metrics

hl_cohort_metrics
Read-onlyIdempotent

Hourly long/short positioning of ONE Hyperliquid perp split by cohort: every bucket of one ladder, every hour, in one call (the matrix behind 'are whales / smart money long or short BTC'). axis picks the ladder: size (account value), pnl (percentile of cumulative realized PnL), pnl_abs (realized PnL in dollar bands), pnl_unrealized (currently onside), tier (each position's own notional). Data from 2026-04-07 (the first hour cohort labels are correct); an older start is served from there and the envelope says data_from. Rows are hour x cohort: n_wallets (wallets in the cohort holding the symbol), notional in USD (total_position_value, total_position_value_long) and bias = (long - short) / (long + short), a fraction from -1 (all short) to +1 (all long), not a percent. BACKTESTS: by default the pnl cohort is TODAY's grading applied to past hours (look-ahead); pass label_basis=point_in_time for each hour's label as it was, and read label_computed and freshness in the envelope. The hour in progress is never included. The response holds about hours x 12-13 rows: pass a small hours (1-24) for a current read and page older data with cursor. With include (volume, median_pnl; size or pnl axis) the newest hour's rows also carry each cohort's 24-hour fill volume and the median realized PnL of its wallets, in USD, computed at request time. Same data as GET /v1/hl-cohorts/symbols/{symbol}/cohort-metrics.

Tool call template

Replace each placeholder with a value matching the input schema. Only required parameters are included; add optional parameters as needed.

{
  "id": 1,
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "arguments": {
      "symbol": "<symbol>"
    },
    "name": "hl_cohort_metrics"
  }
}

Input Schema

NameRequiredDescriptionDefault
endNoISO-8601 UTC upper bound, e.g. 2026-10-02T00:00:00Z.
axisNoLadder to split by: `size` (account value), `pnl` (percentile of cumulative realized PnL), `pnl_abs` (realized PnL in dollar bands), `tier` (each position's own notional bucket; `trade_size` is an alias of it), `pnl_unrealized` (currently onside).size
hoursNoNumber of hourly buckets, newest first; the response holds about this many x 12-13 cohort rows. Pass 1-24 for a current read. Max 8760.
startNoISO-8601 UTC lower bound, e.g. 2026-10-01T00:00:00Z. The hour in progress is never returned.
cursorNoCursor over HOURS: `nextCursor` from the previous page, verbatim.
symbolYesHyperliquid instrument ticker, e.g. BTC, ETH, HYPE; a HIP-3 market is `dex:TICKER`, e.g. xyz:TSLA. Required: an all-symbol matrix is refused.
gradingNoWhich PnL grading labels each wallet (axis `pnl` or `pnl_unrealized` only): `realized` (default on `pnl`), `realized-pit` (a control rebuilt once a day through 23:00 of the last complete UTC day, so a recent window comes back 1 to 25 hours short; read `freshness.behind_hours`) or `unrealized`. For live trading use `realized` with label_basis=point_in_time.
includeNoComma list of `volume`, `median_pnl`; default none. Adds to the NEWEST hour's rows `volume_24h_usd` (USD the cohort's wallets filled in this symbol in the last 24 hours; on `size` only wallets holding it now count; null if they filled nothing or the cohort is empty) and `median_realized_pnl_usd` (USD, median cumulative realized PnL over the DISTINCT wallets holding the symbol now; null if none does). The median is a sampled quantile: exact up to 8,192 wallets in a cohort, an estimate above it; the asset page's pnl-axis "Med Lifetime" counts positions rather than wallets, so it can differ slightly. Both are current figures, not that hour's, and null on `unknown`. Only `axis=size` or `axis=pnl` with the default grading; refused with opened_within, cursor or a past `end`.
label_basisNo`point_in_time` returns each hour's cohort label AS IT WAS: use it for every backtest (axis=pnl). Every field is served while each hour of the page carries that label on its rows: every hour from 2026-08-06 09:00 UTC and most earlier ones. A page reaching an hour without it (all of April 2026, about 365 hours from May to 2026-08-06 08:00) comes from the hourly aggregate, where position_count*, total_unrealized_pnl and total_position_size* are null, named in `unavailable_fields`. Without it a `pnl` cohort is TODAY's grading applied to past hours (look-ahead). `size`, `tier` and `pnl_unrealized` are always point-in-time; `pnl_abs` is always today's bands (look-ahead, never for a backtest); a conflicting value is refused.
opened_withinNoOnly positions opened within this window BEFORE EACH HOUR (rolling per bucket, not relative to now): `24h`, `7d`, `30d` or `all`. Applied on `size`, `tier`, `pnl_abs` and `pnl` with the default label basis; REFUSED (anything but `all`) with `axis=pnl_unrealized`, `grading=unrealized` or `realized-pit`, and `label_basis=point_in_time`, whose stored sources sum position age away.all

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed1 schema field changed
    • changedInput schema / properties / label_basis / description
      Previous value: -"`point_in_time` returns each hour's cohort label AS IT WAS: use it for every backtest (axis=pnl; rows then omit position_count*, total_unrealized_pnl and total_position_size*). Without it a `pnl` cohort is TODAY's grading applied to past hours (look-ahead). `size`, `tier` and `pnl_unrealized` are always point-in-time; `pnl_abs` is always today's bands (look-ahead, never for a backtest); a conflicting value is refused."New value: +"`point_in_time` returns each hour's cohort label AS IT WAS: use it for every backtest (axis=pnl). Every field is served while each hour of the page carries that label on its rows: every hour from 2026-08-06 09:00 UTC and most earlier ones. A page reaching an hour without it (all of April 2026, about 365 hours from May to 2026-08-06 08:00) comes from the hourly aggregate, where position_count*, total_unrealized_pnl and total_position_size* are null, named in `unavailable_fields`. Without it a `pnl` cohort is TODAY's grading applied to past hours (look-ahead). `size`, `tier` and `pnl_unrealized` are always point-in-time; `pnl_abs` is always today's bands (look-ahead, never for a backtest); a conflicting value is refused."
  2. Changed1 schema field changed
    • changedInput schema / properties / grading / description
      Previous value: -"Which PnL grading labels each wallet (axis `pnl` or `pnl_unrealized` only): `realized` (default on `pnl`), `realized-pit` (a frozen control: it stops growing, so a recent window comes back short; read `freshness.behind_hours`) or `unrealized`. For live trading use `realized` with label_basis=point_in_time."New value: +"Which PnL grading labels each wallet (axis `pnl` or `pnl_unrealized` only): `realized` (default on `pnl`), `realized-pit` (a control rebuilt once a day through 23:00 of the last complete UTC day, so a recent window comes back 1 to 25 hours short; read `freshness.behind_hours`) or `unrealized`. For live trading use `realized` with label_basis=point_in_time."
  3. First observed

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly/idempotent/non-destructive, and the description still adds substantial behavior beyond them: the 2026-04-07 data floor with `data_from` in the envelope, the look-ahead default for the `pnl` cohort, `label_computed`/`freshness` signaling, null `unavailable_fields` on older pages, and the sampled-quantile caveat on the median. It also discloses response size (~hours x 12-13 rows), which matters for paging decisions.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Purpose and scope are front-loaded in the first sentence, and the dense length is largely justified by a 10-parameter tool with several interacting refusal rules. It loses a point for a single unbroken paragraph with heavy ALL-CAPS emphasis and for restating axis definitions that already live in the schema.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema, and the description compensates fully: it defines the row grain (hour x cohort), names the returned fields (`n_wallets`, `total_position_value`, `total_position_value_long`, `bias`) and defines `bias` precisely as a -1 to +1 fraction rather than a percent. Nothing an agent needs to call or interpret this correctly appears to be missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% and the description largely restates the schema's own parameter documentation (the `axis` ladder, `hours`, `cursor`, `grading`, `include`, `label_basis`, `opened_within`). It adds some relational framing — which axes are always point-in-time, which combinations are refused — but most of that is also mirrored in the schema text, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The first sentence names a specific verb and resource: hourly long/short positioning of ONE Hyperliquid perp split by cohort, and frames it concretely as the matrix behind 'are whales / smart money long or short BTC'. It also scopes the tool to a single symbol and points at the underlying REST endpoint, which is enough for an agent to separate it from aggregate siblings like perp_long_short or wallet_positions.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit when-to-use rules: pass a small `hours` (1-24) for a current read, page older data with `cursor`, and use label_basis=point_in_time for every backtest. It also states when-not: the hour in progress is never included, and `include` is refused with opened_within, cursor or a past `end`. Alternatives and refusal conditions are named rather than inferred.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.