vike

Recipe 7 of 33

Feed Hyperliquid cohort bias into a trading bot as an external signal

Poll the newest settled hour of a coin's realized-PnL cohort matrix with point-in-time labels, and trade only when its freshness block says the hour is not stale.

GET /v1/hl-cohorts/symbols/{symbol}/cohort-metrics with axis=pnl&labelBasis=point_in_time&hours=1 answers it in one call: the newest settled hour, one row per realized-PnL cohort, each with a bias from -1 to +1, and a freshness block on the envelope that says how old that hour is and whether it is stale. A bot polls the call, checks freshness.stale, and only then reads the bias it trades on. The full parameter list is on Coin cohort metrics.

Quick answer

Poll this; each row carries the cohort the wallet was in that hour.

cURL
# BTC smart-money matrix for the newest settled hour, labels as they were at that hour
curl -H "X-API-Key: $VIKE_API_KEY" \
  "https://data.vike.io/v1/hl-cohorts/symbols/BTC/cohort-metrics?axis=pnl&labelBasis=point_in_time&hours=1"

Example response

Captured from the live API on 2026-10-24 at 17:12 UTC, trimmed to the 3 smart cohorts of 13; label_computed shortened. freshness.behind_hours is whole hours from the newest bucket to the current hour, and stale is true once it passes settled_lag_ceiling_hours (3). On BTC at 16:00 UTC the top 1% (3x smart) held $1.79B and leaned short (bias -0.17), while 2x smart and smart leaned long.

Example response
{
  "axis": "pnl",
  "label_basis": "point_in_time",
  "metrics": [
    {
      "ts": "2026-10-24T16:00:00+00:00",
      "cohort": "3x smart",
      "position_count": 792,
      "position_count_long": 470,
      "total_position_value": 1789495937.0,
      "total_position_value_long": 740398060.4,
      "total_unrealized_pnl": -6457174.158,
      "total_position_size": 22400.51606,
      "total_position_size_long": 9268.19371,
      "bias": -0.1725065758,
      "label_basis": "point_in_time",
      "grading": "realized"
    },
    {
      "ts": "2026-10-24T16:00:00+00:00",
      "cohort": "2x smart",
      "position_count": 2165,
      "position_count_long": 1520,
      "total_position_value": 273175838.8,
      "total_position_value_long": 178920271.8,
      "total_unrealized_pnl": -1922811.317,
      "total_position_size": 3419.60655,
      "total_position_size_long": 2239.72417,
      "bias": 0.3099275,
      "label_basis": "point_in_time",
      "grading": "realized"
    },
    {
      "ts": "2026-10-24T16:00:00+00:00",
      "cohort": "smart",
      "position_count": 2484,
      "position_count_long": 1687,
      "total_position_value": 55931566.96,
      "total_position_value_long": 38706119.61,
      "total_unrealized_pnl": -609371.5268,
      "total_position_size": 700.14703,
      "total_position_size_long": 484.52053,
      "bias": 0.3840527529,
      "label_basis": "point_in_time",
      "grading": "realized"
    }
  ],
  "hours": 1,
  "unavailable_fields": [],
  "nextCursor": "eyJtIjoiY29ob3J0X21ldHJpY3MiLCJ0IjoiMjAyNi0xMC0yNCAxNjowMDowMCJ9",
  "grading": "realized",
  "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"
  },
  "freshness": {
    "newest_ts": "2026-10-24T16:00:00+00:00",
    "behind_hours": 1,
    "settled_lag_ceiling_hours": 3,
    "stale": false
  }
}

Variations

The gate and the signal in one line. Return only what the bot needs: the verdict and the three smart rows.

cURL — gate
# stale flag plus smart-cohort bias, nothing else
curl -s -H "X-API-Key: $VIKE_API_KEY" \
  "https://data.vike.io/v1/hl-cohorts/symbols/BTC/cohort-metrics?axis=pnl&labelBasis=point_in_time&hours=1" \
  | jq '{stale: .freshness.stale, smart: [.metrics[] | select(.cohort | test("smart")) | {cohort, bias}]}'

A faster, unsettled reading. /indices reads the newest 5-minute snapshot. Its latest.smart_bias is graded by today's labels, so use it for the live edge, not for history.

cURL — 5-minute
# smart-money bias at the newest 5-minute snapshot
curl -s -H "X-API-Key: $VIKE_API_KEY" \
  "https://data.vike.io/v1/hl-cohorts/symbols/BTC/indices?hours=1" \
  | jq '.latest | {ts, smart_bias, smi}'

Warm-up history for the same signal. The same call with hours=720 gives the bot 30 days of hourly bias, labelled the same way, to set its thresholds.

cURL — warm-up
# 30 days of the same matrix for calibration
curl -H "X-API-Key: $VIKE_API_KEY" \
  "https://data.vike.io/v1/hl-cohorts/symbols/BTC/cohort-metrics?axis=pnl&labelBasis=point_in_time&hours=720"

Before you rely on it

Polling only, and the signal is an hour old

There is no stream or push for this data; the bot polls. A settled hour lands one to two hours after it starts, so a few polls an hour are enough. Gate every decision on freshness.stale, which appears only when the window reaches the present (no past end). Keep labelBasis=point_in_time so live and warm-up rows are graded the same way.

Ask your agent

Connected to the Vike MCP server (https://vike.io/mcp) in Claude, ChatGPT or Cursor, ask it in plain words. The hl_cohort_metrics tool answers, at 1 credit a call.

Ask your agent
Is Hyperliquid's BTC smart-money data fresh, and how is the top 1% positioned?
Example response
{  "axis": "pnl",  "label_basis": "point_in_time",  "metrics": [    {      "ts": "2026-10-24T16:00:00+00:00",      "cohort": "3x smart",      "position_count": 792,      "position_count_long": 470,      "total_position_value": 1789495937.0,      "total_position_value_long": 740398060.4,      "total_unrealized_pnl": -6457174.158,      "total_position_size": 22400.51606,      "total_position_size_long": 9268.19371,      "bias": -0.1725065758,      "label_basis": "point_in_time",      "grading": "realized"    },    {      "ts": "2026-10-24T16:00:00+00:00",      "cohort": "2x smart",      "position_count": 2165,      "position_count_long": 1520,      "total_position_value": 273175838.8,      "total_position_value_long": 178920271.8,      "total_unrealized_pnl": -1922811.317,      "total_position_size": 3419.60655,      "total_position_size_long": 2239.72417,      "bias": 0.3099275,      "label_basis": "point_in_time",      "grading": "realized"    },    {      "ts": "2026-10-24T16:00:00+00:00",      "cohort": "smart",      "position_count": 2484,      "position_count_long": 1687,      "total_position_value": 55931566.96,      "total_position_value_long": 38706119.61,      "total_unrealized_pnl": -609371.5268,      "total_position_size": 700.14703,      "total_position_size_long": 484.52053,      "bias": 0.3840527529,      "label_basis": "point_in_time",      "grading": "realized"    }  ],  "hours": 1,  "unavailable_fields": [],  "nextCursor": "eyJtIjoiY29ob3J0X21ldHJpY3MiLCJ0IjoiMjAyNi0xMC0yNCAxNjowMDowMCJ9",  "grading": "realized",  "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"  },  "freshness": {    "newest_ts": "2026-10-24T16:00:00+00:00",    "behind_hours": 1,    "settled_lag_ceiling_hours": 3,    "stale": false  }}