Spread API · Current value plus its own window

The spread, and what is normal for it.

GET /v1/spread returns the live spread in pips and points, its mean, minimum, maximum and standard deviation over your chosen window, and three session averages. /v1/spread/compare does the same across up to 20 symbols, pre-sorted.

4 windows: 1h, 24h, 7d, 30d 3 session buckets 1× request weight
tickatlas.com / v1 / spread 200 OK
GET /v1/spread?symbol=EURUSD&period=24h
EUR/USD · current.spread_pips
1.3
13 points
avg_spread · 24h1.62
min / max0.8 / 6.4
std_deviation0.71
period24h
by_session.asian2.14
by_session.london1.28
by_session.new_york1.47
buckets3, any may be null
{
  "success": true,
  "data": {
    "symbol": "EURUSD",
    "current": { "spread_pips": 1.3, "spread_points": 13 },
    "statistics": {
      "period": "24h",
      "avg_spread": 1.62,
      "min_spread": 0.8,
      "max_spread": 6.4,
      "std_deviation": 0.71
    },
    "by_session": {
      "asian": 2.14, "london": 1.28, "new_york": 1.47
    }
  }
}
4Analysis windows
3Session buckets
20Symbols per compare
1×Request weight
Two endpoints

Depth on one symbol, or breadth across many.

They take the same period and cost the same single request of quota. The difference is shape: one returns statistics and session buckets for a single instrument, the other returns a comparable row per instrument and leaves the sessions out.

GET /v1/spread

One symbol, in depth

Live spread in both units, five statistics over the window and three session averages. A missing cached price is a 404 SYMBOL_NOT_FOUND; an empty history window is not an error — the statistics fall back to the current spread.

  • symbol required, period optional
  • Canonical symbol names
  • Returns current, statistics, by_session
GET /v1/spread/compare

Up to 20 symbols, side by side

A comma-separated list, one row each with current, average, minimum and maximum, plus a has_live_data flag. Rows arrive sorted by average spread ascending, and rows with no average sort to the end rather than to the front.

  • symbols required, period optional
  • Over 20 → 400 TOO_MANY_SYMBOLS
  • Returns period, symbols, count

Where the numbers come from is not uniform, on purpose. The current spread is the cached quote. The statistics and the session buckets are computed from our data over the window. So current is this instant and the window is its history — which is exactly why comparing the two is informative.

Windows

4 lookbacks, one parameter.

period selects how far back the statistics and the session buckets reach. It never affects current, which is always the latest cached quote.

An unrecognised period is a 400 with INVALID_PERIOD and the valid keys listed, not a silent fallback to 24h.
period Lookback Covers Default
1h 1 h the last hour —
24h 24 h the last day yes
7d 168 h the last week —
30d 720 h the last month —
  • 1h — the last hour
  • 24h — the last day (default)
  • 7d — the last week
  • 30d — the last month

Four statistics, and the fifth is the interesting one. A mean on its own does not say whether the current reading is ordinary. std_deviation together with min_spread and max_spread is what lets you express "unusual for this symbol, in this window" as a number rather than a feeling — and the endpoint returns all of them in the same call, so no second request is needed to normalise.

Session buckets

3 windows, anchored on real opens.

Each bucket is an eight-hour UTC window starting at the centre's own local open hour and resolved through the tz database — so the UTC boundaries move with BST and EDT instead of being hard-coded and wrong for seven months a year.

Sydney is not bucketed, and there is no overlap bucket. The London and New York windows already share three hours; a value is null when that window holds no rows for the symbol.
by_session key Centre Local open Standard time (UTC) Summer time (UTC)
asian Tokyo 09:00 Asia/Tokyo 00:00–07:00 UTC 00:00–07:00 UTC
london London 08:00 Europe/London 08:00–15:00 UTC 07:00–14:00 UTC
new_york New York 08:00 America/New_York 13:00–20:00 UTC 12:00–19:00 UTC
Request pattern

One required parameter, either way.

symbol on the single endpoint, symbols on the comparison, and everything else is the optional window. No special key scope is required — a valid key is enough, which is unusual on this API and makes these two the cheapest pair of calls to add to an existing integration.

  • Required: symbol, or symbols as a comma list.
  • Optional period, defaulting to 24h.
  • Authenticate with the X-API-Key header.
  • No permission scope needed beyond a valid key.
# one symbol, one period
curl -H "X-API-Key: YOUR_API_KEY" \
  "https://tickatlas.com/v1/spread?symbol=EURUSD&period=24h"

# up to 20 symbols in one call, tightest average first
curl -H "X-API-Key: YOUR_API_KEY" \
  "https://tickatlas.com/v1/spread/compare?symbols=EURUSD,GBPUSD,USDJPY&period=7d"
# how does the current spread sit against its own window?
d = requests.get(
    "https://tickatlas.com/v1/spread",
    headers={ "X-API-Key": KEY },
    params={ "symbol": "EURUSD", "period": "24h" },
).json()["data"]

now = d["current"]["spread_pips"]
st  = d["statistics"]

