Obscura

Fund Securities Lending and Brokerage (N-CEN)

The per-fund detail inside each N-CEN annual census: securities lending, brokerage commissions, advisers and sub-advisers, custodians, expense waivers, lines of credit and interfund lending - plus, for index funds, tracking difference and tracking error both before and after expenses.

edgar_ncen_series - the dataset name to pass to the Obscura API.

Category Regulatory Columns 54 Refresh Every 6 hours Entity key series_id Point-in-time available_date

What one row means

One **fund** inside a Form N-CEN annual census - Item C, one block per series. This is where the census stops describing a fund complex and starts describing a FUND: this series' adviser and sub-advisers, its custodian chain, its transfer agent, its average net assets, the commissions it paid, what it earned lending securities, and whether its fees are capped. `edgar_ncen_filings` is the registrant row this hangs off. # THE FAN-OUT IS THE REASON THIS TABLE EXISTS EQ Advisors Trust's 2024 census (`0001752724-25-052137`) is **3.4 MB carrying 110 Item C blocks**; Pacific Select Fund states 122; Securian Funds Trust 11; Boyar Value Fund 1. A registrant-only table would discard 109 funds' worth of net assets and adviser identity from a single filing. # WHAT IS SCALAR AND WHAT IS JSON WAS MEASURED, NOT GUESSED Over the 110 series blocks of `0001752724-25-052137`, the per-series multiplicity of each service-provider list is: | element | count per series | modelled as | |---|---|---| | `investmentAdviser` | **1 on 110/110** | scalar columns | | `transferAgent` | **1 on 110/110** | scalar columns | | `admin` | **1 on 110/110** | scalar column | | `shareholderServicingAgent` | **1 on 110/110** | scalar column | | `subAdviser` | 0-5 | `sub_advisers` JSON | | `pricingService` | 0-5 | `pricing_services` JSON | | `custodian` | **1-50** | `custodians` JSON + count | | `broker` (Item C.16, ten largest by commission) | 0-10 | `top_brokers` JSON | | `principalTransaction` (Item C.17, ten largest) | 0-10 | `top_principal_counterparties` JSON | | `brokerDealer` (Item C.15, ALL used) | **15-115** | count + aggregate ONLY | A single global-equity series names 50 custodians because it holds a sub-custodian in every market it settles in - so "the custodian" is not a scalar fact and modelling it as one would have silently kept the first alphabetically. `brokerDealer` is the one list deliberately NOT warehoused: 115 entries × 110 series in ONE filing, across 26,240 filings, is the shape `tasks::export::copy_csv_bytes` cannot carry (it buffers a whole table as CSV in RAM, ~10-15 GB practical ceiling). Its aggregate survives intact in `aggregate_commission`, which is the Form's own total, not a sum this pipeline computed. # THE TWO AVERAGE-NET-ASSET COLUMNS ARE NOT INTERCHANGEABLE The Form asks for MONTHLY average net assets from most funds and DAILY average net assets from money market funds. Over the 110 EQ Advisors series, 109 state `monthly_avg_net_assets` and exactly 1 states `daily_avg_net_assets`. Some filers state both with `0.00` in the unused one (Boyar), so **a zero here is ambiguous between "not applicable" and "genuinely zero"** and is preserved verbatim rather than being cleaned to NULL - the filer's own zero is the record, and normalising it away would be unrecoverable. See `docs/datasets/edgar_ncen_series.md`.

One row per One row per (N-CEN submission, fund series), keyed by (accession, series_id). The row says 'in this registrant's census for this fiscal year, this series had these advisers, these custodians and this much in average net assets'. The key includes the accession rather than being (series_id, period_end) because an N-CEN/A restates a series' figures under a NEW accession and both statements must survive - collapsing them would destroy the only record that a census was corrected. A series that states no seriesId (measured on some N-2 closed-end registrants, which have exactly one fund and no series identifier) is keyed on the EMPTY STRING sentinel, because a NULL cannot sit in a composite primary key; read it as 'the registrant's only fund, unidentified'..

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_series: filing_join: available_date is the EDGAR DISSEMINATION day of the parent submission, taken from the bronze object's own day partition - the same value carried on the parent edgar_ncen_filings row, denormalised onto this table so a point-in-time query over fund economics needs no join. Never the header's FILED AS OF DATE. period_end is the census's fiscal period (Item A.2) and precedes availability by the statutory 75-day window; it is what the MEASURES on this row describe and is never an availability anchor.

