List an ETF's holdings from Form N-PORT
Read a fund's Form N-PORT from SecFeed, list its largest holdings with shares, value and weight, and break the portfolio down by asset category.
Registered funds, ETFs included, file Form N-PORT every month with a complete schedule of investments. The SEC makes the report for the third month of each fiscal quarter public 60 days after the period ends, so N-PORT is the authoritative public source for what a fund held at quarter end: every security, with identifiers, quantity, fair value, percentage of net assets and asset category.
This tutorial lists the holdings of one ETF series from its N-PORT filing.
Fetch the filing
GET /v1/n-port returns N-PORT filings parsed to JSON. Filter by cik (the registrant, usually a trust that holds many series) and a date range. Each filing covers one series, named in genInfo.seriesName, so pick the series you want from the trust's filings.
This example uses Running Oak Efficient Growth ETF, a series of Strategic Trust (CIK 1873280).
import os
from collections import Counter
import requests
BASE = "https://secfeedapi.com"
HEADERS = {"Authorization": f"Bearer {os.environ['SECFEED_KEY']}"}
CIK, SERIES = 1873280, "Running Oak Efficient Growth ETF"
r = requests.get(f"{BASE}/v1/n-port", params={"cik": CIK, "startDate": "2026-09-01"}, headers=HEADERS, timeout=120)
r.raise_for_status()
filing = next(f for f in r.json()["filings"] if f["data"]["primary_doc"]["formData"]["genInfo"]["seriesName"] == SERIES)
form = filing["data"]["primary_doc"]["formData"]
gen, fund = form["genInfo"], form["fundInfo"]
holdings = form["invstOrSecs"]["invstOrSec"]
if isinstance(holdings, dict):
holdings = [holdings]
print(f"{gen['seriesName']} ({gen['seriesId']}), filed {filing['filedAt']}")
print(f"Period end {gen['repPdDate']} | net assets ${float(fund['netAssets']):,.0f} | holdings {len(holdings)}")
print()
print(f"{'Holding':<34}{'CUSIP':<11}{'Shares':>12}{'Value (USD)':>16}{'Weight':>8}")
for h in sorted(holdings, key=lambda h: -float(h["pctVal"]))[:10]:
print(f"{h['name'][:33]:<34}{h['cusip']:<11}{float(h['balance']):>12,.0f}{float(h['valUSD']):>16,.0f}{float(h['pctVal']) / 100:>8.2%}")
cats = Counter()
for h in holdings:
cats[h.get("assetCat") or "other"] += float(h["pctVal"])
print()
print("Weight by asset category:", {k: f"{v:.1f}%" for k, v in cats.most_common()})
print(f"Top 10 weight: {sum(sorted((float(h['pctVal']) for h in holdings), reverse=True)[:10]):.1f}%")
Output:
Running Oak Efficient Growth ETF (S000080468), filed 2026-10-09
Period end 2026-08-31 | net assets $415,687,534 | holdings 59
Holding CUSIP Shares Value (USD) Weight
SERVICENOW INC 81762P102 72,594 10,743,186 2.58%
ZEBRA TECHNOLOGIES CORP 989207105 29,488 10,425,482 2.51%
IQVIA HOLDINGS INC 46266C105 36,690 9,583,061 2.31%
FACTSET RESEARCH SYSTEMS INC 303075105 29,160 9,143,118 2.20%
AUTOMATIC DATA PROCESSING INC 053015103 30,897 8,841,486 2.13%
CACI INTERNATIONAL INC 127190304 13,937 8,682,890 2.09%
ARTHUR J. GALLAGHER & COMPANY 363576109 32,796 8,597,471 2.07%
STATE STREET INSTITUTIONAL INVEST 857492888 8,474,306 8,474,306 2.04%
BROWN & BROWN INC 115236101 115,656 8,346,894 2.01%
JACOBS SOLUTIONS INC 46982L108 55,152 8,220,406 1.98%
Weight by asset category: {'EC': '97.9%', 'STIV': '2.0%'}
Top 10 weight: 21.9%
Where the fields come from
| Field | N-PORT item | Meaning |
|---|---|---|
name, cusip | C.1 | Issuer name and CUSIP of each holding |
balance, units | C.2 | Quantity held and its unit (NS = shares, PA = principal amount) |
valUSD | C.2 | Fair value in US dollars |
pctVal | C.2 | Value as a percent of net assets (2.58 means 2.58%) |
assetCat | C.4 | Asset category: EC equity common, STIV short-term investment vehicle, DBT debt and so on |
fundInfo.netAssets | B.1 | Net assets of the series |
pctVal is already a percentage, so the script divides by 100 before formatting it with %. The 2.0% in STIV is the fund's cash sweep, a money market fund position.
Compare snapshots
Each quarterly report gives you a snapshot. Fetch the same series a quarter earlier and join on CUSIP to see positions added, removed and resized. Because ETFs publish holdings daily on their own sites, N-PORT is most useful as the official, comparable record across many funds: you can run the same code over every series of a trust, or over every ETF in a date range.