# Fathom Footprint

Bid and ask volume at each price level, bar by bar.

## What the indicator shows

- Each bar is split into price levels. At each level, the volume of aggressive selling, filled at the bid, and the volume of aggressive buying, filled at the ask; on the Fathom chart, the bid is on the left and the ask on the right.
- The POC is the level with the most volume traded in the bar; the Fathom chart frames it.
- A level’s delta (ask minus bid) shows which side was more aggressive at that price. The sum over the levels gives the bar’s delta.

## How to use it

- Spot absorption: heavy aggressive volume at an extreme without price moving on shows passive orders soaking up the aggression.
- Follow where the POC sits: at the top of the bar, volume traded at the highs; at the bottom, at the lows.
- Compare bid and ask on neighboring levels to see where one side takes over. The `imbalances` indicator keeps only those zones.
- Raise `groupTicks` for a more condensed reading on a fast instrument. `filterMin` and `filterMax` only count trades of a given size, for example large lots.

## How it is computed

- Bars last `timeframe` seconds, from 1 second to 1 hour, and start on multiples of `timeframe` from midnight UTC (9:30, 9:35… with 5 minutes). A bar with no counted trade is not sent.
- Levels are aligned on multiples of `groupTicks` ticks: a level’s price is the bottom of its group, so with `groupTicks: 4` the first level can be below the bar’s `low`.
- `levels` volumes only count trades whose volume is between `filterMin` and `filterMax`. The OHLC (`open`, `high`, `low`, `close`) is computed on all the bar’s trades, counted or not.
- A level’s bid volume comes from aggressive sellers (hitting the bid), its ask volume from aggressive buyers. Level volume = `l[1] + l[2] + (l[3] ?? 0)`; delta = `l[2] − l[1]`.

## When it updates

- The bar is sent once, final, on the first trade of a later bar; nothing is sent while it is in progress. The last bar before the 5:00 pm New York break therefore only arrives at the 6:00 pm reopen, and Friday’s last bar on Sunday evening.

- No reset: each bar is independent.

- **Identifier**: `footprint`

- **Objects received**: `bar`

- **Historical cost**: 1 compute unit per trade

## Subscribe

