Market insights API · Pre-computed every six hours

The whole market, already analysed.

A background job scores every cached symbol on 4 timeframes four times a day and stores the result. Read the market-wide aggregate and the per-symbol teaser cards at no quota cost; unlock the full twenty-five-field analysis for a symbol when you want the signal lists and the raw readings behind it.

00:05 · 06:05 · 12:05 · 18:05 UTC 4 timeframes Teasers cost no quota
tickatlas.com / api / market-insights 200 OK
GET /api/market-insights/cards/H4
cards[0] · sorted by |daily_change_pct|
GBPUSD
BEARISH
confidence0.55
rsi / adx38.1 / 32.7
spread_pips1.3
daily_change_pct-0.6412
bullish_count2
bearish_count6
trend_score-2.5
momentum_score-0.5
{
  "success": true,
  "timeframe": "H4",
  "cards": [
    {
      "symbol": "GBPUSD",
      "display_name": "GBPUSD",
      "timeframe": "H4",
      "bias": "BEARISH",
      "confidence": 0.55,
      "trend_score": -2.5,
      "momentum_score": -0.5,
      "rsi": 38.1,
      "adx": 32.7,
      "bid": 1.2641,
      "ask": 1.26423,
      "spread_pips": 1.3,
      "daily_change_pct": -0.6412,
      "bullish_count": 2,
      "bearish_count": 6,
      "snapshot_time": "2026-09-18T12:00:00+00:00"
    },
    … one entry per symbol in this timeframe
  ]
}
6hCycle interval
4Timeframes per cycle
16Teaser fields
$0.01Per full analysis
How you read it

Aggregate, then scan, then expand one symbol.

The two read endpoints cost nothing against your quota, so the pattern is to narrow for free and pay only for the symbols you actually intend to use. Note the prefix on all of them — /api/market-insights, not /v1.

GET no quota cost

Market-wide aggregate

One object built from the latest H4 snapshots: sentiment counts and percentages, the five largest gainers and losers, the five strongest trends by ADX and the five most volatile symbols by ATR relative to price.

/api/market-insights/overview
  • { success, overview }
  • overview is null with a message when no cycle has run yet, rather than a 404.
GET no quota cost

Teaser card per symbol

Sixteen fields for every symbol in the requested timeframe, already sorted by absolute daily change so the movers come first. The timeframe is a PATH segment, not a query parameter.

/api/market-insights/cards/{timeframe}
  • { success, cards, timeframe }
  • Anything outside M30, H1, H4, D1 is a 400 with the valid set in the detail.
POST $0.01 + 1 request

Full analysis for one symbol

Twenty-five fields: every teaser field plus ATR, MACD histogram, the three signal arrays, the volatility notes, the generated paragraph and all thirteen raw readings. Body is { symbol, timeframe }.

/api/market-insights/unlock
  • { success, analysis, charged, cost, new_balance }
  • Insufficient credit returns 200 with success:false and error:"insufficient_credits", not a 402.

Authentication accepts either credential. All three routes resolve the caller through a dual-auth dependency, so an X-API-Key header and a logged-in session cookie both work. That is why they sit under /api rather than /v1 — and why they are outside the /v1 rate-limit headers and the /v1 usage middleware.

The cycle

Four runs a day, on the hour, on a lock.

The job wakes at 00:05, 06:05, 12:05, 18:05 UTC, takes a distributed Redis lock so only one process in the cluster does the work, walks every cached symbol that has a live price, and upserts one row per timeframe. Rows are stamped on the hour, so the 12:05 run carries 12:00:00+00:00.

  • Symbol set is the live indicator cache, not a fixed list.
  • Upsert on (symbol, timeframe, snapshot_time) — a re-run inside a window overwrites, it never duplicates.
  • Results cached in Redis for 7 hours — one cycle plus a buffer.
  • The start-up run is skipped over a forex weekend; scheduled runs are not.
Pythonfree scan, then one paid unlock
# 1. market-wide aggregate — no quota cost
BASE = "https://tickatlas.com"
H = {"X-API-Key": KEY}

ov = requests.get(f"{BASE}/api/market-insights/overview", headers=H).json()
if ov["overview"] is None:
    # no cycle has landed yet; ov["message"] says so
    sys.exit()
print(ov["overview"]["total_symbols"], ov["overview"]["sentiment"])

# 2. every card for one timeframe — also no quota cost
#    timeframe is a PATH segment, not ?timeframe=
cards = requests.get(f"{BASE}/api/market-insights/cards/H4", headers=H).json()["cards"]

# already sorted by |daily_change_pct| — take the top mover
top = cards[0]

# 3. expand exactly one symbol. body is {symbol, timeframe}
r = requests.post(
    f"{BASE}/api/market-insights/unlock",
    headers=H,
    json={"symbol": top["symbol"], "timeframe": "H4"},
).json()

