If you are building an agent or a model on SEC fund-holdings data, it will read a field called IDENTIFIER_TICKER and trust it. Here is what that field actually contains.
If you build fund-ownership data from SEC Form N-PORT, you will read a field called IDENTIFIER_TICKER and treat it as a stock symbol. The SEC's data-set documentation describes it in one word: "Ticker".
The form itself says more. Form N-PORT, Item C.1.e, asks for "at least one" other identifier: an ISIN, or a "Ticker (if ISIN is not available)", or some other identifier. Nothing requires the ticker to be an exchange symbol. It is a fallback.
So we measured what funds actually put there - every quarter the SEC has published, 2019 Q4 to 2026 Q2:
- 17,361,050 rows carry a ticker.
- 72% are on common-stock lines, and they look like real tickers: MSFT, AMZN, AAPL.
- On mortgage-backed lines (676,336 rows) the "tickers" are agency pool-type prefixes: FN 161,550 rows, GN 109,156, FNMA 55,140, FHLMC 45,223.
- On bond lines (2,312,102 rows) the ticker is the ISSUER's stock symbol, not the bond's: AT&T bonds carry "T" on 86,298 rows.
- On derivative lines you find futures contract codes (TYZ2, ESZ2) and currency codes (USD, EUR).
Why it matters: FG is a Freddie Mac pool prefix. It is also the NYSE ticker of F&G Annuities & Life. Join N-PORT's ticker field to a ticker list and Freddie Mac mortgage pools turn into holdings of an insurance company. Bond holdings turn into stock holdings. Ownership counts, "smart money" signals and flow features all inherit it - silently.
Two more traps in the same files:
- Placeholders that look like data: ISSUER_CUSIP is "N/A" on 47.5 million rows, "000000000" on 15.2 million and "999999999" on 210 thousand. ISSUER_LEI is "N/A" on 67.6 million. Count those as filled and your coverage numbers are wrong.
- The SEC's machine-readable field list ships unchanged with every historical quarter, so a field "defined" there may not exist in older files (the VaR table is listed back to 2019 but only appears from 2022 Q1).
What to do: before trusting any identifier on an N-PORT line, check what kind of holding the line is (the ASSET_CAT field), and treat placeholder values as blank.
What I don't know yet:
- Whether anyone publishes an open mapping from N-PORT pool prefixes (FN, GN, FG...) to the agency programs they stand for. I could not find one.
- How much of the bond-line "issuer ticker" habit comes from filers themselves and how much from the software vendors that prepare their filings.
We published the full N-PORT field dictionary - the SEC's definitions with citations, the official code lists, and what is actually in each field - free, under CC BY 4.0: https://alexbocio.github.io/us-gov-data-dictionary/sec_nport.html
Source data: SEC Form N-PORT data sets, 2019 Q4 - 2026 Q2.
If you build fund-ownership data from N-PORT: how do you handle the non-stock lines today - map them, or drop them? And if someone has already solved this better, link it in the comments and I'll credit it in the dictionary.
Top comments (4)
The "ticker field is a fallback" finding also matters for time, not only for identity. A point for anyone building a fund-ownership feature from these files: the date you join on has to be when the holdings became public, not the report period. As I understand the N-PORT rules, only the third month of each fiscal quarter is public, about 60 days after quarter end, so a backtest that stamps holdings at the period end is using data nobody outside the fund had yet.
On your open question about filers versus filing vendors: one cheap test is to group the bond-line issuer-ticker rate by filing agent or by software-generated accession prefix. If it clusters by agent and not by fund family, it's the vendor. If you have the accession numbers in the extract, that's one groupby.
The placeholder numbers ("N/A" on 47.5M CUSIP rows) are a good reminder too: coverage should be computed after normalising placeholders, which you already say. I build canli-mcp (free, MIT,
npx -y canli-mcp, github.com/arhancanli/canlicapital) for EDGAR and macro lookups; I hit the same class of issue with acceptance timestamps, where the same filing carried different offsets in different companies' files.Agreed on the timing, and it's the more dangerous half. A holdings feature joined on the report period is reading data nobody outside the fund had yet; the date to join on is when the filing became public. N-PORT makes that easy to get wrong because the period date sits right there in every row.
The accession-prefix test is a good one. The first ten digits of an accession number are the submitter's CIK, which for many funds is a filing agent, so it really is one groupby. I'll run it and post what it shows.
And thanks for the canli-mcp pointer. If it helps your acceptance-time work: our check matched EDGAR's index-header ACCEPTANCE-DATETIME to the second on 200 of 200 filings, so the header is a usable reference.
In institutional fund pipelines, the standard rule is never letting non-equity lines touch security master resolution without first partitioning on ASSET_CAT and INV_CAT.
For common stock lines, stripping the ticker field and joining to an equity master works as expected. The moment a pipeline encounters fixed income or agency debt, treating the ticker as an instrument identifier creates immediate phantom equity exposure. On corporate bond rows, filers routinely report the parent entity ticker, so joining on that symbol maps hundreds of millions in debt obligations into common stock ownership models.
For agency mortgage pools, the issue runs deeper because CUSIP licensing fees push filers to use ad-hoc prefixes. Dropping those rows blinds a portfolio monitor to liquidity and interest rate exposure, while mapping them cleanly usually requires parsing the pool prefix and matching against agency schedules like Fannie Mae PoolTalk rather than standard ticker feeds. OpenFIGI resolves many of the debt and derivative rows that lack exchange tickers, but raw pool lines almost always need a custom agency parser before any downstream agent can touch them safely.
Useful pointer on PoolTalk, thanks. Partitioning on ASSET_CAT first is the same conclusion we reached. Do you know of anyone who publishes an open mapping from the pool prefixes to agency programs? I couldn't find one, and it seems like something that should exist.