Indicator

Fathom Zones

See where the market pushes hard. Volume and time spent in each bar bring effort zones to the surface.

Computed on 40-tick range bars: the trade that exceeds the range opens the next bar, and so does a new session. A run of at least two valid effort bars (moderate delta, bounded effort, short duration) forms a zone when it breaks. The zone extends for 20 bars, or until a bar body crosses it. Publishes closed bars, the 20-period exponential moving average and the zones. The computation restarts every week.

Identifier
effort-zones
Objects received
bar, ema, zone
Calculation
Since the start of the week
Historical cost
1 unit per trade

Subscribe

The same params work in real time, on historical data and in exports. Any you leave out take their default value.

Subscribe message
{
  "t": "subscribe",
  "sub": "effort-zones",
  "instrument": "NQ.front",
  "indicator": "effort-zones",
  "params": {},
  "mode": "live",
  "from": "live"
}

Parameters

This indicator has no parameters. Send "params": {}.

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 complete

Closed range bar (index counted from the start of the week).

Format of the id: bar:<weekStart>:<index>. Each object is sent once, already complete (final: true).

FieldTypeUnitPresentDescription
closeintegerticksalwaysClose.
highintegerticksalwaysHigh.
lowintegerticksalwaysLow.
openintegerticksalwaysOpen.
startstringtimestamp (ns)alwaysts_event of the bar’s first trade.

ema sent complete

Moving average point at the close of bar index.

Format of the id: ema:<weekStart>:<index>. Each object is sent once, already complete (final: true).

FieldTypeUnitPresentDescription
valuenumberticksalways20-period exponential moving average of the closes, taken at the close of bar index.

zone updated continuously

Zone; provisional while it is active.

Format of the id: zone:<weekStart>:<startIndex>. While it changes, the object is sent with final: false, and each new version fully replaces the previous one. Its last version carries final: true.

FieldTypeUnitPresentDescription
activeboolean—alwaysThe zone is still being extended.
endintegerbarssometimesIndex of the last bar; absent while the zone is active.
highnumberticksalwaysTop of the zone.
lownumberticksalwaysBottom of the zone.
sidestring · buy | sell—alwaysSide of the effort that formed the zone.
startintegerbarsalwaysIndex of the range bar that confirmed the zone.

Calculation warm-up

The calculation starts over at the beginning of every week (Saturday 00:00 UTC). During the weekend close it keeps the state of the past week; objects still open are finalized on the first trade of the new week. If nobody is using your parameters yet, the server first recomputes the week since its start (status warming), then goes live (status live).

Historical data follows the same rules: a query over a past period returns exactly what the real-time stream published.

Example messages

Messages received with the subscription parameters above. Over WebSocket, each message also carries sub and cursor.

Final version
{
  "t": "upsert",
  "id": "bar:2026-09-19:2173",
  "final": true,
  "ts": "1790208062570437091",
  "data": {
    "start": "1790207999116757165",
    "open": 123012,
    "high": 123044,
    "low": 123004,
    "close": 123006
  }
}
Final version
{
  "t": "upsert",
  "id": "ema:2026-09-19:2173",
  "final": true,
  "ts": "1790208062570437091",
  "data": {
    "value": 123066.85128768138
  }
}
In-progress version
{
  "t": "upsert",
  "id": "zone:2026-09-19:2348",
  "final": false,
  "ts": "1790230140362667235",
  "data": {
    "side": "buy",
    "high": 122357,
    "low": 122258,
    "active": true,
    "start": 2348
  }
}
Final version
{
  "t": "upsert",
  "id": "zone:2026-09-19:2348",
  "final": true,
  "ts": "1790231072263560767",
  "data": {
    "side": "buy",
    "high": 122357,
    "low": 122258,
    "active": false,
    "start": 2348,
    "end": 2369
  }
}

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
JSON
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://fathomcharts.com/schemas/effort-zones/params.json",
  "type": "object",
  "additionalProperties": false,
  "properties": {}
}
Schema of the data field
JSON
{
  "$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,
      "required": [
        "start",
        "open",
        "high",
        "low",
        "close"
      ],
      "properties": {
        "close": {
          "type": "integer",
          "description": "Close."
        },
        "high": {
          "type": "integer",
          "description": "High."
        },
        "low": {
          "type": "integer",
          "description": "Low."
        },
        "open": {
          "type": "integer",
          "description": "Open."
        },
        "start": {
          "type": "string",
          "pattern": "^[0-9]+$",
          "description": "`ts_event` of the bar’s first trade."
        }
      }
    },
    {
      "title": "ema",
      "type": "object",
      "additionalProperties": false,
      "required": [
        "value"
      ],
      "properties": {
        "value": {
          "type": "number",
          "description": "20-period exponential moving average of the closes, taken at the close of bar `index`."
        }
      }
    },
    {
      "title": "zone",
      "type": "object",
      "additionalProperties": false,
      "required": [
        "side",
        "high",
        "low",
        "active",
        "start"
      ],
      "properties": {
        "active": {
          "type": "boolean",
          "description": "The zone is still being extended."
        },
        "end": {
          "type": "integer",
          "description": "Index of the last bar; absent while the zone is active."
        },
        "high": {
          "type": "number",
          "description": "Top of the zone."
        },
        "low": {
          "type": "number",
          "description": "Bottom of the zone."
        },
        "side": {
          "type": "string",
          "enum": [
            "buy",
            "sell"
          ],
          "description": "Side of the effort that formed the zone."
        },
        "start": {
          "type": "integer",
          "description": "Index of the range bar that confirmed the zone."
        }
      }
    }
  ]
}