The same `params` work in [real time](https://fathomcharts.com/docs/websocket.md), on [historical data](https://fathomcharts.com/docs/history.md) and in exports. Parameters you omit take their default values.

**Subscribe message**

```json
{
  "t": "subscribe",
  "sub": "footprint",
  "instrument": "NQ.front",
  "indicator": "footprint",
  "params": {
    "filterMax": 0,
    "filterMin": 0,
    "groupTicks": 1,
    "timeframe": 15
  },
  "mode": "live",
  "from": "live"
}
```

## Parameters

As soon as a parameter differs from its default, the subscription counts as a [custom configuration](https://fathomcharts.com/docs/limits.md#how-limits-are-counted). To change a parameter, open a new subscription.

| Parameter    | Type    | Default | Allowed values                                                                                  | Unit      | Description                                                                              |
| ------------ | ------- | ------- | ----------------------------------------------------------------------------------------------- | --------- | ---------------------------------------------------------------------------------------- |
| `filterMax`  | integer | `0`     | 0 to 1,000,000                                                                                  | contracts | Maximum volume for a trade to be counted; 0 = unlimited, otherwise at least `filterMin`. |
| `filterMin`  | integer | `0`     | 0 to 1,000,000                                                                                  | contracts | Minimum volume for a trade to be counted; 0 = no minimum.                                |
| `groupTicks` | integer | `1`     | 1 to 100                                                                                        | ticks     | Number of ticks grouped into each price level.                                           |
| `timeframe`  | integer | `15`    | `1` · `5` · `10` · `15` · `30` · `60` · `120` · `180` · `300` · `600` · `900` · `1800` · `3600` | —         | Bar duration in seconds: from 1 second (`1`) to 1 hour (`3600`).                         |

## Objects received

Each object keeps the same `id` from one update to the next. Its data is in the `data` field. Prices are in ticks: multiply them by the instrument’s tick size (`GET /v1/instruments`) to get points.

### `bar` (sent final)

Finished bar that starts at `barStartNs`, sent on the first trade of a later bar.

`id` format: `<barStartNs>`. Each object is sent once, final (`final: true`).

| Field    | Type    | Unit  | Present | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| -------- | ------- | ----- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `close`  | integer | ticks | always  | Close: price of the bar’s last trade, counted or not.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `high`   | integer | ticks | always  | High of the bar, over all its trades.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `levels` | array   | —     | always  | Levels by ascending price: `[price (ticks), bid volume (contracts), ask volume (contracts)]`, plus a 4th element when the level holds trades whose aggressor is not identified (their volume, in contracts): `[122008, 14, 3, 2]` counts 14 contracts at the bid, 3 at the ask and 2 without an identified aggressor. Bid volume comes from aggressive sellers (hitting the bid), ask volume from aggressive buyers. A level’s price is the bottom of its `groupTicks`-tick group. Level volume = `l[1] + l[2] + (l[3] ?? 0)`; delta = `l[2] − l[1]`. |
| `low`    | integer | ticks | always  | Low of the bar, over all its trades.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `open`   | integer | ticks | always  | Open: price of the bar’s first trade, counted or not.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `poc`    | integer | ticks | always  | Price of the bar’s highest-volume level. On a tie: the lowest of the tied levels at or above the open’s level, otherwise the highest of those below it.                                                                                                                                                                                                                                                                                                                                                                                               |

## Example messages

Messages as the WebSocket sends them to the subscription above, taken from a real NQ session. [Historical data](https://fathomcharts.com/docs/history.md) returns the same objects, with the same `cursor`, without the `sub` field.

**Final object**

```json
{
  "sub": "footprint",
  "cursor": "20720.0.0",
  "t": "upsert",
  "id": "1790207985000000000",
  "final": true,
  "ts": "1790208000058746563",
  "data": {
    "open": 123032,
    "high": 123032,
    "low": 123012,
    "close": 123014,
    "levels": [
      [
        123012,
        1,
        0
      ],
      [
        123014,
        0,
        1
      ],
      [
        123015,
        1,
        0
      ],
      [
        123016,
        2,
        0
      ],
      [
        123017,
        1,
        0
      ],
      [
        123018,
        1,
        0
      ],
      [
        123020,
        3,
        1
      ],
      [
        123022,
        1,
        0
      ],
      [
        123024,
        1,
        0
      ],
      [
        123025,
        0,
        1
      ],
      [
        123026,
        0,
        1
      ],
      [
        123027,
        0,
        2
      ],
      [
        123032,
        0,
        1
      ]
    ],
    "poc": 123020
  }
}
```

## JSON schemas

To validate or type your data: the JSON schemas of the parameters and of `data`, also available from `GET /v1/indicators`. The SDK can [generate types from them](https://fathomcharts.com/docs/sdk.md#indicator-types).

**Parameters schema**

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://fathomcharts.com/schemas/footprint/params.json",
  "type": "object",
  "additionalProperties": false,
  "properties": {
    "filterMax": {
      "description": "Maximum volume for a trade to be counted; 0 = unlimited, otherwise at least `filterMin`.",
      "type": "integer",
      "default": 0,
      "minimum": 0,
      "maximum": 1000000
    },
    "filterMin": {
      "description": "Minimum volume for a trade to be counted; 0 = no minimum.",
      "type": "integer",
      "default": 0,
      "minimum": 0,
      "maximum": 1000000
    },
    "groupTicks": {
      "description": "Number of ticks grouped into each price level.",
      "type": "integer",
      "default": 1,
      "minimum": 1,
      "maximum": 100
    },
    "timeframe": {
      "description": "Bar duration in seconds: from 1 second (`1`) to 1 hour (`3600`).",
      "type": "integer",
      "default": 15,
      "enum": [
        1,
        5,
        10,
        15,
        30,
        60,
        120,
        180,
        300,
        600,
        900,
        1800,
        3600
      ]
    }
  }
}
```

**`data` field schema**

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://fathomcharts.com/schemas/footprint/data.json",
  "title": "bar",
  "type": "object",
  "additionalProperties": false,
  "properties": {
    "close": {
      "description": "Close: price of the bar’s last trade, counted or not.",
      "type": "integer"
    },
    "high": {
      "description": "High of the bar, over all its trades.",
      "type": "integer"
    },
    "levels": {
      "description": "Levels by ascending price: `[price (ticks), bid volume (contracts), ask volume (contracts)]`, plus a 4th element when the level holds trades whose aggressor is not identified (their volume, in contracts): `[122008, 14, 3, 2]` counts 14 contracts at the bid, 3 at the ask and 2 without an identified aggressor. Bid volume comes from aggressive sellers (hitting the bid), ask volume from aggressive buyers. A level’s price is the bottom of its `groupTicks`-tick group. Level volume = `l[1] + l[2] + (l[3] ?? 0)`; delta = `l[2] − l[1]`.",
      "type": "array",
      "items": {
        "type": "array",
        "maxItems": 4,
        "minItems": 3,
        "prefixItems": [
          {
            "type": "integer"
          },
          {
            "type": "integer"
          },
          {
            "type": "integer"
          },
          {
            "type": "integer"
          }
        ]
      }
    },
    "low": {
      "description": "Low of the bar, over all its trades.",
      "type": "integer"
    },
    "open": {
      "description": "Open: price of the bar’s first trade, counted or not.",
      "type": "integer"
    },
    "poc": {
      "description": "Price of the bar’s highest-volume level. On a tie: the lowest of the tied levels at or above the open’s level, otherwise the highest of those below it.",
      "type": "integer"
    }
  },
  "required": [
    "open",
    "high",
    "low",
    "close",
    "levels",
    "poc"
  ]
}
```
