Fund Shareholder Reports (N-CSR)
The cover sheet of every N-CSR and N-CSRS certified shareholder report, with the roster of fund series, share classes and TICKERS the report covers. Twice a year since 2003, this is a point-in-time record of which funds a trust ran and what they traded as - the join key from a market ticker back to a fund's SEC filings.
edgar_fund_shareholder_reports - the dataset name to pass to the Obscura API.
What one row means
One **certified shareholder report** - Form `N-CSR` (annual) or `N-CSRS` (semi-annual) - filed by a registered investment company under Rule 30a-2. 37,675 `N-CSR` and 37,236 `N-CSRS` since **2003-02-07** and **2003-07-28** respectively (the earliest of each in the EDGAR full indexes), and no collector claimed either until now. # THIS IS THE COVER SHEET AND THE FUND ROSTER. IT IS NOT THE REPORT. An N-CSR is the fund's annual report to shareholders wrapped in a cover: the president's letter, the manager commentary, the schedule of investments, the financial statements and the notes - HTML prose and images. It is enormous. **Direxion Shares ETF Trust's `0001133228-25-002399` is 95 MB in one submission**, of which 269 members are `GRAPHIC`; AMG Funds' `0001193125-25-050865` is 33 MB with 91 graphics. Warehousing the bodies of 74,911 such filings is not a storage question, it is impossible on this pipeline: `tasks::export::copy_csv_bytes` buffers a whole table into RAM as CSV, which caps a table around 10-15 GB. So this follows the `edgar_foreign_reports` and `edgar_filing_text` rule - derive, do not warehouse. What survives is the SGML cover sheet, the document manifest with each member's filer-written `<DESCRIPTION>`, the certification and XBRL flags, and the one thing on an N-CSR that is genuinely structured across all 23 years: # THE SERIES/CLASS/TICKER ROSTER IS THE REAL PAYLOAD EDGAR writes a `<SERIES-AND-CLASSES-CONTRACTS-DATA>` block into the SGML header of a fund filing, naming every series and share class the report covers and, usually, each class's TICKER. Direxion's amendment states **93 series, 93 classes and 93 tickers**; AMG Funds states 14 series, 34 classes and 34 tickers. Since each report is stamped with a fiscal `period_end`, the corpus is a 23-year, twice-yearly, point-in-time record of which funds a trust ran and what they traded as. **The block is absent on a large minority of the family, and its absence is information.** Closed-end funds and fund-of-fund LLCs have no series at all: A&Q Long/Short Strategies Fund LLC (`0001193125-25-050694`) states none, and nor do the standalone N-CSRs sampled from 2024 and 2025. `series_count = 0` means "this registrant has no series", not "the parse missed it". `edgar_fund_series_classes` is the dedicated relational crosswalk for this block, fed today from prospectus filings only; the roster here is JSON on the report row and the two are complementary rather than duplicative. # `has_xbrl` MARKS A REGIME BREAK, NOT A FILER PREFERENCE SEC's Tailored Shareholder Report rule (compliance date **2024-07-24**) requires open-end funds to tag the report in Inline XBRL. Measured on four dissemination days: | day | submissions sampled | carrying an XBRL instance | |---|---|---| | 2019-03-12 | 11 | **0** | | 2024-06-05 | 12 | **0** | | 2024-09-05 | 12 | **11** | | 2025-03-10 | 30 | **25** | The five modern filings without one are closed-end/LLC funds, which the rule does not reach. Behind that flag is a genuinely rich per-share-class fact set - AMG Funds' instance carries `oef:ExpenseRatioPct`, `oef:ExpensesPaidAmt`, `oef:AdvisoryFeesPaidAmt`, `oef:HoldingsCount` and `oef:AvgAnnlRtrPct` for all 34 of its classes. **This table does not extract those facts**; it records truthfully whether they are there. Extracting them is a separate dataset with a 2024-07-24 floor, and pretending a 2003-2024 row merely has NULLs would misrepresent 21 of the family's 23 years. See `docs/datasets/edgar_fund_shareholder_reports.md`.
One row per One row per N-CSR / N-CSRS / N-CSR/A / N-CSRS/A submission, keyed by its ACCESSION. The key is the accession and NOT the archive path because EDGAR indexes a submission under one path per associated registrant, so a report filed on behalf of several co-registered trusts would otherwise be counted once per trust. An amendment is its OWN row under its own accession and is never merged over the original: the pair IS the restatement record. The report BODY is deliberately not a column - see the type docs for the 95 MB single submission that settles it..
Point-in-time availability
Every Obscura dataset carries available_date: the calendar day the publisher made the row
available, day-of, with no session rounding. It is the one column a backtest filters on, and it means the
same thing on every dataset in the catalog.
For edgar_fund_shareholder_reports: filing_join: available_date is the EDGAR DISSEMINATION day, taken from the bronze object's own day partition, never from the header's FILED AS OF DATE. Evidence class B, CONFIRMED: over 45 submissions of this family and N-CEN sampled from the 2025-03-10 dissemination day, 45/45 state FILED AS OF DATE = 2025-03-10 = the day's feed partition, and 44/45 carry an ACCEPTANCE-DATETIME on that same calendar day with a maximum of 17:24:37 ET, inside EDGAR's 17:30 cut-off; the one exception was accepted Friday 2025-03-07 18:13:11, after the cut-off, and was disseminated the following Monday - dissemination behaving as documented, not an embargo. Unlike SEC UPLOAD/CORRESP correspondence there is no review hold on this family: a shareholder report is public the day EDGAR carries it. period_end is EDGAR's CONFORMED PERIOD OF REPORT, the fiscal period the report COVERS, and it precedes availability by the Rule 30a-2 filing window (10 days after transmission to shareholders, itself 60 days after period end); it is never an availability anchor.
Refresh cadence
Obscura refreshes edgar_fund_shareholder_reports every 6 hours - the most frequent scheduled job that re-collects or re-exports it. This is Obscura's own pipeline cadence, not the upstream publisher's release schedule; when a row became public is recorded per row in available_date.
Schema - 32 columns
The full public column list for edgar_fund_shareholder_reports, with the meaning of every field. The same
schema is served unauthenticated at https://api.obscura.trade/v1/catalog/edgar_fund_shareholder_reports.
| Column | Type | Description |
|---|---|---|
| accession | text · not null | PK. SEC accession number of the submission, e.g. `0001193125-25-050865`. The key is the accession, not the archive path: EDGAR lists one submission under one path per associated registrant. |
| filename | text · not null | The PRIMARY registrant's SEC EDGAR Archives path for this submission (`edgar/data/{cik}/{accession}.txt`), derived from the payload's own first `FILER:` block rather than from whichever index row was walked - so it is the same value on every ingestion path. The join key into `edgar_filings`. |
| available_date | date | Public availability date: the EDGAR DISSEMINATION day, recovered from the bronze object's day partition. The point-in-time anchor and the only date a backtest may key on. |
| period_end | date | EDGAR's `CONFORMED PERIOD OF REPORT` - the fiscal period the report COVERS (the fiscal year end for an `N-CSR`, the half-year for an `N-CSRS`). Always earlier than `available_date` on this family, by the Rule 30a-2 window: the report goes to shareholders within 60 days of period end and is filed within 10 days of that. An as-of date for the contents, NEVER an availability date. |
| accepted_at | timestamp with time zone | When SEC ACCEPTED the submission (`<ACCEPTANCE-DATETIME>`), US-Eastern wall clock stored under a UTC type. Deliberately NOT the availability date: an acceptance after EDGAR's 17:30 ET cut-off is disseminated the NEXT business day - `0001133228-25-002365` was accepted 2025-03-07 18:13:11 and disseminated 2025-03-10. NULL on a row ingested from the dissemination feed, whose envelope does not carry this stamp. |
| filed_as_of | date | SEC's LEGAL filing date (`FILED AS OF DATE`). Kept for parity with `edgar_filings`; never an availability date - measured in prod, 4.88 % of all EDGAR filings carry a back-dated value here. |
| form_type | text · not null | The submission type exactly as EDGAR states it. The family is exactly four literals, confirmed across 2003 Q2, 2003 Q3, 2018 Q3 and 2025-03-10: `N-CSR`, `N-CSR/A`, `N-CSRS`, `N-CSRS/A`. |
| is_semiannual | boolean · not null | TRUE when the report covers a SEMI-ANNUAL period (`N-CSRS` or `N-CSRS/A`) rather than a fiscal year. The single most important filter on this table: the annual report is audited and the semi-annual one is not, so mixing them is mixing audited and unaudited statements. Derived from `form_type`, and the migration CHECKs the derivation as a biconditional rather than trusting the writer. |
| is_amendment | boolean · not null | TRUE when this is an amendment (`N-CSR/A` or `N-CSRS/A`) restating an earlier report. A separate row under its own accession, never a merge over the original. Measured 136 `N-CSR/A` and 88 `N-CSRS/A` across the four sampled periods. Also CHECKed as a biconditional on `form_type`. |
| cik | bigint | Central Index Key of the PRIMARY registrant - the first `FILER:` block in the header, which is also the registrant whose path `filename` names. |
| company_name | text | Primary registrant's name as EDGAR conforms it, e.g. `AMG FUNDS`, `ADVISORS SERIES TRUST`. |
| sic_code | integer | The registrant's SIC code, read from its own header block. Overwhelmingly `6726` (investment offices) on this family. |
| state_of_incorporation | text | Where the trust is ORGANISED, as an EDGAR state-or-country code (`DE`, `MA`, `MD` for the great majority - Delaware statutory trusts and Massachusetts business trusts). NULL where the registrant's header states none. |
| business_state | text | The registrant's business-address state as a bare EDGAR state code, e.g. `NY`, `WI`. Note this is the EDGAR code, NOT the ISO `US-NY` form that `edgar_ncen_filings` carries - the two families use different vocabularies and do not join without normalisation. |
| business_city | text | The registrant's business-address city from its header block, verbatim and unnormalised. |
| irs_number | text | The registrant's IRS Employer Identification Number as text (leading zeros are significant), or NULL. EDGAR's nine-zero placeholder `000000000` - which means "none stated" and is common on fund trusts - is normalised to NULL rather than stored as a string that reads like a real identifier. |
| fiscal_year_end | text | The registrant's fiscal year end as EDGAR's four-digit `MMDD`, e.g. `1231`, `0630`. Text, not a date - it names a recurring day, not an instant. Useful against `period_end` to tell an on-cycle report from an off-cycle one. |
| sec_file_number | text | The registrant's SEC file number, e.g. `811-21195`. Effectively always an `811-` Investment Company Act number on this family. |
| co_filers | jsonb · not null | JSON array of the ADDITIONAL registrant blocks after the first, as `[{"cik":…,"name":…,"file_number":…}]`; `[]` on the overwhelming majority with a single filer. Non-empty exactly where one report is filed on behalf of several co-registered trusts, which is why the accession rather than the path is the key. |
| series_count | integer · not null | How many fund SERIES the report covers, from the header's `<SERIES-AND-CLASSES-CONTRACTS-DATA>` block. **Zero is a real answer, not a gap**: closed-end funds and fund-of-fund LLCs have no series (A&Q Long/Short Strategies Fund states none). Measured 93 on Direxion's amendment and 14 on AMG Funds. |
| class_count | integer · not null | How many SHARE CLASSES the report covers across all its series. Exceeds `series_count` wherever funds are multi-class - AMG Funds states 14 series and 34 classes (Class N / Class I / Class Z), Direxion states 93 and 93 (single-class ETFs). |
| ticker_count | integer · not null | How many of the `class_count` classes state a TICKER. A missing ticker is information: an insurance-dedicated or institutional class is not exchange-traded. Both Direxion (93/93) and AMG (34/34) are fully tickered, but the fund-of-funds and separate-account trusts in this family are not. |
| series_classes | jsonb · not null | Ordered JSON array of the full roster as `[{"series_id":"S000009876","series_name":…,"class_id":"C000027322","class_name":"Class Z","ticker":"TMDIX"}]` - one entry per (series, class), with `class_id`/`ticker` null where the series states no classes or a class states no symbol. `[]` where the registrant has no series. This is the point-in-time fund roster the type docs describe, and the relational crosswalk beside it is `edgar_fund_series_classes`. |
| tickers | jsonb · not null | Flat JSON array of the DISTINCT tickers in `series_classes`, e.g. `["TMDIX","TMDPX","TQMIX"]`; `[]` where none. A denormalisation of the roster kept deliberately: "which reports covered TMDIX" is the most common question asked of this table and a GIN index over a flat array answers it without unnesting the nested roster. |
| document_count | integer | Number of documents in the submission (`PUBLIC DOCUMENT COUNT:`) - the TOTAL, including images and the XBRL rendering artifacts. Measured 8 on a small fund-of-funds report and 382 on Direxion's amendment. |
| exhibits | jsonb · not null | Ordered JSON array of every NON-image document in the submission as `[{"type":…,"sequence":…,"filename":…,"description":…}]` - the report itself plus its certifications, code of ethics and XBRL members, with the filer's own verbatim `<DESCRIPTION>`. `GRAPHIC` members are excluded and counted in `graphic_count` instead: they were 269 of 382 members on Direxion's amendment and 91 of 111 on AMG's report, and their description is the literal word `GRAPHIC` or empty. |
| graphic_count | integer · not null | How many `GRAPHIC` (image) members the submission carried - 269 on Direxion's amendment, 91 on AMG Funds', 9 on a small single-fund report. The reason `document_count` so exceeds `jsonb_array_length(exhibits)`, and a rough proxy for how chart-heavy the report is. |
| has_xbrl | boolean · not null | TRUE when the submission carries an XBRL instance or `EX-101.*` member. **A regime marker, not a filer preference** - measured 0/11 on 2019-03-12, 0/12 on 2024-06-05, 11/12 on 2024-09-05 and 25/30 on 2025-03-10, straddling the Tailored Shareholder Report compliance date of 2024-07-24. The per-share-class `oef:` facts behind this flag are NOT extracted into this table; see the type docs. |
| has_302_certification | boolean · not null | TRUE when the submission attaches the Rule 30a-2(a) / Section 302 certification (`EX-99.CERT`). Required on every N-CSR and N-CSRS, so a FALSE is a genuinely deficient filing rather than an ordinary variation. |
| has_906_certification | boolean · not null | TRUE when the submission attaches the Section 906 certification (`EX-99.906CERT`). The document TYPE is spelled inconsistently by filers - `EX-99.906CERT`, `EX-99.906 CERT` and `EX-99.906CE` all occur in the sampled filings - and the detector normalises whitespace before matching, which a unit test pins. |
| has_code_of_ethics | boolean · not null | TRUE when the submission attaches the registrant's code of ethics (`EX-99.CODE`, also filed as `EX-99.CODE ETH` and `EX-99.CODEETH`). Item 2 requires it only when the code changed or a waiver was granted during the period, so a FALSE here is the ordinary case and a TRUE is the event. |
| primary_description | text | The filer's own `<DESCRIPTION>` for the primary report document, e.g. `AMG FUNDS`, `ANNUAL REPORT`. Free text, not a controlled vocabulary, and frequently just the trust's name. |
Access edgar_fund_shareholder_reports
Two delivery paths, one identifier. Both require an Obscura account and an active subscription; the catalog entry and the schema above are public.
import obscura
client = obscura.Client("obs_live_…")
df = client.query(
dataset="edgar_fund_shareholder_reports",
symbols=["NVDA", "AAPL"],
start="2024-01-01",
)
Create a free account Browse all 122 datasets
Frequently asked questions
What is in the edgar_fund_shareholder_reports dataset?
The cover sheet of every N-CSR and N-CSRS certified shareholder report, with the roster of fund series, share classes and TICKERS the report covers. Twice a year since 2003, this is a point-in-time record of which funds a trust ran and what they traded as - the join key from a market ticker back to a fund's SEC filings. One **certified shareholder report** - Form `N-CSR` (annual) or `N-CSRS` (semi-annual) - filed by a registered investment company under Rule 30a-2. 37,675 `N-CSR` and 37,236 `N-CSRS` since **2003-02-07** and **2003-07-28** respectively (the earliest of each in the EDGAR full indexes), and no collector claimed either until now. # THIS IS THE COVER SHEET AND THE FUND ROSTER. IT IS NOT THE REPORT. An N-CSR is the fund's annual report to shareholders wrapped in a cover: the president's letter, the manager commentary, the schedule of investments, the financial statements and the notes - HTML prose and images. It is enormous. **Direxion Shares ETF Trust's `0001133228-25-002399` is 95 MB in one submission**, of which 269 members are `GRAPHIC`; AMG Funds' `0001193125-25-050865` is 33 MB with 91 graphics. Warehousing the bodies of 74,911 such filings is not a storage question, it is impossible on this pipeline: `tasks::export::copy_csv_bytes` buffers a whole table into RAM as CSV, which caps a table around 10-15 GB. So this follows the `edgar_foreign_reports` and `edgar_filing_text` rule - derive, do not warehouse. What survives is the SGML cover sheet, the document manifest with each member's filer-written `<DESCRIPTION>`, the certification and XBRL flags, and the one thing on an N-CSR that is genuinely structured across all 23 years: # THE SERIES/CLASS/TICKER ROSTER IS THE REAL PAYLOAD EDGAR writes a `<SERIES-AND-CLASSES-CONTRACTS-DATA>` block into the SGML header of a fund filing, naming every series and share class the report covers and, usually, each class's TICKER. Direxion's amendment states **93 series, 93 classes and 93 tickers**; AMG Funds states 14 series, 34 classes and 34 tickers. Since each report is stamped with a fiscal `period_end`, the corpus is a 23-year, twice-yearly, point-in-time record of which funds a trust ran and what they traded as. **The block is absent on a large minority of the family, and its absence is information.** Closed-end funds and fund-of-fund LLCs have no series at all: A&Q Long/Short Strategies Fund LLC (`0001193125-25-050694`) states none, and nor do the standalone N-CSRs sampled from 2024 and 2025. `series_count = 0` means "this registrant has no series", not "the parse missed it". `edgar_fund_series_classes` is the dedicated relational crosswalk for this block, fed today from prospectus filings only; the roster here is JSON on the report row and the two are complementary rather than duplicative. # `has_xbrl` MARKS A REGIME BREAK, NOT A FILER PREFERENCE SEC's Tailored Shareholder Report rule (compliance date **2024-07-24**) requires open-end funds to tag the report in Inline XBRL. Measured on four dissemination days: | day | submissions sampled | carrying an XBRL instance | |---|---|---| | 2019-03-12 | 11 | **0** | | 2024-06-05 | 12 | **0** | | 2024-09-05 | 12 | **11** | | 2025-03-10 | 30 | **25** | The five modern filings without one are closed-end/LLC funds, which the rule does not reach. Behind that flag is a genuinely rich per-share-class fact set - AMG Funds' instance carries `oef:ExpenseRatioPct`, `oef:ExpensesPaidAmt`, `oef:AdvisoryFeesPaidAmt`, `oef:HoldingsCount` and `oef:AvgAnnlRtrPct` for all 34 of its classes. **This table does not extract those facts**; it records truthfully whether they are there. Extracting them is a separate dataset with a 2024-07-24 floor, and pretending a 2003-2024 row merely has NULLs would misrepresent 21 of the family's 23 years. See `docs/datasets/edgar_fund_shareholder_reports.md`.
How do I avoid look-ahead bias with edgar_fund_shareholder_reports?
Filter on edgar_fund_shareholder_reports.available_date, the day the publisher made the row public. For this dataset that date is derived as follows - filing_join: available_date is the EDGAR DISSEMINATION day, taken from the bronze object's own day partition, never from the header's FILED AS OF DATE. Evidence class B, CONFIRMED: over 45 submissions of this family and N-CEN sampled from the 2025-03-10 dissemination day, 45/45 state FILED AS OF DATE = 2025-03-10 = the day's feed partition, and 44/45 carry an ACCEPTANCE-DATETIME on that same calendar day with a maximum of 17:24:37 ET, inside EDGAR's 17:30 cut-off; the one exception was accepted Friday 2025-03-07 18:13:11, after the cut-off, and was disseminated the following Monday - dissemination behaving as documented, not an embargo. Unlike SEC UPLOAD/CORRESP correspondence there is no review hold on this family: a shareholder report is public the day EDGAR carries it. period_end is EDGAR's CONFORMED PERIOD OF REPORT, the fiscal period the report COVERS, and it precedes availability by the Rule 30a-2 filing window (10 days after transmission to shareholders, itself 60 days after period end); it is never an availability anchor. A query of the form WHERE available_date <= '<as-of date>' never sees a row before it existed.
In what formats can I get edgar_fund_shareholder_reports?
As a Parquet bulk export (POST https://api.obscura.trade/v1/download) or as JSON from the typed query API (POST https://api.obscura.trade/v1/query), both with dataset="edgar_fund_shareholder_reports". The column schema is public at https://api.obscura.trade/v1/catalog/edgar_fund_shareholder_reports.
Can I filter edgar_fund_shareholder_reports by company or symbol?
Yes. edgar_fund_shareholder_reports carries cik, the column the API's symbols filter resolves against.
How often is edgar_fund_shareholder_reports updated?
Obscura refreshes edgar_fund_shareholder_reports on a every 6 hours schedule - that is the most frequent scheduled job that re-collects or re-exports the table. It is Obscura's own pipeline cadence, not the upstream publisher's release schedule; when the publisher makes a row available is described by the availability rule above, and is recorded per row in available_date.