Refresh cadence

Obscura refreshes edgar_ncen_series 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 - 54 columns

The full public column list for edgar_ncen_series, with the meaning of every field. The same schema is served unauthenticated at https://api.obscura.trade/v1/catalog/edgar_ncen_series.

ColumnTypeDescription
accessiontext · not nullPK part. SEC accession number of the N-CEN submission this series block came from, e.g. `0001752724-25-052137`. The foreign key into `edgar_ncen_filings`.
series_idtext · not nullPK part. SEC series identifier for the fund, `S000010926` - the same identifier `edgar_nport_filings`, `edgar_fund_series_classes` and `edgar_fund_risk_return` carry, which is what makes this table joinable to holdings and to a market ticker. The EMPTY STRING (never NULL) where the registrant states none: a NULL cannot participate in a composite primary key, and dropping the row would erase the fund.
filenametext · not nullThe registrant's SEC EDGAR Archives path for the parent submission. Denormalised from `edgar_ncen_filings` so this table stands alone as the declared `filing_join` via-column.
available_datedatePublic availability date: the parent submission's EDGAR DISSEMINATION day, from the bronze object's own day partition. The point-in-time anchor and the only date a backtest may key on.
period_enddateThe fiscal period these figures DESCRIBE - the census's `reportEndingPeriod`. Every measure on this row is an annual figure for the year ending on this date, and every one of them is stale by at least the statutory 75-day filing window when it becomes available. NEVER an availability date.
cikbigintCentral Index Key of the REGISTRANT (the trust), denormalised from the parent filing. Note this is the trust's CIK, not the series' - SEC assigns no CIK to a series, which is why `series_id` exists.
fund_nametextThe fund's name as the Form states it (`mgmtInvFundName`), e.g. `Allspring Managed Account CoreBuilder Shares Series M`. The filer's spelling, which is not necessarily the prospectus name.
fund_leitextThe SERIES' own Legal Entity Identifier (`mgmtInvLei`), distinct from the registrant's. Funds within one trust each carry their own LEI, so this is the identifier that joins a fund to non-SEC reference data. NULL where the filer states `N/A`.
is_first_filing_by_fundbooleanTRUE when this is the FUND's first appearance on an N-CEN (`isFirstFilingByFund`) - a fund launch, stated by the filer rather than inferred from an absence.
is_fund_liquidatedbooleanTRUE when the fund was LIQUIDATED during the reporting period (`isFundLiquidated`). Together with `num_terminated_class` this is the fund-death record, and it is why a naive "the series stopped appearing" heuristic is unnecessary here.
num_authorized_classintegerHow many share classes the fund is AUTHORIZED to issue (`numAuthorizedClass`).
num_added_classintegerHow many share classes were ADDED during the period (`numAddedClass`).
num_terminated_classintegerHow many share classes were TERMINATED during the period (`numTerminatedClass`). Non-zero is a real share-class closure, which usually precedes a fee-structure change or a fund merger.
share_classesjsonb · not nullJSON array of the fund's share classes with outstanding shares as `[{"class_id":"C000030254","class_name":…,"ticker":"BOYAX"}]`. **The ticker is frequently absent and that is information, not a gap** - the 110 EQ Advisors series carry 208 classes and ZERO tickers, because insurance-dedicated classes are not exchange-traded. `edgar_fund_series_classes` is the dedicated crosswalk when a ticker is what you need.
fund_typesjsonb · not nullJSON array of the fund-type classifications the filer selected, e.g. `["Money Market Fund"]`, `["Index Fund"]`; `[]` where none applies. The Form states these in THREE places and all three are unioned: a wrapped `<fundTypes><fundType>`, a BARE `<fundType>` directly on the series block, and an `indexFundInfo/@fundType` ATTRIBUTE. Securian's `0001752724-25-052131` uses all three shapes across its own 11 series. The filer's `N/A` placeholder - 8 of Securian's 9 - is normalised AWAY rather than stored, so `fund_types @> '["N/A"]'` cannot match a non-answer as though it were a category.
is_index_fund_affiliatedbooleanTRUE when the fund is an INDEX fund whose target index is AFFILIATED with the adviser (`indexFundInfo/isIndexFundAffiliated`) - a self-indexing ETF, where the same firm builds the benchmark and manages the fund tracking it. NULL when the fund is not an index fund at all, which is the majority.
is_index_fund_exclusivebooleanTRUE when the fund has EXCLUSIVE rights to the index it tracks (`indexFundInfo/isIndexFundExclusive`) - i.e. no competitor may launch a fund on the same benchmark. NULL for a non-index fund.
index_tracking_diff_before_expensenumeric**TRACKING DIFFERENCE BEFORE EXPENSES**, in percent: the fund's annual return minus its target index's return, gross of the fund's own fees (`indexFundReturnDiffBeforeExpense`). Negative means the fund trailed its index before it charged anything - i.e. the shortfall is sampling, cash drag or transaction costs rather than fees. NULL for a non-index fund. Together with the after-expense figure this is the only per-fund, per-year tracking record SEC publishes anywhere.
index_tracking_diff_after_expensenumeric**TRACKING DIFFERENCE AFTER EXPENSES**, in percent (`indexFundReturnDiffAfterExpense`) - what the shareholder actually experienced against the benchmark. The gap between this and `index_tracking_diff_before_expense` is the fee drag, measured rather than quoted: Securian's SFT Index 500 Fund reports 0.00 before and −0.35 after. NULL for a non-index fund.
index_tracking_stdev_before_expensenumeric**TRACKING ERROR BEFORE EXPENSES**: the standard deviation of the DAILY return difference against the index, in percent (`indexFundReturnDailyStdevBeforeExpense`). Difference measures the level of the miss; this measures its volatility, and a fund can have near-zero tracking difference with large tracking error. NULL for a non-index fund.
index_tracking_stdev_after_expensenumeric**TRACKING ERROR AFTER EXPENSES**: the same daily standard deviation net of fund expenses (`indexFundReturnDailyStdevAfterExpense`), in percent. NULL for a non-index fund.
is_non_diversifiedbooleanTRUE when the fund is NON-DIVERSIFIED under Section 5(b)(2) (`isNonDiversifiedCompany`) - i.e. it may concentrate. A structural risk attribute stated annually.
is_foreign_subsidiarybooleanTRUE when the fund invests through a FOREIGN SUBSIDIARY (`isForeignSubsidiary`), typically a Cayman subsidiary used for commodity exposure. The structure that makes a fund's stated holdings incomplete on their own.
is_securities_lending_authorizedbooleanTRUE when the fund is AUTHORISED to lend portfolio securities (`isFundSecuritiesLending`). Distinct from `did_lend_securities`, which says whether it actually did - 27 of 110 EQ Advisors series name no securities-lending agent at all.
did_lend_securitiesbooleanTRUE when the fund ACTUALLY lent securities during the period (`didFundLendSecurities`). The pair with `is_securities_lending_authorized` separates permission from practice; conflating them overstates lending activity across the corpus.
avg_securities_on_loan_valuenumericAverage value of portfolio securities ON LOAN over the period (`avgPortfolioSecuritiesValue`), in USD. The denominator for a securities-lending yield; `net_income_securities_lending` is the numerator.
net_income_securities_lendingnumericThe fund's NET INCOME from securities lending for the period (`netIncomeSecuritiesLending`), in USD - after the lending agent's split. One of the few places a fund's lending revenue is stated as a number rather than buried in an expense ratio.
monthly_avg_net_assetsnumericThe fund's MONTHLY average net assets for the period (`mnthlyAvgNetAssets`), in USD. The size measure for a non-money-market fund - 109 of 110 EQ Advisors series state this one. **A zero is ambiguous**: some filers state `0.00` here when they answered in `daily_avg_net_assets` instead, so read both columns before treating a zero as a size.
daily_avg_net_assetsnumericThe fund's DAILY average net assets for the period (`dailyAvgNetAssets`), in USD - what money market funds answer instead of the monthly figure. Exactly 1 of the 110 EQ Advisors series states it. Same zero ambiguity as `monthly_avg_net_assets`, in the other direction.
aggregate_commissionnumericTOTAL brokerage commissions the fund paid during the period (`aggregateCommission`), in USD. **The Form's own total across ALL broker-dealers**, not a sum over the stored `top_brokers` - which is why the unbounded Item C.15 list can be left unwarehoused without losing the aggregate.
aggregate_principal_transactionsnumericTOTAL value of PRINCIPAL transactions (purchases and sales combined) the fund transacted during the period (`principalAggregatePurchase`), in USD. The Form's own total; `top_principal_counterparties` names only the ten largest counterparties behind it.
broker_dealer_countinteger · not nullHow many broker-dealers the fund used in total (Item C.15, `brokerDealer` entries). **The list itself is deliberately not stored** - measured 15 to 115 entries per series, which across 110 series in one filing and 26,240 filings would exceed the export path's practical table ceiling. This count and `aggregate_commission` preserve what the list aggregates to.
adviser_nametextThe fund's investment adviser NAME (Item C.7). A scalar because it measured exactly 1 per series on 110 of 110 EQ Advisors series - a fund has one adviser and delegates to sub-advisers, which are in `sub_advisers`.
adviser_file_numbertextThe adviser's Investment Advisers Act file number, e.g. `801-19283`.
adviser_crdtextThe adviser's CRD number, e.g. `000105255` - the join key into FINRA/IAPD adviser data. Text, not an integer: leading zeros are significant and the Form permits `N/A`, normalised to NULL.
adviser_leitextThe adviser's Legal Entity Identifier. NULL where the filer states `N/A`, which is the majority - advisers state a CRD far more often than an LEI.
is_adviser_hiredbooleanTRUE when the adviser was HIRED during the reporting period (`isInvestmentAdviserHired`) - a management change, stated rather than inferred from a name diff between years.
sub_advisersjsonb · not nullJSON array of SUB-advisers as `[{"name":…,"file_number":…,"crd":…,"lei":…,"is_affiliated":…,"is_hired":…}]`; `[]` where none. Measured 0-5 per series (23 of 110 EQ Advisors series have none), which is why this is an array while `adviser_name` is a scalar. The sub-adviser is who actually picks the securities in a manager-of-managers structure.
transfer_agent_nametextThe fund's transfer agent NAME (Item C.9) - 1 per series on 110 of 110 measured, hence a scalar.
administrator_nametextThe fund's ADMINISTRATOR name (Item C.12) - 1 per series on 110 of 110 measured.
shareholder_servicing_agent_nametextThe fund's shareholder servicing agent NAME (Item C.11) - 1 per series on 110 of 110 measured.
custodiansjsonb · not nullJSON array of custodians as `[{"name":…,"lei":…,"state":…,"country":…,"is_affiliated":…,"is_sub_custodian":…,"custody_type":…}]`. **Measured 1 to 50 per series** - a global-equity fund names a sub-custodian in every settlement market it touches - which is exactly why this is not a scalar column. `custodian_count` is its length.
custodian_countinteger · not nullHow many custodians the fund names. Measured 1-50 per series; the long tail is sub-custodian networks and is itself a proxy for how many markets the fund settles in.
pricing_servicesjsonb · not nullJSON array of pricing/valuation services as `[{"name":…,"lei":…,"state":…,"country":…,"is_affiliated":…}]`; `[]` where none. Measured 0-5 per series. Which vendor marks a fund's book is a real dependency and the Form is the only place it is stated.
top_brokersjsonb · not nullJSON array of the TEN broker-dealers that received the largest brokerage commissions from this fund (Item C.16) as `[{"name":…,"file_number":…,"crd":…,"lei":…,"state":…,"country":…,"gross_commission":…}]`. Bounded at ten by the Form itself - measured 0-10 per series - which is why the whole list is stored while the unbounded Item C.15 list is not.
top_principal_counterpartiesjsonb · not nullJSON array of the TEN counterparties with the largest PRINCIPAL transactions (Item C.17) as `[{"name":…,"file_number":…,"crd":…,"lei":…,"state":…,"country":…,"total_purchase_sale":…}]`. Bounded at ten by the Form; measured 0-10 per series. This is the dealer relationship that a commission-only view misses entirely, because a principal trade pays no commission.
is_expense_limitation_in_placebooleanTRUE when an EXPENSE LIMITATION (fee cap) was in place during the period (`isExpenseLimitationInPlace`). The stated-rather-than-derived version of "is this fund's headline expense ratio subsidised".
is_expense_reduced_or_waivedbooleanTRUE when expenses were actually REDUCED OR WAIVED during the period (`isExpenseReducedOrWaived`). The pair with `is_expense_limitation_in_place` separates a cap that exists from a cap that bound.
is_fees_waived_recoupablebooleanTRUE when waived FEES are RECOUPABLE by the adviser in later periods (`isFeesWaivedRecoupable`) - i.e. today's low expense ratio carries a future claw-back against the fund. A materially different economic position from a permanent waiver, and the Form distinguishes them.
has_line_of_creditbooleanTRUE when the fund had a LINE OF CREDIT during the period (`hasLineOfCredit`).
is_interfund_lendingbooleanTRUE when the fund LENT to affiliated funds under an interfund lending order (`isInterfundLending`).
is_interfund_borrowingbooleanTRUE when the fund BORROWED from affiliated funds (`isInterfundBorrowing`). Together with `is_interfund_lending` this is the intra-complex liquidity network, and the two directions are separate columns because a fund can do either, both or neither.
is_swing_pricingbooleanTRUE when the fund applied SWING PRICING during the period (`isSwingPricing`). Very rarely TRUE in US funds and therefore worth finding when it is.
relied_on_rulesjsonb · not nullJSON array of the 1940 Act rules the fund states it relied on (`relyOnRuleType`), e.g. `["Rule 32a-4 (17 CFR 270.32a-4)"]` - verbatim rule citations as the filer selected them, not normalised to rule numbers, because the Form's own strings are the controlled vocabulary here.

