Fathom Zones
Directional effort zones on 40-tick range bars, with the 20-period EMA of the closes.
What the indicator shows
- A buy zone marks a fast upward push backed by buying delta; a sell zone, a fast downward push backed by selling delta. On the Fathom chart, buy zones are blue and sell zones coral.
- The range bars and the 20-period EMA of their closes are published with the zones, to put them in the context of the trend.
How to use it
- When price comes back into a zone, watch how it reacts: a buy zone often acts as support, a sell zone as resistance.
- Place the zone against the EMA: a buy zone above the EMA goes with the trend, and so does a sell zone below it.
- A zone crossed by a bar body ends: the level did not hold.
How it is computed
- 40-tick range bars, with no parameter: a bar runs until the trade that would take its high-low spread beyond 40 ticks, and that trade opens the next bar. A new bar also opens at every session open (6:00 pm New York time). Bars are numbered from 0 from the start of the week.
- A finished bar is an effort bar when four conditions hold: its body goes the way of its delta (ask − bid; close ≥ open for a positive or zero delta, close < open for a negative one); the absolute delta is 10% to 40% of the bar’s volume; the delta per body tick,
delta / (|close − open| + 1)truncated, is at most 14 contracts in absolute value; the bar formed in 45 seconds at most (duration truncated to the second), from its first trade to the trade that opens the next one. - As soon as two consecutive effort bars go the same way, a push starts: its bounds start from the high and low of these two bars, then widen with each further effort bar the same way.
- The first bar that is not an effort bar that way ends the push and creates the zone, whose
startis that bar’s index. The zone covers the half of the push where it started: the lower half for a buy zone, the upper half for a sell zone, so its bounds can fall on a half tick. - The 20-period EMA of the closes starts at the bar with index 21: its first value is that bar’s close, then
EMA = previous EMA + (close − previous EMA) × 2/21. - The three object kinds have no field telling them apart in
data: read theidprefix (bar:,ema:,zone:).<weekSunday>is theYYYY-MM-DDdate of the week’s Sunday reopen; the index of a bar or an EMA value is the last segment of itsid.
When it updates
- Each range bar is sent once, final, when it closes, with its EMA value from index 21 on.
- A zone is sent in progress as soon as it is created, then final (
active: false, with itsend) on the first of these events: a bar body crosses it (below its bottom for a buy zone, above its top for a sell zone), it has covered 21 bars (starttostart+ 20), or a new session opens (6:00 pm New York time). A zone can end on the very bar that creates it. - The snapshot keeps the last 32 final objects of all kinds together: the more numerous bars and EMA values can leave no room for any final zone.
- Weekly reset: on the first trade of the Sunday reopen (6:00 pm New York time), the week’s last bar is sent, zones still in progress are sent final (
active: false, with theirend), then bars, indices and the EMA start over; nothing carries over to the new week.
- Identifier
effort-zones- 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": "effort-zones",
"instrument": "NQ.front",
"indicator": "effort-zones",
"params": {},
"mode": "live",
"from": "live"
}Parameters
This indicator has no parameters: omit params or send {}.
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 range bar. <weekSunday>: YYYY-MM-DD date of the week’s Sunday reopen; <index>: number of the bar from the start of the week (0, 1, 2…), read from the id (data has no index field).
id format: bar:<weekSunday>:<index>. Each object is sent once, final (final: true).
| Field | Type | Unit | Present | Description |
|---|---|---|---|---|
close | integer | ticks | always | Close. |
high | integer | ticks | always | High. |
low | integer | ticks | always | Low. |
open | integer | ticks | always | Open. |
start | string | timestamp (ns) | always | Timestamp of the bar’s first trade. To place a zone in time, read the start of the bar whose index equals the zone’s start (or end); the bar of the end is only published when it closes. |
ema sent final
EMA value at the close of bar <index> (the same index as in that bar’s id).
id format: ema:<weekSunday>:<index>. Each object is sent once, final (final: true).
| Field | Type | Unit | Present | Description |
|---|---|---|---|---|
value | number | ticks | always | 20-period EMA of the closes, at the close of bar <index>. It starts at the bar with index 21, on its close, then EMA = previous EMA + (close − previous EMA) × 2/21. No ema object exists for bars 0 to 20 of the week. |
zone sent in progress
Zone; in progress while it is active. <startIndex> is its start.
id format: zone:<weekSunday>:<startIndex>. The object is sent in progress (final: false), then sent again on every change; each version fully replaces the previous one. Once it can no longer change, its last version carries final: true, except for objects whose description says they are removed without a final version.
| Field | Type | Unit | Present | Description |
|---|---|---|---|---|
active | boolean | — | always | true while the zone is extended; false once it is final. |
end | integer | bars | sometimes | Index of the range bar after the end of the zone: the bar still in progress when the zone ends, only published when it closes; at the end of the week, the index that would follow the week’s last bar, which no bar carries. On expiry, end = start + 21. Absent while the zone is active. |
high | number | ticks | always | Top of the zone; can fall on a half tick. |
low | number | ticks | always | Bottom of the zone; can fall on a half tick. |
side | string · buy | sell | — | always | Direction of the push that formed the zone: buy for a positive or zero delta, sell for a negative delta. |
start | integer | bars | always | Index of the range bar that created the zone, counted from the start of the week like the index of bar ids (not a timestamp). |
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": "effort-zones",
"cursor": "20720.110.0",
"t": "upsert",
"id": "bar:2026-09-20:2939",
"final": true,
"ts": "1790208062570437091",
"data": {
"start": "1790207999116757165",
"open": 123012,
"high": 123044,
"low": 123004,
"close": 123006
}
}{
"sub": "effort-zones",
"cursor": "20720.110.1",
"t": "upsert",
"id": "ema:2026-09-20:2939",
"final": true,
"ts": "1790208062570437091",
"data": {
"value": 123066.85128768138
}
}{
"sub": "effort-zones",
"cursor": "20720.32179.2",
"t": "upsert",
"id": "zone:2026-09-20:3114",
"final": false,
"ts": "1790230140362667235",
"data": {
"side": "buy",
"high": 122357,
"low": 122258,
"active": true,
"start": 3114
}
}{
"sub": "effort-zones",
"cursor": "20720.34641.2",
"t": "upsert",
"id": "zone:2026-09-20:3114",
"final": true,
"ts": "1790231072263560767",
"data": {
"side": "buy",
"high": 122357,
"low": 122258,
"active": false,
"start": 3114,
"end": 3135
}
}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/effort-zones/params.json",
"type": "object",
"additionalProperties": false,
"properties": {}
}data field schema
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://fathomcharts.com/schemas/effort-zones/data.json",
"anyOf": [
{
"title": "bar",
"type": "object",
"additionalProperties": false,
"properties": {
"close": {
"description": "Close.",
"type": "integer"
},
"high": {
"description": "High.",
"type": "integer"
},
"low": {
"description": "Low.",
"type": "integer"
},
"open": {
"description": "Open.",
"type": "integer"
},
"start": {
"description": "Timestamp of the bar’s first trade. To place a zone in time, read the `start` of the bar whose index equals the zone’s `start` (or `end`); the bar of the `end` is only published when it closes.",
"type": "string",
"pattern": "^[0-9]+$"
}
},
"required": [
"start",
"open",
"high",
"low",
"close"
]
},
{
"title": "ema",
"type": "object",
"additionalProperties": false,
"properties": {
"value": {
"description": "20-period EMA of the closes, at the close of bar `<index>`. It starts at the bar with index 21, on its close, then `EMA = previous EMA + (close − previous EMA) × 2/21`. No `ema` object exists for bars 0 to 20 of the week.",
"type": "number"
}
},
"required": [
"value"
]
},
{
"title": "zone",
"type": "object",
"additionalProperties": false,
"properties": {
"active": {
"description": "`true` while the zone is extended; `false` once it is final.",
"type": "boolean"
},
"end": {
"description": "Index of the range bar after the end of the zone: the bar still in progress when the zone ends, only published when it closes; at the end of the week, the index that would follow the week’s last bar, which no bar carries. On expiry, `end` = `start` + 21. Absent while the zone is active.",
"type": "integer"
},
"high": {
"description": "Top of the zone; can fall on a half tick.",
"type": "number"
},
"low": {
"description": "Bottom of the zone; can fall on a half tick.",
"type": "number"
},
"side": {
"description": "Direction of the push that formed the zone: `buy` for a positive or zero delta, `sell` for a negative delta.",
"type": "string",
"enum": [
"buy",
"sell"
]
},
"start": {
"description": "Index of the range bar that created the zone, counted from the start of the week like the index of bar `id`s (not a timestamp).",
"type": "integer"
}
},
"required": [
"side",
"high",
"low",
"active",
"start"
]
}
]
}