if not r["success"]:          # 200 + insufficient_credits
    print(r["error"], r.get("balance"))
else:
    a = r["analysis"]
    print(a["bias"], a["confidence"], len(a["bearish_signals"]))
    print(r["charged"], r["cost"], r["new_balance"])
Teaser card reference

All 16 fields, at no quota cost.

One of these objects per symbol, for the timeframe in the path. The envelope is { "success": true, "cards": [ … ], "timeframe": "H4" } — and when no cycle has landed, cards is an empty array with a message rather than an error.

Field Type What it carries
symbol string Canonical symbol, e.g. EURUSD: one card per instrument.
display_name string Human-facing name of the instrument.
timeframe string Echo of the path segment: M30, H1, H4 or D1.
bias string UPPERCASE, five values: STRONGLY BULLISH, BULLISH, NEUTRAL, BEARISH, STRONGLY BEARISH.
confidence number Three decimals. Bounded 0.3–0.9 by the same ladder /v1/summary uses.
trend_score number Signed trend total, two decimals.
momentum_score number Signed momentum total, two decimals. Added to trend_score, this selects the bias.
rsi number RSI_14 for the timeframe. Named rsi here, rsi_14 inside key_values.
adx number ADX for the timeframe.
bid number Bid at the moment the snapshot was taken.
ask number Ask at the same moment.
spread_pips number Derived from ask − bid, one decimal. Scaled ×100 when bid > 10 (JPY-quoted and similar) and ×10000 otherwise.
daily_change_pct number Bid against the D1 open, four decimals. null when no D1 candle is available.
bullish_count number Number of bullish conditions that fired across all four analysers.
bearish_count number The same for bearish conditions.
snapshot_time string ISO 8601, stamped on the hour — 12:00:00+00:00 for the cycle that ran at 12:05.

Field names differ from the live endpoints on purpose. This surface is generated from stored snapshot columns, so it is rsi, spread_pips and daily_change_pct — not rsi_14, spread or change_24h. There is no locked flag and no cycle field anywhere in the API.

Overview object

One request for the shape of the whole market.

Built from the cycle's H4 snapshots only. Each of the four leaderboards is five entries long, and every entry carries its own bias so you can read direction without a second call.

A bias string containing "BULLISH" counts as bullish in the sentiment tally, so STRONGLY BULLISH is folded into the same bucket. Percentages are one decimal.
Field Type What it carries
snapshot_time string ISO 8601 timestamp of the cycle this aggregate was built from.
total_symbols number How many H4 snapshots the cycle produced — the real breadth of the cycle, not a marketing figure.
sentiment object bullish, bearish, neutral counts plus bullish_pct and bearish_pct to one decimal. A bias containing "BULLISH" counts as bullish, so the STRONGLY variants are folded in.
top_gainers object[] Five entries, each symbol, display_name, change, bias — sorted by daily change descending.
top_losers object[] Five entries, same shape, from the other end of the same sort.
strongest_trends object[] Five entries by highest ADX: symbol, display_name, adx, bias.
most_volatile object[] Five entries by ATR relative to bid: symbol, display_name, atr, atr_pct, bias.
analysis.bias
BULLISH confidence 0.55 · EURUSD · H4
charged: true
Envelope siblingscharged · cost 0.01 · new_balance
Signal arraysbullish · bearish · neutral · volatility_info
Raw readingskey_values — 13 fields
Re-read window7 hours, charged: false
What the unlock adds

Twenty-five fields, and one debit you can predict.

The analysis object is the teaser plus ATR, the MACD histogram, four arrays of readable conditions, the generated paragraph and all thirteen raw readings. The charge is $0.01, posted through the credit ledger with the usage-log row as its idempotency key — a retried request cannot double-post.

Unlock field reference

The 9 fields the teaser does not carry.

Everything in the 16-field teaser table above is present too, so the analysis object is 25 fields in total.

Field Type What it carries
atr number ATR_14 for the timeframe.
macd_hist number MACD histogram for the timeframe.
summary_text string One generated paragraph: bias with confidence, up to three bullish and three bearish factors, the leading volatility note, then the leading entry of recommendations. Abridged wherever this page shows it.
bullish_signals string[] Every bullish condition, as a readable sentence with its triggering number inlined.
bearish_signals string[] The same for bearish conditions.
neutral_signals string[] Conditions that fired without scoring, such as an ADX below 25.
volatility_info string[] Volatility and volume observations, concatenated. Informational — they never move the bias.
recommendations string[] Generated strings. Documented by name and type; TickAtlas does not reprint their wording — see the note under the table.
key_values object Thirteen raw readings: bid, ask, rsi_14, macd_hist, adx, atr_14, sma_20, sma_50, sma_200, bb_upper, bb_lower, stochastic_k, mfi_14. Any of them can be null.
POST /api/market-insights/unlock200 OK
// request body — two keys, no cycle
{ "symbol": "EURUSD", "timeframe": "H4" }