# describe the reading; the endpoint publishes no verdict of its own
z = (now - st["avg_spread"]) / st["std_deviation"] if st["std_deviation"] else 0
print(now, "pips |", st["period"], "avg", st["avg_spread"],
      "range", st["min_spread"], "to", st["max_spread"],
      "| z =", round(z, 2))

# session averages: three buckets, any of them may be null
for name, avg in d["by_session"].items():
    print(name, "-", "no data" if avg is None else f"{avg} pips")
current.spread_pips
1.3 EUR/USD · 13 points · 24h avg 1.62
1× weight
Two unitsspread_pips · spread_points
Five statisticsperiod · avg · min · max · std_deviation
Three bucketsasian · london · new_york
No verdict fieldno "optimal", no recommendation
Descriptive by construction

Numbers and their context. Nothing more.

The response has no field that judges a spread. That is a design choice, not an omission: what counts as acceptable execution cost depends on a strategy TickAtlas cannot see, so the endpoint returns the current reading, the distribution behind it and the session means, and leaves the threshold to you.

Field reference

Both responses, field by field.

Each envelope is { "success": true, "data": { … } }. All spread values are in pips unless the field name says points.

GET /v1/spread
Field Type What it carries
symbol string The CANONICAL symbol, e.g. EURUSD.
current.spread_pips number Live spread in pips, two decimals, from the quote cache. 0 when the cached spread is missing or null rather than an invented value.
current.spread_points number The same spread in raw points, as an integer. Points are what our data carries; pips are derived.
statistics.period string Echo of the requested period: 1h, 24h, 7d, 30d.
statistics.avg_spread number Mean spread over the period, in pips, two decimals. Falls back to the current spread when the window holds no rows — so it is never null, and never zero by accident.
statistics.min_spread number Tightest spread recorded in the window, same units and same fallback.
statistics.max_spread number Widest spread recorded in the window. The gap between this and avg_spread is the part of execution cost that is not typical.
statistics.std_deviation number Standard deviation of the spread over the window, in pips. 0 when the window has too few rows to compute one.
by_session.asian number Mean spread over the 8-hour window anchored on the Tokyo open. null when the window holds no rows for this symbol.
by_session.london number Mean spread over the 8-hour window anchored on the London open.
by_session.new_york number Mean spread over the 8-hour window anchored on the New York open. The London and New York windows overlap by three hours; the endpoint does not publish a separate overlap bucket.
GET /v1/spread/compare
Field Type What it carries
period string Echo of the requested period, applied identically to every symbol.
count number How many symbols were resolved and returned — compare with what you asked for to spot a name that did not resolve.
symbols[].symbol string Canonical symbol.
symbols[].current_pips number Live spread in pips, or null when nothing is cached for that symbol right now.
symbols[].avg_pips number Mean over the period, or null when the window is empty. This is the sort key — ascending, so the tightest average is the first row.
symbols[].min_pips number Tightest recorded spread in the window, or null.
symbols[].max_pips number Widest recorded spread in the window, or null.
symbols[].has_live_data boolean Whether a live quote existed for the symbol at read time. This is the field to branch on before trusting current_pips.
GET /v1/spread/compare200 OK
# GET /v1/spread/compare?symbols=EURUSD,GBPUSD,USDJPY,AUDUSD&period=24h
{
  "success": true,
  "data": {
    "period": "24h",
    "count": 4,
    "symbols": [                        # pre-sorted by avg_pips ascending
      { "symbol": "EURUSD", "current_pips": 1.3,  "avg_pips": 1.62,
        "min_pips": 0.8, "max_pips": 6.4,  "has_live_data": true },
      { "symbol": "USDJPY", "current_pips": 1.4,  "avg_pips": 1.85,
        "min_pips": 0.9, "max_pips": 7.1,  "has_live_data": true },
      { "symbol": "GBPUSD", "current_pips": 1.6,  "avg_pips": 2.04,
        "min_pips": 1.1, "max_pips": 9.3,  "has_live_data": true },
      { "symbol": "AUDUSD", "current_pips": null, "avg_pips": 2.41,
        "min_pips": 1.3, "max_pips": 11.2, "has_live_data": false }
    ]
  }
}
Units

Points are our data. Pips are derived.

Our data carries an integer spread in points; the conversion to pips depends on the symbol's digit count, looked up from the symbols table. Getting this wrong by a factor of ten is the most common mistake in spread arithmetic, so the endpoint returns both.

÷ 10

Fractional quotes: 1 pip = 10 points

5-digit FX (EURUSD at 1.23456) and 3-digit JPY quotes (USDJPY at 123.456) carry a fractional pip, so a 13-point spread is 1.3 pips.

  • 5-digit FX · 3-digit JPY
  • The default when a symbol's digits are unknown
× 1

Everything else: 1 pip = 1 point

Legacy 4- and 2-digit FX, metals, indices and crypto report whole pips, so points and pips are the same number. Pip size for non-FX classes is not standardised, so treat the value as our data's own unit rather than a universal one.

  • 4-/2-digit FX · metals · indices · crypto
  • spread_points is always the unconverted integer
Developer-first behavior

Missing data is a value, not an exception.