Access edgar_ncen_series

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_series",
    symbols=["NVDA", "AAPL"],
    start="2024-01-01",
)

Create a free account Browse all 122 datasets

Frequently asked questions

What is in the edgar_ncen_series dataset?

The per-fund detail inside each N-CEN annual census: securities lending, brokerage commissions, advisers and sub-advisers, custodians, expense waivers, lines of credit and interfund lending - plus, for index funds, tracking difference and tracking error both before and after expenses. One **fund** inside a Form N-CEN annual census - Item C, one block per series. This is where the census stops describing a fund complex and starts describing a FUND: this series' adviser and sub-advisers, its custodian chain, its transfer agent, its average net assets, the commissions it paid, what it earned lending securities, and whether its fees are capped. `edgar_ncen_filings` is the registrant row this hangs off. # THE FAN-OUT IS THE REASON THIS TABLE EXISTS EQ Advisors Trust's 2024 census (`0001752724-25-052137`) is **3.4 MB carrying 110 Item C blocks**; Pacific Select Fund states 122; Securian Funds Trust 11; Boyar Value Fund 1. A registrant-only table would discard 109 funds' worth of net assets and adviser identity from a single filing. # WHAT IS SCALAR AND WHAT IS JSON WAS MEASURED, NOT GUESSED Over the 110 series blocks of `0001752724-25-052137`, the per-series multiplicity of each service-provider list is: | element | count per series | modelled as | |---|---|---| | `investmentAdviser` | **1 on 110/110** | scalar columns | | `transferAgent` | **1 on 110/110** | scalar columns | | `admin` | **1 on 110/110** | scalar column | | `shareholderServicingAgent` | **1 on 110/110** | scalar column | | `subAdviser` | 0-5 | `sub_advisers` JSON | | `pricingService` | 0-5 | `pricing_services` JSON | | `custodian` | **1-50** | `custodians` JSON + count | | `broker` (Item C.16, ten largest by commission) | 0-10 | `top_brokers` JSON | | `principalTransaction` (Item C.17, ten largest) | 0-10 | `top_principal_counterparties` JSON | | `brokerDealer` (Item C.15, ALL used) | **15-115** | count + aggregate ONLY | A single global-equity series names 50 custodians because it holds a sub-custodian in every market it settles in - so "the custodian" is not a scalar fact and modelling it as one would have silently kept the first alphabetically. `brokerDealer` is the one list deliberately NOT warehoused: 115 entries × 110 series in ONE filing, across 26,240 filings, is the shape `tasks::export::copy_csv_bytes` cannot carry (it buffers a whole table as CSV in RAM, ~10-15 GB practical ceiling). Its aggregate survives intact in `aggregate_commission`, which is the Form's own total, not a sum this pipeline computed. # THE TWO AVERAGE-NET-ASSET COLUMNS ARE NOT INTERCHANGEABLE The Form asks for MONTHLY average net assets from most funds and DAILY average net assets from money market funds. Over the 110 EQ Advisors series, 109 state `monthly_avg_net_assets` and exactly 1 states `daily_avg_net_assets`. Some filers state both with `0.00` in the unused one (Boyar), so **a zero here is ambiguous between "not applicable" and "genuinely zero"** and is preserved verbatim rather than being cleaned to NULL - the filer's own zero is the record, and normalising it away would be unrecoverable. See `docs/datasets/edgar_ncen_series.md`.

