# Node classification and velocity

> How the Heatseeker API labels each strike (King, Gatekeeper, Pika, Barney) and how velocityPct is calculated.

Every strike in a `/v1/heatmap` or `/v1/historical` response carries a `nodeType`.
`/v1/gex/levels` returns only the classified strikes. This page defines exactly how
those labels and the live `velocityPct` are computed.

## The value being classified

`value` is the strike's **net, signed** exposure for the requested `metric` (gamma or
vanna), **summed across the returned expirations**:

- By default the response nets the **nearest 5 expirations**.
- Use `maxExpirations` to net more or fewer, or `expirations` to name the exact ones.
- The `expirations` array in the response tells you which ones were included.

The sign is kept. Ranking for King and Gatekeeper uses the **absolute** value; Pika and
Barney use the sign.

Classification runs over the **strikes returned**: 92 around spot by default, or set
`maxStrikes`. The King is the largest strike in that window, not across the whole chain.

### One expiration on its own

- Pass a single date, for example `expirations=2026-10-02`. `value` and `nodeType` are then
  computed from that expiration alone.
- Or add `layout=matrix` to receive the full grid (one row per strike, one column per
  expiration) with each strike × expiration value. `value` and `nodeType` still use the
  summed total.

## Node types

Each strike gets exactly **one** type, assigned in this order of precedence:

| `nodeType` | Rule |
|---|---|
| `king` | The single strike with the largest absolute `value`. |
| `gatekeeper` | Any other strike whose absolute `value` is **at least 25% of the King's**. |
| `pika` | The **3 largest positive** strikes that are not King or Gatekeeper. |
| `barney` | The **3 most negative** strikes that are not King, Gatekeeper or Pika. |
| `normal` | Every other strike. |

So the Gatekeeper threshold is a percent of the King's magnitude (the same idea as
"P25" in the web app's Nodes setting), not a percentile of the strike distribution.

> **Note:** `significant` appears in the schema's list of values but is **not currently returned**
> by the API. In Skylit alerts it means your top-N nodes by absolute value (default 5).
> To get that from the API, sort strikes by `abs(value)` and take the top N.

## velocityPct

`velocityPct` is the live percent change of a strike's `value` versus the snapshot
**5 minutes earlier**, matched by strike:

```
velocityPct = (value - value_5_minutes_ago) / |value_5_minutes_ago| * 100
```

- Returned on `/v1/heatmap` (live) only. It is omitted on `/v1/historical`.
- It reads `0` when there is no snapshot from 5 minutes earlier yet (for example right
  after the open), for a strike that did not exist 5 minutes ago, or when that strike's
  value 5 minutes ago was 0.