// response
{
  "success": true,
  "charged": true,
  "cost": 0.01,
  "new_balance": 2.4808,
  "analysis": {
    "symbol": "EURUSD", "display_name": "EURUSD", "timeframe": "H4",
    "snapshot_time": "2026-09-18T12:00:00+00:00",
    "bias": "BULLISH", "confidence": 0.55,
    "trend_score": 2.5, "momentum_score": 0.5,
    "rsi": 61.2, "adx": 21.4, "atr": 0.00052, "macd_hist": 0.00021,
    "bid": 1.08432, "ask": 1.08445, "spread_pips": 1.3,
    "daily_change_pct": 0.3184,
    "bullish_count": 7, "bearish_count": 0,
    "bullish_signals": ["Price above 200 SMA (long-term uptrend)", …],
    "bearish_signals": [],
    "neutral_signals": ["ADX 21.4 (weak/ranging market)", …],
    "volatility_info": […],
    "summary_text": "EURUSD on H4: Overall bias is BULLISH
                      (confidence: 55%). Bullish factors: …",
    "recommendations": […],
    "key_values": { "bid": 1.08432, "rsi_14": 61.2, … }
  }
}

Two fields are elided above, deliberately. summary_text ends by appending the first entry of recommendations, and both are advice-shaped in the live API. TickAtlas provides market data and computed analytics for software use, not personalised investment advice, so this page documents the two fields by name, type and origin and does not reprint their wording. Every other sample value here is a reading or a classification.

Timeframes

4 snapshot intervals, one per call.

The snapshot job covers M30, H1, H4, D1 — a narrower set than the seven the live indicator endpoints accept, because these are aligned to the cycle rather than to your request. The timeframe is uppercased for you; anything outside the set is a 400 that names the valid values.

  • M30
  • H1
  • H4 — the timeframe the overview aggregate is built from
  • D1

H4 is load-bearing. The overview aggregate — sentiment, gainers, losers, strongest trends, most volatile — is computed from the H4 snapshots alone. The other three timeframes are available through the cards and unlock endpoints, not through the overview.

Developer-first behavior

Cheap to poll, safe to retry.

A cached product has different failure modes from a live one, and this one is explicit about all of them rather than returning an error and letting you guess.

EMPTY STATE

Never a 404 for "not yet"

Before the first cycle lands, overview returns null and cards returns [], each with a message — so a client can render "generating" instead of an error page.

  • 200 with a message
IDEMPOTENCY

An unlock cannot double-charge

The debit is posted with the usage-log row id as its ledger key, and the result is cached per user, symbol and timeframe for 7 hours with charged:false on re-read.

  • checked twice, once under a row lock
AUTH

API key or session

Dual authentication on all three routes: the same call works from a server with a key and from a logged-in browser with a cookie.

  • X-API-Key: tk_…
QUOTA

Reads are outside the meter

Usage tracking measures /v1/ paths. Overview and cards are neither tracked nor rate-limited by it; unlock does its own accounting, one request at a time.

  • unlock: +1 request, +1 premium
Insights or summary

Same scoring code. Different contract.

The snapshot job calls the very same analyser functions /v1/summary uses, so the verdicts agree. What differs is freshness, breadth, cost and — the detail that bites — the spelling of bias.

If your code consumes both surfaces, normalise bias before comparing: one is lowercase with a separate strength field, the other is uppercase with the strength folded in.
Field /v1/summary /api/market-insights
Path GET /v1/summary GET /api/market-insights/…
Freshness Computed on the request, from the per-timeframe indicator cache Last 6-hourly cycle; Redis copy has a 7-hour TTL
Cost 1 call of quota, 5 weighted units Teasers free; unlock $0.01 + 1 request
bias spelling lowercase, plus a separate bias_strength UPPERCASE, five values, strength folded in
Timeframes M1, M5, M15, M30, H1, H4, D1 M30, H1, H4, D1
Breadth per call One symbol Every symbol in one timeframe
Timestamp field updated_at (epoch) snapshot_time (ISO 8601)
Auth X-API-Key X-API-Key or a session cookie
What it costs

Free to read. $0.01 to expand.

The two read endpoints cost no quota at all, so the only spend on this product is unlocks. The arithmetic is exactly N × $0.01, where N is the number of symbol-and-timeframe pairs you expand in a seven-hour window — re-reads inside that window are free.

Unlocks are settled in real time against prepaid credit, never billed at month end. A new account starts with $2.50 and allow_overage off, so the balance is a hard stop rather than a bill.
overview · cards
No quota cost Readable on any plan, with a key or a session
  • Market-wide sentiment, gainers, losers, ADX and volatility leaderboards
  • All 16 teaser fields for every symbol in a timeframe
  • Pre-sorted by absolute daily change
  • Not measured by the /v1/ usage middleware
