Obscura

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.

Category Regulatory Columns 37 Refresh Every 6 hours Entity key cik Point-in-time available_date

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.

ColumnTypeDescription
accessiontext · not nullPK 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_ordinalinteger · not nullPK 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.
filenametext · not nullThe 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_datedatePublic 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_enddateThe 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_attimestamp with time zoneWhen 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_ofdateSEC'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_ondateDate 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_typetext · not nullThe 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_amendmentboolean · not nullTRUE 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_versiontextThe 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_salesnumeric**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_redemptionsnumericAggregate 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_redemptionsnumericRedemptions 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_availablenumericTotal 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_basisnumericThe 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_forwardnumericRedemption 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_ratenumericSEC'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_duenumericRegistration 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_duenumericInterest 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_interestnumericRegistration fee plus any late interest, in USD - the total the filer actually remitted.
securities_deductednumericAmount 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_unsoldnumericShares 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_latebooleanThe 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_filingbooleanThe 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".
seriesjsonb · not nullJSON 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_countinteger · not nullNumber 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_modetext · not nullHOW `<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_idtextThe 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_nametextRegistrant name as stated in the form's item 1 (`<nameOfIssuer>`), which is the fund complex or trust, not the individual fund.
cikbigintCentral Index Key of the registrant, from `<filer><issuerCredentials><cik>` with leading zeros stripped, falling back to the SGML header.
sec_file_numbertextThe 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_numbertextThe 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_typetextThe 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_statetextRegistrant's state from item 1's address (`<addressOfIssuer><state>`).
issuer_countrytextRegistrant's country from item 1's address (`<addressOfIssuer><country>`), an EDGAR country code (`X1` = United States).
explanatory_notestextThe 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.

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…