How do I calculate the holdings overlap between two ETFs?
Overlap is the sum over shared holdings of the smaller of the two weights. Compute it from data.topHoldings, or call GET /overlap?isins=A,B for a name-matched result. Formula, Python and the free tool.Updated 12 September 2026 · by FundFacts APIShort answer
Overlap = Σ over holdings present in both funds of min(weight in A, weight in B), in percent of portfolio. GET https://fundfactsapi.com/api/v1/overlap?isins=A,B (Pro and above) does the name matching and returns overlap, sharedCount and the shared list per pair; on any plan you can compute the same from each fund's data.topHoldings, limited to the positions the fund houses publish. The free ETF overlap tool on this site runs the endpoint in the browser.
The formula
For two funds A and B with holdings weights wA[name] and wB[name] in percent:
textoverlap(A, B) = Σ_{name ∈ A ∩ B} min(wA[name], wB[name])
An overlap of 40 means 40% of each portfolio's weight sits in names the other fund also holds (at the smaller of the two weights). Two share classes of the same index fund overlap near 100; a world ETF and an emerging-markets ETF near 0.
From the payload
pythonimport os, requestsH = {"Authorization": f"Bearer {os.environ['FUNDFACTS_API_KEY']}"}def holdings(isin):d = requests.get(f"https://fundfactsapi.com/api/v1/funds/{isin}", headers=H, timeout=300).json()["data"]return {h["name"].upper(): h["weight"] for h in d["topHoldings"]}a, b = holdings("IE00B4L5Y983"), holdings("IE00B3RBWM25")shared = {n: min(a[n], b[n]) for n in a.keys() & b.keys()}print(round(sum(shared.values()), 2), "% overlap over published holdings;", len(shared), "shared names")
This is exact over the positions the fund houses publish (the full file for most large ETFs, the top ten for factsheet-only funds) and is what the endpoint does, with better name matching.
The endpoint
bashcurl -s "https://fundfactsapi.com/api/v1/overlap?isins=IE00B4L5Y983,IE00B3RBWM25" -H "Authorization: Bearer $FUNDFACTS_API_KEY"
json{ "pairs": [ { "a": "IE00B4L5Y983", "b": "IE00B3RBWM25", "overlap": 71.4, "sharedCount": 612, "disclosed": { "a": 100, "b": 100 }, "shared": [ { "label": "NVIDIA", "a": 5.48, "b": 4.61 } ] } ] }
disclosed states what share of each portfolio the published holdings cover, so you can tell an exact 71% from a top-ten-only estimate. Several ISINs return every pair. One request per ISIN; Pro and above. The MCP server's fund_overlap tool wraps it for assistants.
Reading the number
Overlap is about names, not about risk: two funds with 30% overlap can still be 95% correlated because they hold the same sectors and countries. Pair it with the sector and geography tables, or with POST /portfolio for the aggregate view. How to calculate ETF holdings overlap goes deeper into matching and edge cases.
Verify it yourself
The demo endpoint returns the live payload for a fund that is already in the store, without a key. Everything on this page can be checked against it.bashcurl -s https://fundfactsapi.com/api/v1/demo/funds/IE00B4L5Y983 | jq '{name, asOf: .data.dataAsOf, ter: .data.headlineMetrics.ter, risk: .data.riskRating, top: .data.topHoldings[:3]}'