Fathom Walls
Liquidity walls defending repeated highs or lows.
What the indicator shows
- A sell wall sits on a high tested several times, where aggressive buying stalls without breaking the level; the Fathom chart marks it with an S.
- A buy wall sits on a low tested several times, where aggressive selling stalls; the Fathom chart marks it with a B.
- In both cases, passive orders absorb the aggression: the level is defended.
How to use it
- A wall gives a level to trade for a bounce while it holds, or to watch for a breakout if it gives way.
- Start with the looser settings described below (about one signal per hour on NQ), then tighten the criteria to keep only the clearest walls. Stricter criteria do not guarantee that a level will hold.
How it is computed
- The test runs when each
timeframe-second bar closes. A bar is a candidate for a sell wall when its high reaches those of the two previous bars (its low, for a buy wall). - The tested group (cluster) starts at a recent candidate bar and gathers every later candidate up to the closed bar, at least
minimumBarsbars in all. Its first bar is less thannearnessBarsbars old, and the closed bar does not exceed that bar’s high by more thantickBreakoutMarginticks: a candidate that no longer meets these conditions is dropped. The closed bar’s high must be less thantickGroupingticks from the group’s high. Groups are tried from the oldest candidate to the most recent. - A cell is one price level of one bar of the group, within the
tickGroupingticks below the group’s high (above its low, for a buy wall). - A wall is signaled when at least
minimumBarscells each reachminPerBarVolumecontracts, the cells’ total volume exceedsminClusterVolumeand the share of aggressive volume stalling on the wall (sideVolume / volume) exceedsminDeltaPercent%; these last two thresholds are exclusive, so withminDeltaPercent: 100no wall is possible. Despite their names,minimumBarsalso counts cells,minPerBarVolumeapplies to each cell, andminDeltaPercentis not a delta but that share of aggressive volume. - The defaults are strict: on NQ or ES, they give few walls, sometimes none over a whole session. For about one signal per hour on NQ, set
minPerBarVolume: 10,minClusterVolume: 30,minDeltaPercent: 40andtickGrouping: 4, keeping the other parameters at their defaults (these are the parameters of the examples). The stricter the parameters, the fewer the walls.
When it updates
- At most one signal per bar, sent final when the bar closes; the sell wall is tested first.
- Weekly reset: at the Sunday reopen (6:00 pm New York time), the previous week’s highs and lows no longer count.
- Identifier
liquidity-walls- Objects received
signal- Historical cost
- 1 compute unit per trade
Subscribe
The same params work in real time, on historical data and in exports. Parameters you omit take their default values.
{
"t": "subscribe",
"sub": "liquidity-walls",
"instrument": "NQ.front",
"indicator": "liquidity-walls",
"params": {
"minClusterVolume": 30,
"minDeltaPercent": 40,
"minPerBarVolume": 10,
"minimumBars": 2,
"nearnessBars": 20,
"tickBreakoutMargin": 1,
"tickGrouping": 4,
"timeframe": 60
},
"mode": "live",
"from": "live"
}These example parameters differ from the defaults: minClusterVolume 30 (default 400), minDeltaPercent 40 (default 70), minPerBarVolume 10 (default 100), tickGrouping 4 (default 1). This subscription therefore counts as a custom configuration; the Sandbox allows 1.
Parameters
As soon as a parameter differs from its default, the subscription counts as a custom configuration. To change a parameter, open a new subscription.
| Parameter | Type | Default | Allowed values | Unit | Description |
|---|---|---|---|---|---|
minClusterVolume | integer | 400 | 0 to 10,000,000 | contracts | Total volume the wall’s cells must exceed (exclusive). |
minDeltaPercent | integer | 70 | 0 to 100 | % | Minimum share (exclusive) of the wall’s cell volume made up of aggressive volume stalling against it: buying for a sell wall, selling for a buy wall. |
minPerBarVolume | integer | 100 | 0 to 1,000,000 | contracts | Minimum volume for a cell (one price level of one bar of the wall) to count. |
minimumBars | integer | 2 | 2 to 100 | — | Minimum number of cells whose volume reaches minPerBarVolume, and of candidate bars in the cluster. |
nearnessBars | integer | 20 | 1 to 1,000 | bars | Maximum age of a high or low in the cluster, in bars. |
tickBreakoutMargin | integer | 1 | 0 to 100 | ticks | How far price may go past a high (or a low) before it stops counting for the wall. |
tickGrouping | integer | 1 | 1 to 100 | ticks | Depth of the wall, below the cluster’s high (or above its low); the tested bar must reach this band. |
timeframe | integer | 60 | 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.
signal sent final
Signal of the finished bar that starts at barStartNs.
id format: <barStartNs>. Each object is sent once, final (final: true).
| Field | Type | Unit | Present | Description |
|---|---|---|---|---|
cells | integer | — | always | Number of cells (one price level of one bar of the wall) whose volume reaches minPerBarVolume. |
price | integer | ticks | always | High (sell wall) or low (buy wall) of the bar that tests the wall. |
side | string · buy | sell | — | always | sell: sell wall at the high; buy: buy wall at the low. |
sideVolume | integer | contracts | always | Aggressive volume that stalled on the wall, in those cells: buying (ask) for a sell wall, selling (bid) for a buy wall. |
volume | integer | contracts | always | Total volume of the wall’s cells. |
Example messages
Messages as the WebSocket sends them to the subscription above, taken from a real NQ session. Historical data returns the same objects, with the same cursor, without the sub field.
{
"sub": "liquidity-walls",
"cursor": "20720.13976.0",
"t": "upsert",
"id": "1790217900000000000",
"final": true,
"ts": "1790217960047941663",
"data": {
"price": 122988,
"side": "sell",
"volume": 186,
"sideVolume": 162,
"cells": 4
}
}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.
Parameters schema
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://fathomcharts.com/schemas/liquidity-walls/params.json",
"type": "object",
"additionalProperties": false,
"properties": {
"minClusterVolume": {
"description": "Total volume the wall’s cells must exceed (exclusive).",
"type": "integer",
"default": 400,
"minimum": 0,
"maximum": 10000000
},
"minDeltaPercent": {
"description": "Minimum share (exclusive) of the wall’s cell volume made up of aggressive volume stalling against it: buying for a sell wall, selling for a buy wall.",
"type": "integer",
"default": 70,
"minimum": 0,
"maximum": 100
},
"minPerBarVolume": {
"description": "Minimum volume for a cell (one price level of one bar of the wall) to count.",
"type": "integer",
"default": 100,
"minimum": 0,
"maximum": 1000000
},
"minimumBars": {
"description": "Minimum number of cells whose volume reaches `minPerBarVolume`, and of candidate bars in the cluster.",
"type": "integer",
"default": 2,
"minimum": 2,
"maximum": 100
},
"nearnessBars": {
"description": "Maximum age of a high or low in the cluster, in bars.",
"type": "integer",
"default": 20,
"minimum": 1,
"maximum": 1000
},
"tickBreakoutMargin": {
"description": "How far price may go past a high (or a low) before it stops counting for the wall.",
"type": "integer",
"default": 1,
"minimum": 0,
"maximum": 100
},
"tickGrouping": {
"description": "Depth of the wall, below the cluster’s high (or above its low); the tested bar must reach this band.",
"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": 60,
"enum": [
1,
5,
10,
15,
30,
60,
120,
180,
300,
600,
900,
1800,
3600
]
}
}
}data field schema
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://fathomcharts.com/schemas/liquidity-walls/data.json",
"title": "signal",
"type": "object",
"additionalProperties": false,
"properties": {
"cells": {
"description": "Number of cells (one price level of one bar of the wall) whose volume reaches `minPerBarVolume`.",
"type": "integer"
},
"price": {
"description": "High (sell wall) or low (buy wall) of the bar that tests the wall.",
"type": "integer"
},
"side": {
"description": "`sell`: sell wall at the high; `buy`: buy wall at the low.",
"type": "string",
"enum": [
"buy",
"sell"
]
},
"sideVolume": {
"description": "Aggressive volume that stalled on the wall, in those cells: buying (ask) for a sell wall, selling (bid) for a buy wall.",
"type": "integer"
},
"volume": {
"description": "Total volume of the wall’s cells.",
"type": "integer"
}
},
"required": [
"price",
"side",
"volume",
"sideVolume",
"cells"
]
}