Portfolio exposure API
What does a portfolio of ETFs hold underneath, and where does its risk come from? GET /api/v1/lookthrough?portfolio=VOO:60,QQQ:40 weighs each fund's holdings by its share of the portfolio and adds them up: every company with its percent of the portfolio, its value when amounts are given, and the funds it comes through. The MCP tool get_etf_portfolio_risk adds the portfolio's volatility and each fund's share of the risk, from up to three years of weekly returns.
Live example
The request: GET /api/v1/lookthrough?portfolio=VOO:60,QQQ:40&top=5
60% VOO and 40% QQQ on this build, from VOO's file of and QQQ's of : 518 companies underneath, the ten largest 41.1% of the portfolio. The five largest, with the part each fund adds:
{
"holdings_as_of": {"VOO": "2026-08-31", "QQQ": "2026-10-12"},
"distinct_companies": 518,
"top_10_weight_pct": 41.1,
"companies": [
{
"ticker": "NVDA",
"weight_pct": 8.136,
"through": [
{"fund": "VOO", "weight_pct": 4.8556},
{"fund": "QQQ", "weight_pct": 3.2806}
]
},
{
"ticker": "AAPL",
"weight_pct": 7.219,
"through": [
{"fund": "VOO", "weight_pct": 4.2259},
{"fund": "QQQ", "weight_pct": 2.993}
]
},
{
"ticker": "MSFT",
"weight_pct": 5.839,
"through": [
{"fund": "VOO", "weight_pct": 3.422},
{"fund": "QQQ", "weight_pct": 2.4168}
]
},
{
"ticker": "AMZN",
"weight_pct": 3.993,
"through": [
{"fund": "VOO", "weight_pct": 2.3092},
{"fund": "QQQ", "weight_pct": 1.6836}
]
},
{
"ticker": "GOOGL",
"weight_pct": 3.052,
"through": [
{"fund": "VOO", "weight_pct": 1.8069},
{"fund": "QQQ", "weight_pct": 1.2448}
]
}
]
}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/lookthrough?portfolio=VOO:60,QQQ:40&top=5"
Python
Needs Python 3.9 or later and the tickerinside client, pip install tickerinside, which uses only the standard library.
import tickerinside as ti
mix = ti.look_through({"VOO": 60, "QQQ": 40}, top=5)
for fund, date in mix.holdings_as_of.items():
print(fund, date)
print(mix.data["distinct_companies"], mix.data["top_10_weight_pct"])
for company in mix.data["companies"]:
print(company["ticker"], company["weight_pct"])
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/lookthrough"
+ "?portfolio=VOO:60,QQQ:40&top=5";
const mix = await (await fetch(url)).json();
for (const [fund, date] of Object.entries(mix.holdings_as_of)) {
console.log(fund, date);
}
console.log(mix.distinct_companies, mix.top_10_weight_pct);
for (const c of mix.companies) console.log(c.ticker, c.weight_pct);
Google Sheets
Paste it into a cell: Sheets fills the rows below with the CSV twin of the answer, the date on every row. Excel and Power BI read the same address with Power Query; the queries are on ETF holdings in Excel and Google Sheets.
=IMPORTDATA("https://tickerinside.com/api/v1/lookthrough.csv?portfolio=VOO:60,QQQ:40")
MCP tool, over HTTP
In Claude, ChatGPT, Cursor or VS Code, add the MCP server once (how to add it) and ask in words; the assistant makes this same call.
curl -s https://tickerinside.com/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc": "2.0", "id": 1, "method": "tools/call", "params":
{"name": "get_etf_portfolio_risk", "arguments": {"positions": [
{"ticker": "VOO", "amount": 60}, {"ticker": "QQQ", "amount": 40}]}}}'
Fields to read
companies: The companies underneath, largest first, each with weight_pct (its percent of the portfolio), value and through (the funds it comes through, with the part each adds).distinct_companies: How many companies the portfolio holds through its funds.top_10_weight_pct: The weight of the ten largest companies together, in percent.holdings_as_of: The date of each fund's holdings file.holdings_source: Where each fund's holdings come from.
Limits
- One call takes 1 to 6 funds, whose files weigh at most 30 KB and hold at most 1,100 lines between them. The MCP tools take 1 to 60 funds.
- The amounts are proportions: VOO:60,QQQ:40 and VOO:6000,QQQ:4000 give the same percentages, and without amounts every fund counts equally.
topkeeps the largest companies, 25 by default. - Funds whose holdings are not shares, such as bond funds, commodity pools and leveraged or inverse funds, are named in
not_looked_throughand left out of the percentages. - Risk needs a year of weekly prices for every fund in the portfolio.
/api/v1/lookthrough.csvgives one row per company, with the funds it comes through and their dates.
Reference
- The endpoint's fields, errors and examples: the API reference.
- In an assistant: the MCP server's tools
get_etf_portfolio_lookthroughandget_etf_portfolio_riskanswer 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, ETF holdings history API, ETF screener API.