Money Market Fund Reports (N-MFP)
Form N-MFP money-market fund reports, one row per fund per month: net assets, shares outstanding, stable share price, seven-day yield, weighted-average maturity and life, and the Rule 2a-7 daily and weekly liquid-asset ratios that decide whether a fund can meet redemptions. Coverage begins 2016-05 with N-MFP1/2/3; the earlier N-MFP generation is parsed and schema-complete but its presence in the daily dissemination feed is unresolved.
edgar_mmf_filings - the dataset name to pass to the Obscura API.
What one row means
One **money-market fund series' monthly portfolio report** - the cover of an SEC Form N-MFP filing: which series, for which month, its net assets, share count, stable share price, seven-day yield, weighted-average maturity and life, and the daily/weekly liquid-asset ratios that Rule 2a-7 actually constrains. This is the fund-level companion to `edgar_mmf_holdings`. Both are parsed from the SAME submission object, and the split is the same one N-PORT uses: one cover row, N position rows. # FOUR GENERATIONS, ONE TABLE - and the generation is read from the DOCUMENT SEC has rewritten this form's XML three times, and **the vocabularies do not merely add fields, they RENAME the same concept**: | | `N-MFP` | `N-MFP1` | `N-MFP2` | `N-MFP3` | |---|---|---|---|---| | first seen | 2010-11 | 2016-05 | 2016-10 | 2024-07 | | root | bare `edgarSubmission`, no `formData` | `formData` | `formData` | `formData` | | positions | `scheduleOfPortfolioSecuritiesList/scheduleOfPortfolioSecurities` | `scheduleOfPortfolioSecuritiesInfo` | same | same | | net assets | `AssetsNet` | `netAssetOfSeries` | same | same | | WAM | `dollarWeightedAveragePortfolioMaturity` | `averagePortfolioMaturity` | same | same | | liquidity | *not reported* | 5 × `fridayWeek{1..5}` | 4 × `fridayDay` + 5 × `fridayWeek` | 21 × `liquidAssetsDetails` | | category | `InvestmentTypeDomain` | `moneyMarketFundCategory` | same | same | **The generation CANNOT be derived from a date.** Measured on SEC's own quarterly indexes, the generations OVERLAP inside a single quarter at both transitions: 2016 QTR2 carries 546 `N-MFP` and 1,039 `N-MFP1`; 2016 QTR4 carries 484 `N-MFP1` and 935 `N-MFP2`; 2024 QTR3 carries 53 `N-MFP2/A` and 965 `N-MFP3`. Amendments make it strictly worse - an `N-MFP2/A` restating a 2023 period was disseminated in 2024 QTR4, four months after `N-MFP3` began. So `edgar_mmf::Generation` is decided by the XML's own shape, and the form type is only cross-checked against it. Dating the era is the defect that left `edgar_13f_holdings` empty before 2013. # `available_date` is NOT the filing date before 2016-05 Original `N-MFP` filings were **embargoed 60 days** under the original Rule 30b1-7, and the embargo is directly observable: an original `N-MFP` appears in NO daily index on its filing date. Probed on seven dissemination days spanning 2011-07-12 → 2016-04-06, `N-MFP` originals number **zero** in every one, while the quarterly full index attributes thousands of them to those same dates. From 2016-05-06 onward `N-MFP1` originals appear same-day (457 rows), and `N-MFP2`/`N-MFP3` continue same-day through 2025. So the pre-2016-05 corpus is a genuine look-ahead trap: its `FILED AS OF DATE` is up to 60 days BEFORE anyone outside SEC could read it. See `docs/availability/edgar_mmf_filings.md`. See `docs/datasets/edgar_mmf_filings.md`.
One row per One SERIES in one REPORT MONTH - one money-market fund series' Form N-MFP cover, keyed by the EDGAR archive path (filename). One submission covers exactly one series (generalInfo/seriesId), so the path is the identity; a registrant running six money funds files six submissions per month. NOT one registrant per month, and NOT one share class: share classes are a nested list inside the submission and are summarised here into total_share_classes rather than exploded, because the class grain carries no portfolio and belongs to a different question..
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_mmf_filings: filing_join: available_date is the EDGAR DISSEMINATION day, taken from the bronze object's own day partition (edgar_docs::available_date), never from the submission's FILED AS OF DATE. WHY: original N-MFP filings were embargoed 60 days under the original Rule 30b1-7 and are absent from every daily index probed between 2011-07-12 and 2016-04-06 (seven days, zero N-MFP originals in each) while the quarterly full index attributes thousands of them to those dates; the embargo lifted with N-MFP1, whose originals appear same-day from 2016-05-06 (457 rows). occurred_on is generalInfo/reportDate - the month end the portfolio is AS OF - and is systematically 3-10 days BEFORE availability in the post-2016 era and up to 60 days before it in the pre-2016 era. Evidence class B (our own 404/absence-vs-presence observations over SEC's daily indexes); see docs/availability/edgar_mmf_filings.md.
Refresh cadence
Obscura refreshes edgar_mmf_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 - 43 columns
The full public column list for edgar_mmf_filings, with the meaning of every field. The same
schema is served unauthenticated at https://api.obscura.trade/v1/catalog/edgar_mmf_filings.
| Column | Type | Description |
|---|---|---|
| filename | text · not null | EDGAR archive path of the N-MFP submission (`edgar/data/{cik}/{accession}.txt`), under sec.gov/Archives/. The primary key, and the join back to `edgar_filings` for the filing's public dissemination date. |
| available_date | date | The EDGAR dissemination date - the day the public could first fetch this filing. Taken from the bronze object's own day partition, NEVER from the submission's `FILED AS OF DATE`, which is up to 60 days early on the pre-2016-05 embargoed generation. The point-in-time anchor. |
| occurred_on | date | The month end the portfolio is reported AS OF (`generalInfo/reportDate`, or gen-1 `DocumentPeriodEndDate`). The real-world event date, always earlier than `available_date` and never a substitute for it. |
| generation | text · not null | Which of the four N-MFP XML vocabularies this submission was written in: `N-MFP`, `N-MFP1`, `N-MFP2` or `N-MFP3`. **Detected from the document's own shape, never from its date** - the generations overlap inside a single quarter at both transitions (2016 QTR2 carries 546 N-MFP and 1,039 N-MFP1). This is the column that says which source tag fed every other one. |
| is_amendment | boolean · not null | True when the submission is an amendment (`.../A` form type). An amendment restates a period already reported, and it is disseminated in its own era - an `N-MFP2/A` was disseminated in 2024 QTR4, months after `N-MFP3` began - which is the second reason the era cannot be dated. |
| reg_cik | bigint | Registrant (filer) CIK, from the submission header / `generalInfo/cik`. |
| reg_name | text | Registrant name. Present as `registrantFullName` only from N-MFP3; on earlier generations it is recovered from the SGML header's `COMPANY CONFORMED NAME`, so the column is populated across all four. |
| reg_lei | text | Registrant Legal Entity Identifier (`registrantLEIId`). N-MFP3 only. |
| series_id | text | SEC series identifier of the money-market fund this report covers (`generalInfo/seriesId`, e.g. `S000011990`). One submission = one series. |
| series_name | text | Series (fund) name. `nameOfSeries` from N-MFP3; NULL on earlier generations, which identify the series only by `seriesId`. |
| series_lei | text | Series Legal Entity Identifier (`leiOfSeries`). N-MFP3 only. |
| file_number | text | Investment Company Act file number of the series (`securitiesActFileNumber`, e.g. `033-34001`). |
| total_share_classes | integer | Number of share classes in the series (`totalShareClassesInSeries`). The class-level blocks themselves are summarised, not exploded - see grain. |
| is_final_filing | boolean | The registrant's final filing for this series (`finalFilingFlag`) - the fund is winding up or deregistering. The liquidation signal. |
| fund_acquired_or_merged | boolean | Whether the fund acquired or merged with another fund since the last filing (`fundAcqrdOrMrgdWthAnthrFlag`); a discontinuity in the series' own history. |
| fund_category | text | Rule 2a-7 fund category as filed - `Government`, `Exempt Government`, `Prime`, `Treasury`, `Single State Fund`, … From `seriesLevelInfo/moneyMarketFundCategory` (gen 2-4) or gen-1 `InvestmentTypeDomain`. **The vocabulary itself changed with the 2014 reform**, so the string is stored verbatim rather than normalised, and `generation` is what says which vocabulary it belongs to. |
| is_government_fund | boolean | Whether the fund is a government money-market fund (`govMoneyMrktFundFlag`). N-MFP3 only; earlier generations express this through `fund_category`. |
| is_retail_fund | boolean | Whether the fund is a retail money-market fund (`fundRetailMoneyMarketFlag` on N-MFP3, `fundExemptRetailFlag` on N-MFP1/2). Retail funds may hold a stable $1.00 share price; institutional prime funds may not - the central distinction the 2014 reform created. |
| is_feeder_fund | boolean | Whether this series is a feeder in a master-feeder structure (`feederFundFlag`); its portfolio is the master's, so its holdings list may be a single line. |
| is_master_fund | boolean | Whether this series is the master in a master-feeder structure (`masterFundFlag`). |
| is_insurance_separate_account | boolean | Whether the series exists primarily to fund insurance-company separate accounts (`seriesFundInsuCmpnySepAccntFlag`). |
| adviser_name | text | Investment adviser name (`seriesLevelInfo/adviser/adviserName`, gen-1 `investmentAdviserList/adviser`). Who actually runs the money. |
| adviser_file_number | text | Adviser's SEC file number (`adviserFileNumber`, e.g. `801-56720`); the join into Form ADV. |
| weighted_average_maturity_days | integer | Dollar-weighted average portfolio maturity in DAYS (`averagePortfolioMaturity`, gen-1 `dollarWeightedAveragePortfolioMaturity`). Rule 2a-7 caps this at 60 days; it is the fund's headline interest-rate exposure. |
| weighted_average_life_days | integer | Dollar-weighted average LIFE to maturity in DAYS (`averageLifeMaturity`). Rule 2a-7 caps it at 120 days. Differs from WAM because WAM may use a rate-reset date while WAL must use the final legal maturity - the gap between the two is the fund's floating-rate exposure. |
| total_value_portfolio_securities | double precision | Total value of portfolio securities (`totalValuePortfolioSecurities`). |
| amortized_cost_portfolio_securities | double precision | Amortized cost of portfolio securities (`amortizedCostPortfolioSecurities`, gen-1 `AvailableForSaleSecuritiesAmortizedCost`). The difference against `total_value_portfolio_securities` is the fund's unrealised mark - the input to a shadow-NAV break. |
| cash | double precision | Cash held by the series (`seriesLevelInfo/cash`). |
| total_value_other_assets | double precision | Total value of other assets (`totalValueOtherAssets`, gen-1 `OtherAssets`). |
| total_value_liabilities | double precision | Total liabilities (`totalValueLiabilities`, gen-1 `Liabilities`). |
| net_assets | double precision | Net assets of the series (`netAssetOfSeries`, gen-1 `AssetsNet`). The size of the fund, and the denominator of every holding's `pct_of_net_assets`. |
| shares_outstanding | double precision | Shares outstanding across all classes (`numberOfSharesOutstanding`). |
| stable_price_per_share | double precision | The stable price per share the fund seeks to maintain (`stablePricePerShare`), normally 1.0000. NULL for a floating-NAV institutional prime fund, which is itself the signal. |
| seven_day_gross_yield | double precision | Seven-day gross yield at the series level (`sevenDayGrossYield`, gen-1 `MoneyMarketSevenDayYield`) as a decimal fraction exactly as filed (`0.0242` = 2.42 %), never rescaled. On N-MFP3 this is a dated repeating block and the value stored is the LAST reported in the month. |
| daily_liquid_assets_pct_min | double precision | LOWEST daily-liquid-asset percentage reported during the month, as a decimal fraction. Rule 2a-7 requires 10 %; the monthly MINIMUM is what tests the constraint, which is why it is stored alongside the last value rather than instead of it. Sourced from the 5 weekly `fridayWeek*` blocks (N-MFP1), the 4 `fridayDay*` blocks (N-MFP2) or the ~21 daily `liquidAssetsDetails` blocks (N-MFP3). NULL on gen-1, which does not report liquidity at all. |
| daily_liquid_assets_pct_last | double precision | The LAST daily-liquid-asset percentage reported in the month - the month-end state, comparable across funds on the same date. Companion to the minimum above. |
| weekly_liquid_assets_pct_min | double precision | LOWEST weekly-liquid-asset percentage reported during the month, as a decimal fraction. Rule 2a-7 requires 30 %, and breaching it is what historically triggered fees and gates - so this minimum is the single most load-bearing number in the filing. NULL on gen-1. |
| weekly_liquid_assets_pct_last | double precision | The LAST weekly-liquid-asset percentage reported in the month; the month-end state. Companion to the minimum above. |
| net_shareholder_flow | double precision | Net shareholder flow for the month, summed across share classes: subscriptions minus redemptions. A run on a money fund shows up here before it shows up anywhere else. |
| gross_subscriptions | double precision | Gross subscriptions for the month, summed across share classes. |
| gross_redemptions | double precision | Gross redemptions for the month, summed across share classes. |
| person_paid_for_fund | boolean | Whether any person paid or waived expenses for the fund in the period (`personPayForFundFlag`) - a sponsor-support signal, and the reason holdings carry both an including- and an excluding-sponsor-support value. |
| holdings | integer · not null | Number of portfolio-security rows this submission produced in `edgar_mmf_holdings`. Stored so a fund with an empty schedule is distinguishable from one that failed to parse. |
Access edgar_mmf_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_mmf_filings",
symbols=["NVDA", "AAPL"],
start="2024-01-01",
)
Create a free account Browse all 122 datasets
Frequently asked questions
What is in the edgar_mmf_filings dataset?
Form N-MFP money-market fund reports, one row per fund per month: net assets, shares outstanding, stable share price, seven-day yield, weighted-average maturity and life, and the Rule 2a-7 daily and weekly liquid-asset ratios that decide whether a fund can meet redemptions. Coverage begins 2016-05 with N-MFP1/2/3; the earlier N-MFP generation is parsed and schema-complete but its presence in the daily dissemination feed is unresolved. One **money-market fund series' monthly portfolio report** - the cover of an SEC Form N-MFP filing: which series, for which month, its net assets, share count, stable share price, seven-day yield, weighted-average maturity and life, and the daily/weekly liquid-asset ratios that Rule 2a-7 actually constrains. This is the fund-level companion to `edgar_mmf_holdings`. Both are parsed from the SAME submission object, and the split is the same one N-PORT uses: one cover row, N position rows. # FOUR GENERATIONS, ONE TABLE - and the generation is read from the DOCUMENT SEC has rewritten this form's XML three times, and **the vocabularies do not merely add fields, they RENAME the same concept**: | | `N-MFP` | `N-MFP1` | `N-MFP2` | `N-MFP3` | |---|---|---|---|---| | first seen | 2010-11 | 2016-05 | 2016-10 | 2024-07 | | root | bare `edgarSubmission`, no `formData` | `formData` | `formData` | `formData` | | positions | `scheduleOfPortfolioSecuritiesList/scheduleOfPortfolioSecurities` | `scheduleOfPortfolioSecuritiesInfo` | same | same | | net assets | `AssetsNet` | `netAssetOfSeries` | same | same | | WAM | `dollarWeightedAveragePortfolioMaturity` | `averagePortfolioMaturity` | same | same | | liquidity | *not reported* | 5 × `fridayWeek{1..5}` | 4 × `fridayDay` + 5 × `fridayWeek` | 21 × `liquidAssetsDetails` | | category | `InvestmentTypeDomain` | `moneyMarketFundCategory` | same | same | **The generation CANNOT be derived from a date.** Measured on SEC's own quarterly indexes, the generations OVERLAP inside a single quarter at both transitions: 2016 QTR2 carries 546 `N-MFP` and 1,039 `N-MFP1`; 2016 QTR4 carries 484 `N-MFP1` and 935 `N-MFP2`; 2024 QTR3 carries 53 `N-MFP2/A` and 965 `N-MFP3`. Amendments make it strictly worse - an `N-MFP2/A` restating a 2023 period was disseminated in 2024 QTR4, four months after `N-MFP3` began. So `edgar_mmf::Generation` is decided by the XML's own shape, and the form type is only cross-checked against it. Dating the era is the defect that left `edgar_13f_holdings` empty before 2013. # `available_date` is NOT the filing date before 2016-05 Original `N-MFP` filings were **embargoed 60 days** under the original Rule 30b1-7, and the embargo is directly observable: an original `N-MFP` appears in NO daily index on its filing date. Probed on seven dissemination days spanning 2011-07-12 → 2016-04-06, `N-MFP` originals number **zero** in every one, while the quarterly full index attributes thousands of them to those same dates. From 2016-05-06 onward `N-MFP1` originals appear same-day (457 rows), and `N-MFP2`/`N-MFP3` continue same-day through 2025. So the pre-2016-05 corpus is a genuine look-ahead trap: its `FILED AS OF DATE` is up to 60 days BEFORE anyone outside SEC could read it. See `docs/availability/edgar_mmf_filings.md`. See `docs/datasets/edgar_mmf_filings.md`.
How do I avoid look-ahead bias with edgar_mmf_filings?
Filter on edgar_mmf_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 (edgar_docs::available_date), never from the submission's FILED AS OF DATE. WHY: original N-MFP filings were embargoed 60 days under the original Rule 30b1-7 and are absent from every daily index probed between 2011-07-12 and 2016-04-06 (seven days, zero N-MFP originals in each) while the quarterly full index attributes thousands of them to those dates; the embargo lifted with N-MFP1, whose originals appear same-day from 2016-05-06 (457 rows). occurred_on is generalInfo/reportDate - the month end the portfolio is AS OF - and is systematically 3-10 days BEFORE availability in the post-2016 era and up to 60 days before it in the pre-2016 era. Evidence class B (our own 404/absence-vs-presence observations over SEC's daily indexes); see docs/availability/edgar_mmf_filings.md. 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_mmf_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_mmf_filings". The column schema is public at https://api.obscura.trade/v1/catalog/edgar_mmf_filings.
Can I filter edgar_mmf_filings by company or symbol?
Yes. edgar_mmf_filings carries series_id, the column the API's symbols filter resolves against.
How often is edgar_mmf_filings updated?
Obscura refreshes edgar_mmf_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.