← tickerbot.io
View as markdown

Signal state

GEThttps://api.tickerbot.io/v2/signals/{signal}

The state of a signal is the set of tickers matching it right now, or with asof, as of any moment. One name, the whole market, one call.

stringrequired

A signal name. Booleans (e.g. golden_cross, above_sma_50) are detected automatically; every other type (numeric rsi_14, timestamp price_asof, date earnings_date, string asset_class) requires a condition.

string

Optional. Target moment as YYYY-MM-DD (that day's close) or an ISO timestamp (that intraday moment) — the same read as it stood then, unlimited depth. Full contract under As of a past date.

enumdefault auto

Grain the past state is reconstructed at: 1m, 1h, 1d, or auto (default). Only valid alongside asof — a live read with interval is a 400. Details under As of a past date.

1mOne minute. The finest stored tier; carries the intraday column subset and ~1,100 of ~13,700 tickers.
1hOne hour. Stored tier, intraday column subset, full universe.
1dOne day. The full-history, full-column tier — the only grain that carries daily-only columns (SMAs, RSI, fundamentals).
autodefaultLet the server pick the finest grain whose columns and ticker coverage both work out, resolving upward on a miss. Reported in _meta.interval.
string

Required for every non-boolean signal; the shape follows the signal's type in the catalog. Single bound, <op><value>. **numeric**: >70, <=200, !=0 (operators >, >=, =, !=, <, <=). **timestamp**: an ISO instant, <YYYY-MM-DDTHH:MM:SSZ or >=YYYY-MM-DD (a bare date is midnight UTC). **date**: >=YYYY-MM-DD or =YYYY-MM-DD. **string**: =ETF or !=ETF (= and != only; quotes optional). A relative window ("older than 15 minutes") is a /v2/scan query: price_asof < now() - interval '15 minutes'. Sending a condition with a boolean or custom signal returns 400 (it does not apply).

string

Optional. Scope to a system or caller-owned universe slug.

integerdefault 50

Page size. Max 200.

string

Opaque cursor from the previous response.

enumdefault default

Row order: default (alphabetic for booleans, highest-value-first for numerics) or market_cap (desc NULLS LAST; adds market_cap to each row). Live only — with asof it is a 400 (the snapshot's order is fixed).

defaultdefaultThe endpoint’s own ordering — alphabetical for boolean matches, signal value descending for numerics.
market_capLargest companies first.
booleandefault false

Built-in booleans only: adds active_since and days_live per row — the first day of the current true streak, from daily state (the day after the last false day; if the boolean has never been false since it first computed, the first true day). Looks back five years, so a boolean true for longer reports the window edge as a lower bound. Live only — a 400 with asof.

as_ofstring

Server time this response was assembled (ISO 8601).

signalstring

The signal you asked for.

conditionstring

The bound you passed, echoed; `null` for boolean and custom signals.

universestring

The universe you scoped to, echoed; `null` when unscoped.

_metaobject

With `asof`: how the read was resolved — interval served and requested, blending, sources, frozen fields (see the as-of read below). On any read, `deprecated_columns` when you named the signal under its pre-2026-09-07 spelling and it was served under its current name.

countnumber

Rows in this page.

next_cursorstring

Opaque token for the next page; `null` on the last page. Pass it back as `cursor`.

resultsarray

Matching tickers with the signal value.

200
Success — the response shape is documented under Returns above.
400
Non-boolean signal called without condition, a condition whose shape does not match the signal's type, invalid cursor, or interval on a live read — interval selects the grain a PAST state is reconstructed at, so it is only valid alongside asof.
404
Signal name does not exist on the schema.
  • Numeric matches come back sorted by signal value descending; boolean matches alphabetically by ticker.
  • For the match set as of a past date, add ?asof= — see Ticker matches (as-of).
  • Custom signals: {signal} may be one of your custom signals — it resolves as a boolean signal (matches where its predicate is true; condition is ignored). See Create a custom signal.
  • For booleans, the response value is true/false. For numerics it's the signal value at the time of the request.
  • Pair with asof to ask "who matched as of a past date" — see Ticker matches (as-of). For a per-ticker time series of one signal, see Series.
  • Membership: live reads return currently-active tickers only. As-of reads use point-in-time listing instead (was the ticker listed and not yet delisted at that instant), so a since-delisted name can legitimately appear in a historical match set.
Tickers at a 52-week high (boolean)
curl "https://api.tickerbot.io/v2/signals/at_52w_high?limit=3" \
  -H "Authorization: Bearer YOUR_KEY"
Response
{
  "as_of": "2026-08-11T21:35:37.719Z",
  "signal": "at_52w_high",
  "condition": null,
  "universe": null,
  "count": 3,
  "next_cursor": "eyJhZnRlcl90aWNrZXIiOiJBQk5HIn0",
  "results": [
    { "ticker": "AAAP", "name": "Pacer Barings CLO Market Flex ETF",              "value": true },
    { "ticker": "ABCS", "name": "Alpha Blue Capital US Small-Mid Cap Dynamic ETF", "value": true },
    { "ticker": "ABNG", "name": "Leverage Shares 2x Long ABNB Daily ETF",          "value": true }
  ]
}

Ticker matches (as-of)

GEThttps://api.tickerbot.io/v2/signals/{signal}?asof=

The set of tickers that matched one signal as of a past date.

stringrequired

A signal name. Booleans (e.g. golden_cross, above_sma_50) are detected automatically; every other type (numeric rsi_14, timestamp price_asof, date earnings_date, string asset_class) requires a condition.

stringrequired

Target moment as YYYY-MM-DD (the close of that day) or full ISO timestamp (that intraday moment). Unlimited depth.

enumdefault auto

Grain the past state is reconstructed at: 1m, 1h, 1d, or auto (default). Same name and values as Series and Bars. Not every signal exists at every grain (rsi_14, fundamentals and valuation ratios are 1d-only), and a cross-section must resolve to ONE grain — so without this, one 1d-only column in the projection silently re-dated every other column in the request. With it set, that case is a 400 interval_unavailable naming the signal and the grains that carry it. auto picks the finest servable grain and reports which in _meta.interval / _meta.interval_reason.

1mOne minute. The finest stored tier; carries the intraday column subset and ~1,100 of ~13,700 tickers.
1hOne hour. Stored tier, intraday column subset, full universe.
1dOne day. The full-history, full-column tier — the only grain that carries daily-only columns (SMAs, RSI, fundamentals).
autodefaultLet the server pick the finest grain whose columns and ticker coverage both work out, resolving upward on a miss. Reported in _meta.interval.
string

Required for every non-boolean signal; the shape follows the signal's type in the catalog. Single bound, <op><value>. **numeric**: >70, <=200, !=0 (operators >, >=, =, !=, <, <=). **timestamp**: an ISO instant, <YYYY-MM-DDTHH:MM:SSZ or >=YYYY-MM-DD (a bare date is midnight UTC). **date**: >=YYYY-MM-DD or =YYYY-MM-DD. **string**: =ETF or !=ETF (= and != only; quotes optional). A relative window ("older than 15 minutes") is a /v2/scan query: price_asof < now() - interval '15 minutes'. Sending a condition with a boolean or custom signal returns 400 (it does not apply).

string

Scope to a system or caller-owned universe slug.

integerdefault 50

Page size. Max 200.

string

Opaque cursor from the previous response.

as_ofstring

The moment you asked about — the date's close, or the timestamp you passed.

signalstring

The signal you asked for.

conditionstring

The bound you passed, echoed; `null` for boolean and custom signals.

universestring

The universe you scoped to, echoed; `null` when unscoped.

_metaobject

Grain served (`interval`), why (`interval_reason`), `frozen_fields`, and `coverage_gap` when one applies. `_meta.resolution` is a deprecated alias of `interval`. `deprecated_columns` lists any column you named under its pre-2026-09-07 spelling that was served under its current name (`requested`, `use`, `note`).

countnumber

Rows in this page.

next_cursorstring

Opaque token for the next page; `null` on the last page. Pass it back as `cursor`.

resultsarray

Tickers that matched at that instant.

200
Success — the response shape is documented under Returns above.
400
Missing/malformed asof, non-boolean signal called without condition (or a condition whose shape does not match the signal's type), or invalid cursor.
404
Signal name does not exist on the schema.
  • This is GET /v2/signals/{signal} with ?asof= — as-of at one-signal scope, the second tense of the same page because point-in-time is its own question. The response envelope matches the live call, plus _meta describing the grain served and why.
  • Pass asof as a YYYY-MM-DD date (that day's close) or a full ISO timestamp (that intraday moment), and pick the grain with interval. A match set is a cross-section, so it resolves to ONE grain — and 1m is only servable for a scoped universe, since the minute tier carries ~1,100 of ~13,700 tickers.
  • Custom signals: {signal} may be one of your custom signals — it resolves as a boolean signal. See Create a custom signal.
  • A match set spans every asset class the signal is defined for, so R: rates and X: FX/crypto instruments appear alongside equities — the example above is topped by Fed funds rates, not stocks. Scope with universe (or filter asset_class via /v2/scan) when you want one class.
  • Static fields aren't historized — name, sector, industry, asset_type, and exchange reflect their *current* values. _meta.frozen_fields lists exactly which ones.
  • For per-ticker time series of one signal across many bars (not a point-in-time snapshot), use Series — ?ticker={t}&columns={signal}.
  • Unlimited depth.
  • A date-only asof resolves to the close of that day. A full ISO timestamp (…T15:30:00Z) resolves intraday at the grain you name with interval (1m/1h/1d/auto). _meta.interval reports the grain served and _meta.interval_reason why; tickers with no row at that grain are disclosed in _meta.coverage_gap with a sample. Illiquid instruments (SPAC warrants, units, rights) routinely have no intraday print, so a small coverage_gap at 1m/1h is normal rather than a fault. If there is no state exactly at the requested moment (weekend, holiday, or a gap), the server carries forward the most-recent row within the lookback window (14 days at daily resolution, 5 days for intraday granularities) — a Saturday asof returns Friday's values, not an empty set. Beyond the window you get an empty results array with the echoed asof. (/v2/tickers/{ticker}?asof= applies the identical staleness rule since 2026-07-27, and 404s with last_available when nothing is fresh enough.)
  • Membership is point-in-time (survivorship-safe): the as-of set includes tickers that were listed and not yet delisted at that instant, so a since-delisted name can legitimately appear. The live read of this same endpoint returns currently-active tickers only.
Boolean: who was at a 52-week high that day
curl "https://api.tickerbot.io/v2/signals/at_52w_high?asof=2024-02-23&limit=3" \
  -H "Authorization: Bearer YOUR_KEY"
Response
{
  "as_of": "2024-02-23",
  "signal": "at_52w_high",
  "condition": null,
  "universe": null,
  "_meta": {
    "interval": "1d",
    "interval_requested": "auto",
    "interval_reason": "date-only asof resolves to the daily close",
    "resolution": "daily",
    "frozen_fields": ["name", "sector", "industry", "asset_type", "exchange", "asset_class", "ticker_category"]
  },
  "count": 3,
  "next_cursor": "eyJhZnRlcl90aWNrZXIiOiJBRkxHIn0",
  "results": [
    { "ticker": "ABEQ", "name": "Absolute Select Value ETF",              "value": true },
    { "ticker": "ACR",  "name": "ACRES Commercial Realty Corp.",          "value": true },
    { "ticker": "AFLG", "name": "First Trust Active Factor Large Cap ETF", "value": true }
  ]
}