Spread history is thin for a newly covered symbol and on a quiet weekend. Both endpoints are explicit about that rather than failing, which is what makes them safe to poll on a schedule.

FALLBACKS

An empty window degrades

With no rows in the period, avg, min and max fall back to the current spread and std_deviation is 0 — a usable response rather than nulls you have to special-case.

  • a null spread is coerced to 0, never crashed on
FLAGS

has_live_data per row

On the comparison endpoint each row says whether a live quote existed, so a null current_pips is distinguishable from a zero spread.

  • rows with no average sort last
ERRORS

Named codes, valid sets included

INVALID_PERIOD, SYMBOL_NOT_FOUND, NO_SYMBOLS and TOO_MANY_SYMBOLS — each with the constraint that was violated.

  • 400 and 404, machine-readable
QUOTA

1× weight, no extra scope

Standard tier, multiplier 1.0, on both paths. The key needs no named permission beyond being valid — the cheapest pair of calls on the API.

  • X-API-Key: tk_…
Developer API pricing

The cheapest tier on the API.

Both spread endpoints are standard tier at 1×, so they cost one request each and need no named key scope. Pay-as-you-go counts as paid for endpoint access, so a new account can call them immediately.

There is no free tier and no self-serve trial. Every account starts on pay-as-you-go with $2.50 of prepaid credit, no card and no overage — monthly plans lift the starting quota.
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
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

One call, and the reading has context.

A spread on its own is a number. With the mean, the range and the deviation from the same call, it becomes something an application can reason about.

Cost panels

Current, average, min, max and standard deviation in one call is everything a cost widget needs: a live number and the window it should be read against.

dashboardswidgets

Instrument comparison

One compare call ranks up to 20 symbols by average spread, already sorted, with a has_live_data flag per row so gaps are visible rather than silent.

tablesvenue reviews

Deviation monitoring

Standard deviation plus min and max turn "the spread is 4 pips" into "the spread is four standard deviations from its own 24-hour mean", which is a condition you can watch for.

alertsschedulerstime series

Show execution cost on your own page. Embed live spread widgets that render the current spread against its 24-hour normal from a single script tag.

Frequently asked questions

Spreads, clarified.

Units and conversions, which windows and sessions exist, where each number comes from, and what the endpoint deliberately does not tell you.

What exactly is returned, and in what units?

Two views of the same thing. current carries spread_pips (two decimals) and spread_points (the raw integer in our data). statistics carries the period, the mean, the minimum, the maximum and the standard deviation over that window, all in pips. by_session carries three session means, also in pips. A pip is ten points for 5-digit FX and 3-digit JPY quotes, and one point for everything else — legacy 4- and 2-digit FX, metals, indices and crypto.

Which periods are available?

Four: 1h (1 hour), 24h (24 hours), 7d (168 hours), 30d (720 hours). The default is 24h, and the same set applies to both endpoints. Anything else is a 400 with INVALID_PERIOD and the valid list in the detail.

Which sessions does by_session break down?

Three, keyed asian, london and new_york. Each is an 8-hour UTC window anchored on that centre’s local open hour and derived through zoneinfo, so the windows shift with BST and EDT rather than being hard-coded. Sydney is deliberately not bucketed, and there is no separate overlap bucket — the London and New York windows already overlap by three hours, and a value can be null when the window holds no rows for that symbol.

How many symbols can I compare at once?

Up to 20 comma-separated symbols per call. More than that is a 400 with TOO_MANY_SYMBOLS; an empty list is a 400 with NO_SYMBOLS. The response is already sorted by average spread ascending, so the tightest average is simply the first row — there is no rank field and no tightest/widest summary to read.

Where does the data come from?

Two different places, which is worth knowing. The current spread is the cached live quote. The statistics and the session buckets are computed from our data over the requested window. So current is right now, and the window is its history.

What happens when a symbol has no data?

On /v1/spread, no cached price at all is a 404 with SYMBOL_NOT_FOUND. An empty history window is not an error: avg, min and max fall back to the current spread and std_deviation is 0, so you get a usable response rather than nulls. On /v1/spread/compare, a symbol with no live quote comes back with current_pips null and has_live_data false, and rows with no average sort to the end.

Does the endpoint say when to trade?

No, and it deliberately carries no field that would. There is no "optimal window" flag and no recommendation string — the response is the current spread, its statistics and three session means, and what counts as acceptable for a given strategy is not something TickAtlas asserts. TickAtlas provides market data and computed analytics for software use; it does not provide personalised investment advice or execute trades.

What does a call cost, and which plans include it?

One request of quota, for both endpoints: /v1/spread is standard tier at multiplier 1.0, and /v1/spread/compare is not in the tier map so it takes the standard-tier fallback. Neither needs a special key permission scope — a valid key is enough. Every plan includes them — neither endpoint carries a plan gate — so a new account can call them on its $2.50 of starting credit. There is no free tier and no self-serve trial.

Current, average, range, deviation and three sessions — one request

Measure the cost. Set your own threshold.

One GET returns the live spread and the distribution it sits in, so your application can decide what "unusual" means. Start on your $2.50 of credit; both endpoints are 1×.