ETF holdings history API
How did an ETF's holdings change from one file to the next? GET /api/v1/history/{ticker}.json gives a fund's history from the first issuer file the archive holds: one row per file date with its position count and top 10 weight, and one step per new file with the lines that entered, the lines that exited and the weights that moved by 0.05 points or more.
Live example
The request: GET /api/v1/history/spy.json
SPY on this build: 28 files, from to . The latest step in which lines entered or exited, from the file of to that of :
{
"ticker": "SPY",
"first": "2026-09-02",
"last": "2026-10-12",
"file_dates": 28,
"cadence": "daily",
"changes": [
{
"date": "2026-10-06",
"previous": "2026-10-05",
"entered": [["SKYD", 0.0077]],
"exited": [["PSKY", 0.008]]
}
]
}Code
Each block below is a file that runs against each night's build of this site that has the files it reads, before it is published, through the same Worker that answers the API: the code shown is the code that ran. A program that calls the API on its own should name its project in its User-Agent; it is a request, not a condition.
cURL
Prints the whole answer as JSON; add | jq to pick fields.
curl -s https://tickerinside.com/api/v1/history/spy.json
Python
Needs Python 3.9 or later and the tickerinside client, pip install tickerinside, which uses only the standard library.
import tickerinside as ti
spy = ti.history("SPY").data
print(spy["first"], spy["last"], spy["file_dates"])
for step in spy["changes"][-5:]:
for ticker, weight in step.get("entered", []):
print(step["date"], "entered", ticker, weight)
for ticker, weight in step.get("exited", []):
print(step["date"], "exited", ticker, weight)
JavaScript
Runs as a module in Node.js 20 or later (save it as a .mjs file), in Deno, or in a browser page: CORS is open.
const url = "https://tickerinside.com/api/v1/history/spy.json";
const spy = await (await fetch(url)).json();
console.log(spy.first, spy.last, spy.file_dates);
for (const step of spy.changes.slice(-5)) {
for (const [t, w] of step.entered ?? []) {
console.log(step.date, "entered", t, w);
}
for (const [t, w] of step.exited ?? []) {
console.log(step.date, "exited", t, w);
}
}
Fields to read
first: The date of the first file in the history.last: The date of the latest file.file_dates: How many files the history holds.snapshots: One row per file date: positions, top 10 weight, key scheme.changes: One step per file: date, previous (the file it is compared with), entered and exited with their weights, moved with the weight before and after.overlap_history: How the fund's overlap with its ten closest funds moved over the same dates.cite_as: A line to print under a figure, with the link to the file and its dates.
Limits
- The history covers the 697 funds with an archived issuer file, each from its first archived file; the archive holds files dated from 2026-07-31.
- Weights only: a step lists what entered, exited and moved, never share counts or market values.
- A step across a change of keys or of how a file is read is marked
restatedand lists no trades. - The history is published under the TickerInside history terms, not CC BY 4.0: free per request, commercial use included, with a link to the file quoted. Republishing the archive as a whole, or fetching many funds' histories on a schedule to store them, is not granted. The terms: /legal/#history.
Reference
- The endpoint's fields, errors and examples: the API reference.
- In an assistant: the MCP server's tools
get_etf_holdings_historyandget_etf_holdings_changesanswer the same question; add the server to Claude, ChatGPT, Cursor or VS Code with its address, no key. - The other use cases: ETF holdings API, ETF overlap API, Which ETFs hold a stock, by API, Portfolio exposure API, ETF screener API.