vike

Cohort history

One cohort's hourly long, short and bias summed over every symbol, from 2026-04-07; include=leverage adds the cohort's perp bias and exposure against its equity.

GET https://data.vike.io/v1/hl-cohorts/segments/{cohort}/history

One cohort's long, short and bias per hour, summed over every symbol: the cohort's history across the whole book, newest hour first. Two axes, size and pnl, and axis is required — any other axis is a 400. The labels are point-in-time on both: size is stored on the position row, and pnl is the realized ladder as it stood at the time — the hour's own label from 2026-08-06, the day's before it — which the envelope's label_computed declares. Nothing before data_from (2026-04-07) is served.

/segments/{cohort}/summary is the same cohort at the latest snapshot; this is its hourly series.

cURL
# the last week of whale positioning across the whole book, newest hour first
curl -s "https://data.vike.io/v1/hl-cohorts/segments/whale/history?axis=size" \
  -H "X-API-KEY: $VIKE_API_KEY"

# smart money's hourly bias over 30 days: a pnl label needs axis=pnl, and the slug stands in for the label
curl -s "https://data.vike.io/v1/hl-cohorts/segments/3x_smart/history?axis=pnl&hours=720" \
  -H "X-API-KEY: $VIKE_API_KEY" \
  | jq '[.series[] | {ts, bias}]'

# a pinned month: start and end are ISO-8601 UTC, and end is inclusive
curl -s "https://data.vike.io/v1/hl-cohorts/segments/4x_whale/history?axis=size&start=2026-09-01T00:00:00Z&end=2026-09-30T23:00:00Z" \
  -H "X-API-KEY: $VIKE_API_KEY"

# a short page: the newest 24 hours of the default week; has_more says older ones remain
curl -s "https://data.vike.io/v1/hl-cohorts/segments/4x_whale/history?axis=size&limit=24" \
  -H "X-API-KEY: $VIKE_API_KEY"

# the page before it: END is the oldest ts of the call just above minus 1 second
curl -s "https://data.vike.io/v1/hl-cohorts/segments/4x_whale/history?axis=size&limit=24&end=$END" \
  -H "X-API-KEY: $VIKE_API_KEY"

# leverage per hour beside long and short: the cohort's perp bias and exposure against its own equity
curl -s "https://data.vike.io/v1/hl-cohorts/segments/4x_whale/history?axis=size&hours=48&include=leverage" \
  -H "X-API-KEY: $VIKE_API_KEY" \
  | jq '[.series[] | {ts, bias, perp_bias, equity_exposure, equity_covered_share}]'
