Fund Share Sales and Redemptions (Rule 24F-2)
Annual gross share sales and redemptions for US registered funds, as reported to the SEC under Rule 24f-2. A gross flow series: the sales and the redemptions behind a fund's net change, neither of which is recoverable from holdings or net assets. XML era only: primary_doc.xml begins around 2016, and older 24F-2NT filings are a plain-text rendering of the paper form, recorded as unparsed rather than half-stored.
edgar_fund_share_sales - the dataset name to pass to the Obscura API.
What one row means
One **Rule 24f-2 annual filing block** - a US registered fund's declaration of the GROSS share sales and GROSS redemptions it transacted over a fiscal year, filed on Form `24F-2NT` so the registration fee can be computed. 71,196 filings since 2015. It is the only public statement of a fund's gross two-way flow: `edgar_nport_filings` gives holdings and net assets, from which the NET change is recoverable, but the gross sales and gross redemptions behind that net are not - a fund with $1.0 bn in and $1.2 bn out and a fund with $10 m in and $210 m out report the same net, and only this form separates them. # What a row IS, precisely - and the mistake it is shaped to prevent One row per `<annualFilingInfo>` BLOCK, not per fund and not per filing. **The amounts belong to the block, and a block may cover several funds collectively.** Accession `0000940400-24-000242` (Legg Mason Partners Income Trust) reports $1,002,652,789 of sales against a `<item2>` that lists FOUR series. That is one billion dollars across four funds - not four funds' worth of one billion each. Fanning the block out to one row per series would quadruple the reported flow with nothing downstream able to detect it, which is why `series` is a JSON child list on the row and `series_count` is stored beside it: `series_count > 1` is the reader's warning that any per-fund figure they compute is an ALLOCATION they chose, not a measurement the filer made. **A filing may carry several blocks.** Accession `0000102816-26-000002` is one submission with FIVE `<annualFilingInfo>` blocks, one per share class of BNY Mellon Research Growth Fund, each with its own amounts ($92.3 m, $117.1 m, $0.9 m, $61.5 m, $11.3 m - $283.0 m in total). Keying the row on the filing alone would keep the last block and silently discard $190.7 m of it, so the key is `(accession, block_ordinal)`. Together those two facts are the whole grain: **the block is neither the fund nor the filing, and it is the only level at which the amounts are true.** See `docs/datasets/edgar_fund_share_sales.md`.
One row per One row per <annualFilingInfo> BLOCK of a Rule 24f-2 notice, keyed by (accession, block_ordinal). A block is one registrant's report for one fiscal year covering one or more series/classes COLLECTIVELY - the item5 amounts are the block's, never any single series', so the covered series are a JSON child list (series) and are NOT fanned out into rows. MEASURED both ways: 0000940400-24-000242 is ONE block covering FOUR series ($1.0bn of sales in total, not per fund), and 0000102816-26-000002 is ONE filing carrying FIVE blocks ($283.0m in total across five share classes) - so the row is neither per fund nor per filing. The key is the accession rather than the archive path because the daily index is not a source of uniqueness: master.20260511.idx carries accession 0001104659-26-058380 on two identical rows..
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_share_sales: 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 back-dates it on 4.88% of filings). period_end is the fund's FISCAL YEAR END and is systematically EARLIER - Rule 24f-2 allows 90 days, and the measured lags are 44 days (0001445546-24-003890: FY ended 2024-04-10, disseminated 2024-05-24) and 71 days (0000940400-24-000242: FY ended 2024-02-29, disseminated 2024-05-10). A late filing (is_late) may lag much further. Evidence class A (the payload states its own fiscal year end) + B (dissemination day from the feed partition), CONFIRMED.
Refresh cadence
Obscura refreshes edgar_fund_share_sales 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 - 37 columns
The full public column list for edgar_fund_share_sales, with the meaning of every field. The same
schema is served unauthenticated at https://api.obscura.trade/v1/catalog/edgar_fund_share_sales.
| Column | Type | Description |
|---|---|---|
| accession | text · not null | PK part 1. SEC accession number of the notice, e.g. `0000940400-24-000242`. The key is the accession and not the archive path: the daily index is not a source of uniqueness (`master.20260511.idx` lists accession `0001104659-26-058380` twice, byte-identically). |
| block_ordinal | integer · not null | PK part 2. Zero-based position of this `<annualFilingInfo>` within `<annualFilings>`. `0` on a single-block notice, which is the common case; `0..4` on `0000102816-26-000002`, where one submission reports five share classes as five blocks with five different amount sets. Keying on the filing alone would keep only the last of them. |
| filename | text · not null | The registrant's SEC EDGAR Archives path for this notice (`edgar/data/{cik}/{accession}.txt`), derived from the payload's own filer CIK 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. It is NOT the fiscal year end (`period_end`), which is up to 90 days earlier, and NOT the signature date (`signed_on`), which differed from dissemination by two days on `0000940400-24-000242`. |
| period_end | date | The fund's FISCAL YEAR END - the last day of the period whose sales and redemptions this block reports, from `<lastDayOfFiscalYear>` (`MM/DD/YYYY`). Corroborated by the SGML header's `CONFORMED PERIOD OF REPORT`. There is deliberately no `period_start`: the form does not state one, and deriving it as `period_end - 1 year` would be wrong for a fund's first partial year. |
| accepted_at | timestamp with time zone | When SEC ACCEPTED the submission (`<ACCEPTANCE-DATETIME>`), US-Eastern wall clock stored under a UTC type - the standing EDGAR convention in this repo. Provenance, never an availability date: an after-hours acceptance is disseminated the next morning. NULL on a row ingested from the dissemination feed, whose PDS 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 - SEC both back-dates it and rolls it forward past an after-hours acceptance. |
| signed_on | date | Date the officer signed the notice (`<signatureDate>`, `MM/DD/YYYY`). Provenance only: a notice can be signed and disseminated on different days (`0000940400-24-000242` was signed 2024-05-08 and disseminated 2024-05-10), so a signature is not a publication and this is never an availability date. |
| form_type | text · not null | The submission's form type: `24F-2NT` or `24F-2NT/A`. An amendment is kept as its OWN row rather than overwriting the original, because a restatement of a fund's annual flow is itself the fact of interest. |
| is_amendment | boolean · not null | TRUE when `form_type` is an amendment (`24F-2NT/A`). A second row under the same `(cik, period_end)` is either this, or a fund complex filing two notices in one day (`m funds Trust` filed accessions `0001214659-24-008745` and `-008746` on 2024-05-10), which is why `(cik, period_end)` is indexed but NOT unique. |
| schema_version | text | The payload's `<schemaVersion>` - `X0101` or `X0102`. Load-bearing PROVENANCE, not decoration: X0102 RENUMBERED the form's items, moving `interestDue` from item7 to item6, `totalOfRegistrationFeePlusAnyInterestDue` from item8 to item7 and `explanatoryNotes` from item9 to item8, and dropping the Rule 24e-2 prepaid-shares item entirely. The parser therefore keys on LEAF ELEMENT NAMES and never on item numbers; this column records which numbering the source used so the decision is auditable. NULL on a payload that states no version. |
| gross_sales | numeric | **Aggregate sale price of securities sold during the fiscal year**, in USD, from `<aggregateSalePriceOfSecuritiesSold>` (Rule 24f-2 item 5(i)). The GROSS inflow - the headline measure of this dataset, and the number that is not recoverable from any holdings-based source. Belongs to the whole block: on a block covering four series it is the four funds' combined sales. |
| gross_redemptions | numeric | Aggregate price of securities redeemed or repurchased during the fiscal year, in USD (item 5(ii)). The GROSS outflow, on the same collective basis as `gross_sales`. |
| prior_year_redemptions | numeric | Redemptions from PRIOR fiscal years (ending no earlier than 1995-10-11) not yet used to reduce fees, in USD (item 5(iii)). A carried-forward fee credit balance, not a flow of the reported year - do not add it to `gross_redemptions` to get a period outflow. |
| redemption_credits_available | numeric | Total redemption credits usable against this year's fee (item 5(iv)) - the sum of `gross_redemptions` and `prior_year_redemptions` as the filer states it. |
| net_sales_fee_basis | numeric | The FEE-COMPUTATION BASIS from `<netSales>` (item 5(v)). **It is NOT `gross_sales - gross_redemptions` and it is NOT a net flow.** It is `max(0, gross_sales - redemption_credits_available)` - FLOORED AT ZERO, and verified as exactly that on all six probed XML filings. `0000940400-24-000242` reports `0.00` here against $1.0 bn of sales and $6.8 bn of available credits. The column is named for what it is so that a reader cannot mistake it for flow; the net flow they want is `gross_sales - gross_redemptions`, which they must compute themselves. |
| redemption_credits_carried_forward | numeric | Redemption credits carried into future fiscal years (item 5(vi)) - the other side of the same floor, `min(0, gross_sales - redemption_credits_available)`, so it is NEGATIVE or zero. It arrives in ACCOUNTING PARENTHESES (`(5783013314.00)`, `(2793157)`) and is decoded as a negative: the sign is confirmed by the form's own arithmetic on every fixture that carries one. |
| fee_rate | numeric | SEC's registration-fee RATE for the fiscal year (item 5(vii)), e.g. `0.0001476` for FY2024 and `0.0001381` for FY2026. Constant across all filers in a fee year, which makes it a free integrity check on both the parse and the fee arithmetic. |
| registration_fee_due | numeric | Registration fee owed on this block, in USD (item 5(viii)) - `net_sales_fee_basis * fee_rate`, and zero whenever the fee basis is floored to zero. |
| interest_due | numeric | Interest owed for a late filing, in USD. `> 0` is independent corroboration of `is_late`: `0001214659-24-008745` declares itself late and owes $0.48. |
| total_fee_and_interest | numeric | Registration fee plus any late interest, in USD - the total the filer actually remitted. |
| securities_deducted | numeric | Amount of securities deducted under Rule 24e-2 as it stood before 1995-10-11, when the filer reduced item 5(i) by a prepaid amount. Present only on `X0101` payloads: `X0102` dropped this item, so a NULL on a modern filing is a fact about the schema and not a decoder gap. |
| units_remaining_unsold | numeric | Shares or other units registered under the pre-1995 Rule 24e-2 that remain UNSOLD at fiscal year end and stay available to the issuer. Same `X0101`-only caveat as `securities_deducted`. |
| is_late | boolean | The filer's own assertion that the notice is LATE - filed more than 90 days after fiscal year end (`<isThisFormBeingFiledLate>`). NULL means the filing does not state it, which is common on the UIT shape; NULL is "not stated", NEVER "false". |
| is_final_filing | boolean | The filer's assertion that this is the LAST time it will file this form (`<isThisTheLastTimeIssuerFilingThisForm>`) - a fund winding down, deregistering or merging away. A genuine terminal-event signal, and the last flow observation that fund will ever publish. NULL is "not stated". |
| series | jsonb · not null | JSON array of the series/classes this block covers, as `[{series_id, series_name, class_id, class_name, include_all_classes}]` decoded from `<item2>`. **The amounts above belong to the block as a whole and to no single element of this array** - a consumer wanting per-fund flow must state their own allocation assumption, in the open. Empty when the filer checked the "all series/classes" box instead of listing them, which `series_reporting_mode` distinguishes from a parse failure. |
| series_count | integer · not null | Number of entries in `series`. `1` on a single-fund block, `4` on `0000940400-24-000242`, `0` when the filer checked the all-series box. **`> 1` is the signal that the amounts are COLLECTIVE** and that any per-fund figure derived from this row is an allocation rather than a measurement. |
| series_reporting_mode | text · not null | HOW `<item2>` named what the block covers, which is the only thing that makes an empty `series` list interpretable. One of: `enumerated_series` (`rptSeriesClassInfo`, series listed with IDs), `enumerated_classes` (`annualClassInfo`, classes listed with IDs), `named_classes` (`annualClassNameInfo`, names only and no joinable identifier - the unit-investment-trust shape), `all_series` (`rptIncludeAllSeriesFlag`, the "check the box, do not list" case covering every series the registrant has), `all_classes` (`rptIncludeAllFlag`, likewise), or `unstated`. All five shapes were observed live; the `all_*` modes were 6 of 17 probed filings, so a bare `series_count = 0` would have been ambiguous on a third of the corpus. |
| attributed_to_id | text | The series or class ID the FILER attributes this block's amounts to (`<item5><seriesOrClassId>`), e.g. `C000000108`. Introduced by schema `X0102`. **When it is present, per-fund flow is a MEASUREMENT** - the filer has narrowed the block to exactly one series or class, as on the five blocks of `0000102816-26-000002`. When it is NULL the amounts are collective over `series` and any per-fund split is the consumer's own assumption. |
| issuer_name | text | Registrant name as stated in the form's item 1 (`<nameOfIssuer>`), which is the fund complex or trust, not the individual fund. |
| cik | bigint | Central Index Key of the registrant, from `<filer><issuerCredentials><cik>` with leading zeros stripped, falling back to the SGML header. |
| sec_file_number | text | The registrant's Securities Act registration number, e.g. `333-275333` or `002-96408`. From `<filer><fileNumber>`, falling back to item 3's first `<securitiesActFileNo>` - the Legg Mason notice states it only in item 3. |
| investment_company_file_number | text | The registrant's INVESTMENT COMPANY ACT file number, e.g. `811-04254` (item 3). **The stable identifier for a fund complex** - it survives the name changes and Securities Act re-registrations that make `sec_file_number` unreliable over time - and the join to `edgar_nport_filings`. |
| investment_company_type | text | The registrant's investment-company form type from `<investmentCompanyType>`: `N-1A` (open-end mutual fund/ETF), `S-6` (unit investment trust), `N-2` (closed-end), `N-4` (variable annuity separate account), … It separates fund families whose flow dynamics are unrelated - a UIT's "sales" are a one-off deposit, an open-end fund's are continuous - so pooling them without this column produces a meaningless aggregate. |
| issuer_state | text | Registrant's state from item 1's address (`<addressOfIssuer><state>`). |
| issuer_country | text | Registrant's country from item 1's address (`<addressOfIssuer><country>`), an EDGAR country code (`X1` = United States). |
| explanatory_notes | text | The filer's free-text qualification (`<explanatoryNotes>`), `None` when there is nothing to add. Short, and worth keeping because it is where a restatement explains itself - the amendment `0001104659-26-058381` says "This is an amended filing and was not filed late." |
Access edgar_fund_share_sales
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_share_sales",
symbols=["NVDA", "AAPL"],
start="2024-01-01",
)
Create a free account Browse all 122 datasets
Frequently asked questions
What is in the edgar_fund_share_sales dataset?
Annual gross share sales and redemptions for US registered funds, as reported to the SEC under Rule 24f-2. A gross flow series: the sales and the redemptions behind a fund's net change, neither of which is recoverable from holdings or net assets. XML era only: primary_doc.xml begins around 2016, and older 24F-2NT filings are a plain-text rendering of the paper form, recorded as unparsed rather than half-stored. One **Rule 24f-2 annual filing block** - a US registered fund's declaration of the GROSS share sales and GROSS redemptions it transacted over a fiscal year, filed on Form `24F-2NT` so the registration fee can be computed. 71,196 filings since 2015. It is the only public statement of a fund's gross two-way flow: `edgar_nport_filings` gives holdings and net assets, from which the NET change is recoverable, but the gross sales and gross redemptions behind that net are not - a fund with $1.0 bn in and $1.2 bn out and a fund with $10 m in and $210 m out report the same net, and only this form separates them. # What a row IS, precisely - and the mistake it is shaped to prevent One row per `<annualFilingInfo>` BLOCK, not per fund and not per filing. **The amounts belong to the block, and a block may cover several funds collectively.** Accession `0000940400-24-000242` (Legg Mason Partners Income Trust) reports $1,002,652,789 of sales against a `<item2>` that lists FOUR series. That is one billion dollars across four funds - not four funds' worth of one billion each. Fanning the block out to one row per series would quadruple the reported flow with nothing downstream able to detect it, which is why `series` is a JSON child list on the row and `series_count` is stored beside it: `series_count > 1` is the reader's warning that any per-fund figure they compute is an ALLOCATION they chose, not a measurement the filer made. **A filing may carry several blocks.** Accession `0000102816-26-000002` is one submission with FIVE `<annualFilingInfo>` blocks, one per share class of BNY Mellon Research Growth Fund, each with its own amounts ($92.3 m, $117.1 m, $0.9 m, $61.5 m, $11.3 m - $283.0 m in total). Keying the row on the filing alone would keep the last block and silently discard $190.7 m of it, so the key is `(accession, block_ordinal)`. Together those two facts are the whole grain: **the block is neither the fund nor the filing, and it is the only level at which the amounts are true.** See `docs/datasets/edgar_fund_share_sales.md`.
How do I avoid look-ahead bias with edgar_fund_share_sales?
Filter on edgar_fund_share_sales.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 back-dates it on 4.88% of filings). period_end is the fund's FISCAL YEAR END and is systematically EARLIER - Rule 24f-2 allows 90 days, and the measured lags are 44 days (0001445546-24-003890: FY ended 2024-04-10, disseminated 2024-05-24) and 71 days (0000940400-24-000242: FY ended 2024-02-29, disseminated 2024-05-10). A late filing (is_late) may lag much further. Evidence class A (the payload states its own fiscal year end) + B (dissemination day from the feed partition), CONFIRMED. 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_share_sales?
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_share_sales". The column schema is public at https://api.obscura.trade/v1/catalog/edgar_fund_share_sales.
Can I filter edgar_fund_share_sales by company or symbol?
Yes. edgar_fund_share_sales carries cik, the column the API's symbols filter resolves against.
How often is edgar_fund_share_sales updated?
Obscura refreshes edgar_fund_share_sales 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.