Get a key
Pay as you go
$0 to start 200 requests/day · 30/min until you top up
  • $2.50 of credit included
  • Every REST endpoint except raw ticks
  • No card required, no overage
  • 10 API keys
Start free
Starter
$29/mo 10,000 requests · 120/min
  • Every REST endpoint except raw ticks
  • WebSocket streaming, 5 symbols
  • Released calendar actuals
  • Email support
  • 3 API keys
View plan
Pro
$79/mo 100,000 requests · 600/min
  • Everything in Starter
  • Raw tick data (/v1/ticks)
  • Priority support
  • 10 API keys
  • WebSocket streaming, 20 symbols
View plan
Enterprise
$349/mo 1,000,000 requests · 6000/min
  • Everything in Pro
  • Dedicated support
  • 100 API keys
  • Custom indicators
  • SLA guarantee
  • On-premise option
Contact sales
Common software patterns

Built for breadth, not for latency.

A six-hourly snapshot is the wrong tool for a decision that has to be current and the right one for anything that has to cover everything. These three shapes lean on that.

Market dashboards

The cards endpoint is a whole-market payload with no quota cost, already sorted with the movers first. One poll per cycle fills every tile on the page.

tablessparklinessentiment gauges

Scheduled briefings

Read the overview for the aggregate picture, pick the symbols worth expanding from the cards, and unlock only those. The paragraph is already written.

newslettersdigestsreports

Agent context

A cached snapshot is the cheap way to give an agent market-wide state before it decides which single symbol deserves a live 5× summary call.

agentsRAG contextpre-filters
Frequently asked questions

Insights, clarified.

The real paths, the real cycle times, how billing and idempotency work, and where this surface's field names differ from the live endpoints.

What are the real endpoint paths?

Three public routes under one prefix: GET /api/market-insights/overview, GET /api/market-insights/cards/{timeframe} and POST /api/market-insights/unlock, plus GET and PUT /api/market-insights/digest-settings. Note the prefix: these are not /v1 routes, so they are not covered by the /v1 usage middleware and they do not appear in the /v1 rate-limit headers.

When exactly does a cycle run?

The background job wakes at 00:05, 06:05, 12:05, 18:05 UTC and stamps the rows it writes on the hour, so the cycle that runs at 12:05 carries snapshot_time 12:00:00+00:00. The interval is configurable per deployment, and the run that fires at process start is skipped over a forex weekend.

How many snapshots does one cycle produce?

Every symbol that has both a live price and cached indicators, times up to four timeframes. The symbol set comes from the live indicator cache rather than a fixed list, so it moves with the coverage of our data — which is why this page reports the mechanism instead of quoting a number that would go stale. total_symbols on the overview object is the honest count for the cycle you are looking at.

Are the teaser endpoints really free?

Yes, and for a specific reason: the usage-tracking middleware only measures paths beginning /v1/, and neither overview nor cards performs any accounting of its own. Unlock does — it writes a usage-log row, adds one request and one premium request to your daily and monthly totals, and posts the credit debit.

How is an unlock billed, and can I be charged twice?

Each unlock debits $0.01 from your prepaid credit through the ledger, keyed on the usage-log row so a retry cannot double-post. The result is then cached under your user id plus symbol plus timeframe for seven hours: asking again inside that window returns the same analysis with charged:false and no second debit. The cache key has no cycle component, so in practice that is once per cycle per symbol and timeframe.

What happens when my balance is too low?

The response is HTTP 200 with success:false, error:"insufficient_credits", and the cost and your rounded balance included so a client can show the shortfall. It is checked twice — once before the work, and again under a row lock before the debit. Accounts with overage enabled are not blocked.

Which timeframes are available?

M30, H1, H4, D1 — four, not the seven the live indicator endpoints accept. The cards endpoint returns one timeframe per call, so covering all four is four calls, none of which costs quota.

Why is bias spelled differently here than on /v1/summary?

They are two code paths over the same scoring functions. The snapshot job writes one of five uppercase strings with the strength folded in — STRONGLY BULLISH through STRONGLY BEARISH — while /v1/summary returns a lowercase bias and a separate bias_strength field. If your code consumes both, normalise before comparing.

What is in recommendations?

A list of generated strings, derived from the trend and momentum scores, the volatility notes and the bias — and the first of them is appended to summary_text. TickAtlas publishes market data and computed analytics for software use and does not provide personalised investment advice, so this page documents the field by name, type and origin without reprinting its wording.

Scan the whole market for nothing. Expand what matters.

Read four cycles a day. Pay only for depth.

Create a key, call /api/market-insights/cards/H4, and you have every symbol's bias, confidence and readings without touching your quota. Unlocks come out of the $2.50 of credit you start with.