How do I avoid look-ahead bias with edgar_ncen_series?

Filter on edgar_ncen_series.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 of the parent submission, taken from the bronze object's own day partition - the same value carried on the parent edgar_ncen_filings row, denormalised onto this table so a point-in-time query over fund economics needs no join. Never the header's FILED AS OF DATE. period_end is the census's fiscal period (Item A.2) and precedes availability by the statutory 75-day window; it is what the MEASURES on this row describe 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_series?

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_series". The column schema is public at https://api.obscura.trade/v1/catalog/edgar_ncen_series.

Can I filter edgar_ncen_series by company or symbol?

Yes. edgar_ncen_series carries series_id, the column the API's symbols filter resolves against.

How often is edgar_ncen_series updated?

Obscura refreshes edgar_ncen_series 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.

Related datasets

CFTC Commitments of Traders (COT)The CFTC's weekly Commitments of Traders report: how commercial, non-commercial and small traders are positioned in each… EPA Environmental Enforcement ActionsEnvironmental enforcement actions and penalties from the EPA's ECHO database. One row per case, with the facility, the s… EPA Regulated Facilities and ComplianceEPA-regulated facilities and their compliance history, from ECHO: one row per facility, with location, industry, permit … 13F Filing MetadataMetadata for every 13F report, the quarterly filing where large institutional managers list their U.S. equity holdings. … 13F Institutional HoldingsThe line-item positions inside each 13F: which manager held which security, and how much, each quarter. Deep history is … 13F Other Included ManagersWhich other manager reports a fund's 13F holdings, from the 13F-NT notices managers file when their positions appear on … SEC 8-K Item Codes and Material EventsThe item numbers reported on each 8-K (5.02 officer changes, 2.01 acquisitions, 1.01 material agreements, and so on), so… Asset-Backed Securities Distributions (Form 10-D)Form 10-D distribution reports for asset-backed securities: which trust paid out, for which distribution period, its dep…