Fund Annual Census Reports (N-CEN)
Form N-CEN annual census reports, one row per registered fund complex: who audits it, who underwrites it, the compliance officer, board composition, and the year's flags for material weaknesses, NAV errors, legal proceedings and financial support.
edgar_ncen_filings - the dataset name to pass to the Obscura API.
What one row means
One **Form N-CEN** annual census filing - the registrant-level half. N-CEN is the annual report every registered investment company files under Rule 30a-1. It replaced Form N-SAR: measured in the EDGAR full indexes, 2018 Q2 carries **1,062 `NSAR` filings and zero `N-CEN`**, and 2018 Q3 carries 198 `NSAR` and **139 `N-CEN` + 12 `N-CEN/A`**, the earliest dated **2018-09-07**. That is the changeover, and it is the floor of this dataset. # This is the STRUCTURED one Unlike the shareholder reports it sits beside (`edgar_fund_shareholder_reports`, which is prose), an N-CEN's payload is a single `primary_doc.xml` in SEC's own `ncen` namespace - schema-validated, one element per Form item. Everything in this table and in `edgar_ncen_series` is read off that XML, never inferred. # WHY THERE ARE TWO TABLES The Form has a registrant part (Items A-C.1: who the fund complex is, its directors, its CCO, its auditor, its underwriter) and a **per-series part** (Item C: one complete block per fund, with that fund's adviser, custodian, net assets, commissions and lending revenue). The two grains are genuinely different and the fan-out is severe - EQ Advisors Trust's 2024 census (`0001752724-25-052137`) is **3.4 MB carrying 110 series blocks**, Pacific Select Fund's states 122. Flattening them into one row would either lose 109 funds or repeat the registrant 110 times. This table is the registrant row; `edgar_ncen_series` is the fund row. One collector fills both from ONE pass over ONE bronze object, exactly as `edgar_nport_filings`/`edgar_nport_holdings` do. # `total_series` IS NOT `series_reported`, AND THE DIFFERENCE IS REAL `total_series` is Item B.5 - how many series the REGISTRANT has. `series_reported` is how many Item C blocks this filing actually carries. They are usually equal (Boyar 1/1, EQ Advisors 110/110, Securian 11/11) and sometimes wildly not: **Allspring Funds Trust's `0001752724-25-052135` states `total_series = 73` and carries ONE series block**, because a registrant whose series have different fiscal year ends files a separate N-CEN per fiscal-year group and each one reports only the series in its own group. So `SELECT total_series` answers "how big is this trust" and `count(edgar_ncen_series)` answers "how many funds does this filing describe". Using either for the other is wrong by a factor of 73 on a real 2025 filing, which is why both are stored rather than one being derived. # NOT EVERY N-CEN HAS SERIES, DIRECTORS OR AN AUDITOR The Form's sections are keyed to `investment_company_type`. An **N-6 insurance separate account** (Minnesota Life Variable Life Account, `0001752724-25-051617`) files a `registrantInfo` block and nothing else - no Item C series, no `directors`, no `publicAccountants`, no `total_series`. An **N-2 closed-end fund** (Cornerstone Total Return, `0001752724-25-052190`) does carry Item C. Every column that only some company types state is therefore nullable, and a NULL here is the Form not asking, never a parse gap. See `docs/datasets/edgar_ncen_filings.md`.
One row per One row per N-CEN or N-CEN/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; keying on the path would duplicate any census filed on behalf of more than one CIK. An amendment (N-CEN/A) is its OWN row with its own accession - it is never merged over the original, because the pair is the restatement record and collapsing it would destroy the only evidence that a census was corrected..
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_ncen_filings: 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 (SEC moves that field across the corpus; 4.88% of all EDGAR filings carry a back-dated one). N-CEN carries NO embargo - evidence class B, CONFIRMED: over 45 N-CSR-family and N-CEN submissions 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 were ACCEPTED that same calendar day (max acceptance 17:24:37 ET, inside EDGAR's 17:30 cut-off). The single exception was accepted Friday 2025-03-07 18:13:11, after the cut-off, and rolled forward to the Monday - which is dissemination working exactly as documented, not a lag. period_end is the Form's own reportEndingPeriod (Item A.2), the fiscal year the census DESCRIBES; it precedes availability by the statutory 75-day filing window and is never an availability anchor.
Refresh cadence
Obscura refreshes edgar_ncen_filings 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 - 41 columns
The full public column list for edgar_ncen_filings, with the meaning of every field. The same
schema is served unauthenticated at https://api.obscura.trade/v1/catalog/edgar_ncen_filings.
| Column | Type | Description |
|---|---|---|
| accession | text · not null | PK. SEC accession number of the submission, e.g. `0001752724-25-052122`. 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 | The fiscal period the census DESCRIBES - the Form's own `generalInfo/@reportEndingPeriod` (Item A.2), falling back to EDGAR's `CONFORMED PERIOD OF REPORT`. Always earlier than `available_date`: Rule 30a-1 gives 75 days after fiscal year end, and every 2025-03-10 sample states 2024-12-31. NEVER an availability date. |
| is_short_period | boolean | TRUE when the registrant states the reporting period was SHORTER than 12 months (`generalInfo/@isReportPeriodLt12`) - a newly formed or newly liquidated fund complex, or one that changed its fiscal year end. Read it before comparing `monthly_avg_net_assets` across filings: an annualised figure and a stub-period figure are not the same measurement. |
| 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, which is exactly what `0001133228-25-002365` (accepted 2025-03-07 18:13:11, disseminated 2025-03-10) shows. 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: `N-CEN` or `N-CEN/A`. The family has exactly these two literals, confirmed across 2018 Q3 (139 + 12) and the 2025-03-10 dissemination day (33 + 0). |
| is_amendment | boolean · not null | TRUE when this is an amendment (`N-CEN/A`) restating an earlier census. The amendment is a SEPARATE row with its own accession, never a merge over the original. Derived from `form_type`, and the migration CHECKs the derivation as a biconditional rather than trusting the writer. |
| cik | bigint | Central Index Key of the registrant, read from the Form's own `registrantCik` and falling back to the SGML header's first `FILER:` block. |
| company_name | text | The registrant's name as the Form states it (`registrantFullName`), e.g. `Boyar Value Fund Inc`, `ALLSPRING FUNDS TRUST`. Note this is the FILER'S spelling and differs in case and punctuation from EDGAR's conformed `COMPANY CONFORMED NAME` in the same submission's header. |
| registrant_lei | text | The registrant's Legal Entity Identifier (`registrantLei`), 20 characters, e.g. `54930000Q0UK48QTMX79`. The Form asks for it directly, which makes N-CEN one of the few EDGAR families carrying an LEI at all. NULL where the registrant states `N/A` - normalised rather than stored as the literal string, which would sort and join as if it were an identifier. |
| investment_company_type | text | Which registration form the company is registered on, from `filerInfo/investmentCompanyType`: `N-1A` (open-end mutual fund / ETF), `N-2` (closed-end fund), `N-3`/`N-4` (variable annuity separate account), `N-6` (variable life separate account), `N-5`, `N-8B-2`. **This column determines which of the Form's sections exist** - an `N-6` states no series, no directors and no auditor at all - so it must be read before any other column's NULL is interpreted. |
| registrant_classification_type | text | The registrant's own classification of itself (`registrantClassificationType`), which usually but not always repeats `investment_company_type`. Kept separately rather than collapsed: where the two disagree the disagreement is the filer's statement, not a parse error. |
| schema_version | text | SEC's `ncen` XML schema version for this submission, e.g. `X0404`. The Form has been revised since 2018 and elements have been added; this is the only in-band record of WHICH revision produced a row, and it is what an analyst should check before treating a NULL as an absence rather than as a field that did not yet exist. |
| sec_file_number | text | The registrant's Investment Company Act file number (`investmentCompFileNo`), e.g. `811-08253`. Effectively always an `811-` number on this family - it is the 1940 Act registration itself. |
| registrant_state | text | The registrant's principal-office state as an ISO 3166-2 subdivision code (`registrantstate`), e.g. `US-NY`, `US-OH`. NOTE the `US-` prefix: N-CEN uses ISO codes, NOT the bare two-letter EDGAR state codes that `edgar_filings` and `edgar_foreign_reports` carry, and the two do not join without normalisation. |
| registrant_country | text | The registrant's principal-office country as an ISO 3166-1 alpha-2 code (`registrantcountry`), e.g. `US`. |
| registrant_city | text | The registrant's principal-office city (`registrantcity`), verbatim as filed. |
| total_series | integer | Item B.5 - how many series the REGISTRANT has in total. **This is NOT the number of series this filing reports on**: Allspring Funds Trust's `0001752724-25-052135` states 73 here and carries ONE Item C block, because series with different fiscal year ends are censused in separate filings. Compare with `series_reported` before using either. NULL on the company types that have no series concept (N-6 separate accounts). |
| series_reported | integer · not null | How many Item C series blocks this filing actually carries - i.e. exactly how many `edgar_ncen_series` rows this accession produced. Stored rather than left to a `count(*)` so the registrant row alone is enough to spot the `total_series` divergence above, and so a truncated parse would be visible as a disagreement with the child table rather than silently looking complete. |
| director_count | integer | How many directors the registrant states on its board (Item B.9). NULL where the Form does not ask - N-6 and N-4 separate accounts have no board of their own. **The count includes interested and independent directors**; `interested_director_count` splits it. |
| interested_director_count | integer | How many of `director_count` the registrant marks as INTERESTED persons under Section 2(a)(19) (`isDirectorInterestedPerson = Y`) - i.e. affiliated with the adviser or underwriter rather than independent. Boyar Value Fund states 1 of 3. The independent count is the difference, and the ratio is the governance measure this column exists for. |
| cco_name | text | The name of the registrant's Chief Compliance Officer (Item B.10), e.g. `Jared Lahman`. A PERSON's name, and the reason this dataset is `Restricted`-adjacent in spirit even though it is public record: it is SEC-published, but it is people data and should be treated as such downstream. |
| is_cco_changed | boolean | TRUE when the registrant states its CCO CHANGED since the last filing (`isCcoChangedSinceLastFiling`). A compliance-turnover signal that is otherwise invisible: SEC publishes no CCO register, and this is a year-over-year delta the filer states directly. |
| public_accountant_name | text | The registrant's independent public accountant (Item B.12), e.g. `Cohen & Co. Ltd`. Fund-complex auditor concentration is measurable from this column alone across the whole 26,240-filing corpus. |
| pcaob_number | text | The auditor's PCAOB registration number, e.g. `925`. Text, not an integer: it is an identifier and the Form permits `N/A`, which is normalised to NULL. |
| is_accountant_changed | boolean | TRUE when the registrant states its independent accountant CHANGED during the period (`isPublicAccountantChanged`). Auditor changes at a fund complex are a documented governance signal and the Form asks the question directly. |
| is_material_weakness | boolean | TRUE when the accountant's report identified a MATERIAL WEAKNESS in internal control (`isMaterialWeakness`). The single highest-value boolean on the Form and almost always FALSE, which is precisely what makes a TRUE worth finding. |
| is_qualified_opinion | boolean | TRUE when the accountant's report was OTHER than unqualified (`isOpinionOffered` - the Form asks whether any opinion other than an unqualified one was offered). A qualified, adverse or disclaimed opinion on a registered fund. |
| is_accounting_principle_change | boolean | TRUE when the registrant reports a CHANGE IN ACCOUNTING PRINCIPLE or practice during the period (`isAccountingPrincipleChange`). A comparability break that a naive year-over-year read of `edgar_ncen_series` measures would otherwise miss. |
| is_nav_error_payment | boolean | TRUE when the registrant reports a NAV ERROR that required a payment to shareholders or by shareholders to the fund (`isPaymentErrorInNetAssetValue`). A pricing-failure event, self-reported. |
| is_legal_proceeding | boolean | TRUE when the registrant states a legal proceeding against it or its affiliates was pending or concluded in the period (`isPreviousLegalProceeding`). |
| is_fidelity_bond_claim | boolean | TRUE when a claim was FILED against the fidelity bond during the period (`coveredByInsurancePolicy/@isClaimFiledDuringPeriod`). Distinct from `is_legal_proceeding`: this is a loss actually claimed, not a suit. |
| is_financial_support_provided | boolean | TRUE when an affiliated person provided FINANCIAL SUPPORT to a fund during the period (`isFinancialSupportDuringPeriod`) - a sponsor propping up a fund, most often a money market fund. Rare and materially informative. |
| is_first_filing | boolean | TRUE when this is the registrant's FIRST N-CEN (`isRegistrantFirstFiling`) - the complex's arrival on the census. |
| is_last_filing | boolean | TRUE when the registrant states this is its LAST N-CEN (`isRegistrantLastFiling`) - the complex de-registering. The cleanest fund-complex-death signal EDGAR publishes, and it is a forward-looking statement made by the filer, not an inference from a gap in filings. |
| principal_underwriters | jsonb · not null | Ordered JSON array of the registrant's principal underwriters (Item B.13) as `[{"name":…,"file_number":…,"crd":…,"lei":…,"state":…,"country":…,"is_affiliated":…}]`; `[]` where none is stated. An array rather than scalars because a complex can name several, and unlike the per-series adviser this multiplicity is not bounded by the Form. |
| books_records_locations | jsonb · not null | Ordered JSON array of the offices where the registrant's books and records are kept (Item B.4) as `[{"name":…,"city":…,"state":…,"country":…,"description":…}]`. This is where the fund's administrator and accounting agent physically sit, and it is stated even by the N-6 separate accounts that state almost nothing else. |
| document_count | integer | Number of documents in the submission (`PUBLIC DOCUMENT COUNT:`) - typically 2, being `primary_doc.xml` plus the accountant's internal-control report. |
| has_internal_control_report | boolean · not null | TRUE when the submission attaches the independent accountant's INTERNAL CONTROL report (`attachmentsTab/isIPAReportInternalControl`, corroborated by an `INTERNAL CONTROL RPT` document member). Required of registrants that do not file it with an N-CSR. |
Access edgar_ncen_filings
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_ncen_filings",
symbols=["NVDA", "AAPL"],
start="2024-01-01",
)
Create a free account Browse all 122 datasets
Frequently asked questions
What is in the edgar_ncen_filings dataset?
Form N-CEN annual census reports, one row per registered fund complex: who audits it, who underwrites it, the compliance officer, board composition, and the year's flags for material weaknesses, NAV errors, legal proceedings and financial support. One **Form N-CEN** annual census filing - the registrant-level half. N-CEN is the annual report every registered investment company files under Rule 30a-1. It replaced Form N-SAR: measured in the EDGAR full indexes, 2018 Q2 carries **1,062 `NSAR` filings and zero `N-CEN`**, and 2018 Q3 carries 198 `NSAR` and **139 `N-CEN` + 12 `N-CEN/A`**, the earliest dated **2018-09-07**. That is the changeover, and it is the floor of this dataset. # This is the STRUCTURED one Unlike the shareholder reports it sits beside (`edgar_fund_shareholder_reports`, which is prose), an N-CEN's payload is a single `primary_doc.xml` in SEC's own `ncen` namespace - schema-validated, one element per Form item. Everything in this table and in `edgar_ncen_series` is read off that XML, never inferred. # WHY THERE ARE TWO TABLES The Form has a registrant part (Items A-C.1: who the fund complex is, its directors, its CCO, its auditor, its underwriter) and a **per-series part** (Item C: one complete block per fund, with that fund's adviser, custodian, net assets, commissions and lending revenue). The two grains are genuinely different and the fan-out is severe - EQ Advisors Trust's 2024 census (`0001752724-25-052137`) is **3.4 MB carrying 110 series blocks**, Pacific Select Fund's states 122. Flattening them into one row would either lose 109 funds or repeat the registrant 110 times. This table is the registrant row; `edgar_ncen_series` is the fund row. One collector fills both from ONE pass over ONE bronze object, exactly as `edgar_nport_filings`/`edgar_nport_holdings` do. # `total_series` IS NOT `series_reported`, AND THE DIFFERENCE IS REAL `total_series` is Item B.5 - how many series the REGISTRANT has. `series_reported` is how many Item C blocks this filing actually carries. They are usually equal (Boyar 1/1, EQ Advisors 110/110, Securian 11/11) and sometimes wildly not: **Allspring Funds Trust's `0001752724-25-052135` states `total_series = 73` and carries ONE series block**, because a registrant whose series have different fiscal year ends files a separate N-CEN per fiscal-year group and each one reports only the series in its own group. So `SELECT total_series` answers "how big is this trust" and `count(edgar_ncen_series)` answers "how many funds does this filing describe". Using either for the other is wrong by a factor of 73 on a real 2025 filing, which is why both are stored rather than one being derived. # NOT EVERY N-CEN HAS SERIES, DIRECTORS OR AN AUDITOR The Form's sections are keyed to `investment_company_type`. An **N-6 insurance separate account** (Minnesota Life Variable Life Account, `0001752724-25-051617`) files a `registrantInfo` block and nothing else - no Item C series, no `directors`, no `publicAccountants`, no `total_series`. An **N-2 closed-end fund** (Cornerstone Total Return, `0001752724-25-052190`) does carry Item C. Every column that only some company types state is therefore nullable, and a NULL here is the Form not asking, never a parse gap. See `docs/datasets/edgar_ncen_filings.md`.
How do I avoid look-ahead bias with edgar_ncen_filings?
Filter on edgar_ncen_filings.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 (SEC moves that field across the corpus; 4.88% of all EDGAR filings carry a back-dated one). N-CEN carries NO embargo - evidence class B, CONFIRMED: over 45 N-CSR-family and N-CEN submissions 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 were ACCEPTED that same calendar day (max acceptance 17:24:37 ET, inside EDGAR's 17:30 cut-off). The single exception was accepted Friday 2025-03-07 18:13:11, after the cut-off, and rolled forward to the Monday - which is dissemination working exactly as documented, not a lag. period_end is the Form's own reportEndingPeriod (Item A.2), the fiscal year the census DESCRIBES; it precedes availability by the statutory 75-day filing window and 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_ncen_filings?
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_ncen_filings". The column schema is public at https://api.obscura.trade/v1/catalog/edgar_ncen_filings.
Can I filter edgar_ncen_filings by company or symbol?
Yes. edgar_ncen_filings carries cik, the column the API's symbols filter resolves against.
How often is edgar_ncen_filings updated?
Obscura refreshes edgar_ncen_filings 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.