cohortpathrequired
A label or slug of axis, from /cohorts / /segments
axisqueryrequired
size | pnl: this endpoint serves history for these two only. Required.
startqueryoptional
ISO-8601 UTC. Oldest edge. Omit it for the hours newest hours.
endqueryoptional
ISO-8601 UTC. Newest edge; with no start, the window is the hours newest hours at or before it.
hoursqueryoptional
Window length in hours when start is omitted. Default 168, max 8760.
limitqueryoptional
Max rows, newest first, default and max 5000; has_more says there are older ones (page back with end = the oldest ts minus 1 second; end is inclusive).
includequeryoptional
Comma list; only leverage, default none (nothing extra is read). Adds to every row perp_bias = (long - short) / equity, equity_exposure = (long + short) / equity and equity_covered_share = main-dex notional of the counted wallets / main-dex notional of the whole cohort: unbounded ratios (above 1 = more than 1x of equity), native perp account only (main-dex positions of wallets with a known positive native equity, each wallet once; builder-DEX positions are not included). An hour with no stored row, and any hour before leverage.data_from (2026-08-11), is null on all three (never 0). perp_bias and equity_exposure are also null when no counted wallet has a positive equity; equity_covered_share is null when the cohort holds no main-dex notional and a real 0 when it holds some but no wallet is counted. Hours rebuilt from fills rather than read from snapshots are null. An unknown token is a 400.
Example response
{
  "axis": "pnl",
  "cohort": "3x smart",
  "label_basis": "point_in_time",
  "data_from": "2026-04-07T00:00:00+00:00",
  "series": [
    {
      "ts": "2026-10-24T06:00:00+00:00",
      "long_usd": 3539759197.0,
      "short_usd": 4440124719.0,
      "bias": -0.112829,
      "position_count": 21418,
      "perp_bias": -0.4575988062,
      "equity_exposure": 4.688357438,
      "equity_covered_share": 0.9999966347
    },
    {
      "ts": "2026-10-24T05:00:00+00:00",
      "long_usd": 3544735940.0,
      "short_usd": 4438182428.0,
      "bias": -0.11192,
      "position_count": 21441,
      "perp_bias": -0.4526158507,
      "equity_exposure": 4.692875987,
      "equity_covered_share": 0.9997107427
    }
  ],
  "has_more": false,
  "label_computed": {
    "grading": "realized",
    "label_basis": "point_in_time",
    "when": "before 2026-08-06, reconstructed from fills on 2026-08-17; from 2026-08-06, frozen on the position row at its own hour",
    "lookahead": false,
    "resolution": "daily before 2026-08-06, hourly after",
    "source": "hourly cohort snapshots",
    "detail": "Two point-in-time definitions meeting at 2026-08-06. Before it: day D's label is the wallet's rank by cumulative closed PnL as of the END of D-1, reconstructed from fills by the 2026-08-17 rebuild — so a label is constant across D's 24 hours. From it: the hourly rollup stamps the dictionary value as of that hour onto the row, so the label moves within a day. Neither half can see the future, but a series crossing the seam changes its label RESOLUTION, which a difference or a turnover count will read as a regime change that is an artefact.",
    "caveat": "Rows before 2026-08-06 carry no label frozen at write time: their label is the daily reconstruction described above, not a value stamped on the row at its own hour. From 2026-08-06 the label is frozen on the row and does not change."
  },
  "leverage": {
    "data_from": "2026-08-11T00:00:00+00:00",
    "scope": "native perp account only; main-dex positions of wallets with a known positive native equity",
    "note": "hours rebuilt from fills are null"
  }
}

The response

FieldWhat it is
axissize or pnl.
cohortThe cohort's label. A slug in the path comes back as the label it stands for (3x_smart → 3x smart).
label_basisAlways point_in_time.
data_from2026-04-07T00:00:00+00:00, the first hour served on either axis.
label_computedaxis=pnl only: when the labels were computed — hourly from 2026-08-06; before it daily, day D graded on the cumulative realized PnL as of the end of D−1. Absent on size, a stored column with no grading to describe.
seriesOne row per hour, newest first.
has_moretrue when the window holds older rows than limit returned.
leverageinclude=leverage only: data_from, scope and note, below.

Each row of series:

FieldWhat it is
tsThe hour, ISO-8601 UTC.
long_usd, short_usdThe cohort's long and short notional in that hour, USD, summed over every symbol.
bias(long − short) / (long + short), a ratio in [−1, +1]. null when both are 0.
position_countPositions, that is (wallet, symbol) pairs — not a wallet count. The aggregate keeps one count per symbol, which cannot be de-duplicated across symbols.

The window and paging

The window is start as given, or else the hours newest hours at or before end (default 168, max 8760). Only settled hours are served: the hour in progress never is. At most limit rows come back (default and max 5000), newest first; has_more says older ones exist. Page back with end = the oldest ts minus 1 second: end is inclusive, so passing the oldest ts itself repeats that row. A start more than 8760 hours before end (or now, when end is omitted) is a 400.

include=leverage

A comma list; leverage is its only token, and anything else is a 400. Without it the response has none of these three fields and nothing extra is read. With it, every row of series gains three ratios for its hour:

FieldDefinition
perp_bias(long − short) / equity
equity_exposure(long + short) / equity
equity_covered_sharemain-dex notional of the counted wallets / main-dex notional of the whole cohort

