Contents Lesson 13 of 16

5 min read · practitioner

Why does an index have a price but no trades?

Indices get their own virtual exchange, INDX. The S&P 500 is GSPC.INDX, the Dow is DJI.INDX, the Nasdaq Composite is IXIC.INDX, and the volatility index is VIX.INDX.

Note the codes are bare — no caret, no prefix. Not one of the 1,668 codes on this exchange contains a ^, which is the symbol most other systems use. Another convention, another 404 waiting for anyone who guesses.

The list, counted

On 2026-07-28, /exchange-symbol-list/INDX returned 1,668 rows, and /exchange-details/INDX agreed exactly that day (they were one apart when re-checked). Every row carries Type: "INDEX" — uppercase, unlike the Common Stock and Currency casing used elsewhere, which is the sort of detail that breaks a case-sensitive comparison.

Unlike FOREX and CC, some of this metadata does real work. Currency is filled on every row and Country on most: 904 rows for the USA, 92 for India, 43 for France. But roughly one row in five still reads Country of "Unknown", STOXX and STOXX50E among them, so it is a column you check rather than trust. The currency split is 1,110 in USD against 224 in EUR. And 81 of the 1,668 carry an ISIN — GSPC has US78378X1072, VIX has US12497K1007 — because index licensors do register identifiers for some products. Most do not, so treat a null ISIN here as normal.

One naming trap found while checking: there is no code FTSE. STOXX is the Stoxx Europe 600 and STOXX50E is the Euro Stoxx 50. Search the list rather than assuming the ticker you know from a newspaper.

The trap in the exchanges list

This is the single most consequential discovery bug in this part of the API, so it is worth stating flatly.

/exchanges-list returned 70 exchanges on 2026-07-28. FOREX and CC are both in it. INDX is not. Neither are BOND, EUBOND or COMM — and all four answer queries perfectly well. On the same day, /exchange-details reported 1,668 active tickers for INDX, 8,446 for BOND, 23,321 for EUBOND and 245 for COMM.

So the exchanges list is a catalogue of something, but not of every code the API accepts. Discovery logic that enumerates exchanges and then iterates over them will silently skip indices, bonds and commodities — four asset classes, gone, with no error anywhere. Before concluding a code does not exist, ask /exchange-details/{code} directly.

A price series with nothing behind it

Request /eod/GSPC.INDX and you get the familiar shape: date, open, high, low, close, adjusted_close, volume. It looks exactly like a stock.

Live API response: sp500 index daily bar

It is not one. An index does not trade. There is no bid, no ask and no order book, because there is nothing to buy. The level is computed from constituent prices by a formula, published continuously by the index provider, and the volume column counts no trades in the index at all. Note that it is not zero the way an FX row's is — it arrives populated and large, which makes it the harder of the two traps.

What does trade is a fund or a derivative that references the index. Here is the other side of that comparison, which is where the volume is real:

Interactive volume chart: SPY.US (1Y)

That volume is real — shares of a fund changing hands on an exchange, counted by that exchange. The index the fund tracks has no equivalent number, and never will.

GSPC.INDX is a price index: the level counts constituent prices and none of their dividends, which is why adjusted_close equals close on every one of its rows (2,684 rows since 2016, none differ, read 2026-09-07). SPY.US, in its adjusted_close, carries those dividends reinvested. Put the two side by side over ten years and the fund appears to beat its own index by the market's dividend yield, compounded. Compare the fund against a total-return series, SP500TR.INDX exists on the same exchange code, or compare the fund's raw close against the index level and accept that both then omit dividends. Record which of the two you chose beside every index comparison; the performance course in Portfolio Management measures the gap.

The CBOE family, and a warning about it

CBOE indices have their own pair of endpoints. /cboe/indices lists them; /cboe/index returns historical data for one.

On 2026-07-28 the list returned 123 entries in a JSON:API-style envelope quite unlike the flat arrays elsewhere in the API — each entry is {id, type: "cboe-index", attributes: {region, index_code, feed_type, date, index_close, index_divisor}}. Every region observed was European: UK, Germany, France, Spain, Nordic, Eurozone and so on. The US volatility index is not here; VIX lives on INDX.

Now the warning. The dates in that list are not current. The newest date in the entire response on 2026-07-28 was 2025-09-22, with large clusters in 2016 and 2017. Whatever this endpoint is, it is not a live quote board, and a dashboard that renders index_close as today's level will publish a wrong number with total confidence.

The historical endpoint has its own shape worth knowing: filter[index_code], filter[feed_type] and filter[date] are all three required. That makes it a single-date lookup, not a range query — to build a series you loop over dates. filter[include_review] is optional.

Try it now

  1. /exchanges-list cannot be shown here in full, so here is what it held on 28 September 2026 for the codes that matter:
Code In /exchanges-list?
US yes
FOREX yes
CC yes
INDX no
BOND no
EUBOND no
COMM no
All codes listed 70

And here is /exchange-details/INDX, asked anyway. The gap between those two answers is the lesson: write the discovery rule your code needs because of it.

Live API response: mda2 indx exchange details
  1. Here is GSPC.INDX for three sessions, then SPY.US, a fund that tracks it, for the same three. Read the volume column of each and say which one counts something, and what.
Live API response: mda2 gspc volume 2026 09
Live API response: mda2 spy volume 2026 09
3. Here is `/cboe/indices` as it arrives: its count, its first three entries and its last, sorted newest first by the endpoint itself. Counted on 28 September 2026, 112 of the 123 dates fell in 2016 or 2017 and none was later than 22 September 2025. Compare the newest date with the date beside the table's title, and before you use any of those values, decide what you will do about how old they are.
Live API response: mda22 cboe indices head