They are the native perp account only. A wallet is counted when it holds a main-dex position that hour and has a known, positive native perp equity; long and short are the counted wallets' main-dex notional, and equity is their native perp account value, each wallet once. Builder-DEX positions are not included. equity_covered_share is how much of the cohort's main-dex notional those counted wallets hold, so it says how much of the cohort the other two ratios describe. These are the three fields /segments/{cohort}/summary serves for the latest snapshot, here per hour. The ratios are unbounded: above 1 means more than 1x of equity.

The envelope declares the block:

leverage
{
  "data_from": "2026-08-11T00:00:00+00:00",
  "scope": "native perp account only; main-dex positions of wallets with a known positive native equity",
  "note": "hours rebuilt from fills are null"
}

When a ratio is null, never 0:

  • every hour before leverage.data_from (2026-08-11) is null on all three, and a window wholly before it does not read the leverage table at all;
  • an hour with no stored leverage row is null on all three;
  • an hour rebuilt from fills is null on all three: the equity stored for it is not a measurement, so it is left out at read time, and leverage.note says so;
  • with a row, perp_bias and equity_exposure are null when no counted wallet has a positive equity, and equity_covered_share is null when the cohort holds no main-dex notional. A cohort that holds main-dex notional but has no counted wallet gets a real 0 share.

has_more and the paging are the series' own; include does not change them.

Errors

StatusWhen
400axis is not size or pnl, start or end is not ISO-8601, start is more than 8760 hours before end, or include names a token other than leverage. The body is {"detail": "…"}.
404cohort is not a label or slug of axis. The body names the axis only: {"detail": "unknown cohort for axis 'size'"}.
422axis is missing, or hours is above 8760 or limit above 5000.
401 / 429No or bad credential, or the hourly budget or the per-minute cap is spent — see Authentication and Rate limits.
503The store behind it is unavailable.

The ladders and their labels are on Cohorts and axes; when a label was computed is on Label basis.

Example response
{  "axis": "pnl",  "cohort": "3x smart",  "label_basis": "point_in_time",  "data_from": "2026-04-07T00:00:00+00:00",  "series": [    {      "ts": "2026-10-24T06:00:00+00:00",      "long_usd": 3539759197.0,      "short_usd": 4440124719.0,      "bias": -0.112829,      "position_count": 21418,      "perp_bias": -0.4575988062,      "equity_exposure": 4.688357438,      "equity_covered_share": 0.9999966347    },    {      "ts": "2026-10-24T05:00:00+00:00",      "long_usd": 3544735940.0,      "short_usd": 4438182428.0,      "bias": -0.11192,      "position_count": 21441,      "perp_bias": -0.4526158507,      "equity_exposure": 4.692875987,      "equity_covered_share": 0.9997107427    }  ],  "has_more": false,  "label_computed": {    "grading": "realized",    "label_basis": "point_in_time",    "when": "before 2026-08-06, reconstructed from fills on 2026-08-17; from 2026-08-06, frozen on the position row at its own hour",    "lookahead": false,    "resolution": "daily before 2026-08-06, hourly after",    "source": "hourly cohort snapshots",    "detail": "Two point-in-time definitions meeting at 2026-08-06. Before it: day D's label is the wallet's rank by cumulative closed PnL as of the END of D-1, reconstructed from fills by the 2026-08-17 rebuild — so a label is constant across D's 24 hours. From it: the hourly rollup stamps the dictionary value as of that hour onto the row, so the label moves within a day. Neither half can see the future, but a series crossing the seam changes its label RESOLUTION, which a difference or a turnover count will read as a regime change that is an artefact.",    "caveat": "Rows before 2026-08-06 carry no label frozen at write time: their label is the daily reconstruction described above, not a value stamped on the row at its own hour. From 2026-08-06 the label is frozen on the row and does not change."  },  "leverage": {    "data_from": "2026-08-11T00:00:00+00:00",    "scope": "native perp account only; main-dex positions of wallets with a known positive native equity",    "note": "hours rebuilt from fills are null"  }}