SEC MIDAS Security Metrics
Per-security market-structure metrics from the SEC's MIDAS system: trade sizes, cancellations, and hidden and odd-lot activity.
sec_midas_security_metrics — the dataset name to pass to the Obscura API.
What one row means
One row is a single security's SEC MIDAS individual-security market-structure metrics for one trading day: market-cap / turnover / volatility / price decile ranks plus lit, hidden, and odd-lot share-volume and trade-count measures, parsed from SEC's free quarterly bulk zip (`individual_security_<YYYY>_q<Q>.zip`), each holding a ~59MB CSV of daily per-security rows. The `_000` fields are in thousands of shares.
One row per (occurred_on, ticker).
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 sec_midas_security_metrics: published: available_date is the day SEC posted the QUARTERLY bulk zip that contains the row, identical on every row of the quarter, materialized by the collector from the object's HTTP Last-Modified (m20260702_000199). Availability is a property of the FILE: the whole quarter ships as one zip, so a January row and a March row become knowable at the same instant. The date is SEC's OWN DAY on SEC's own clock (Eastern), day-of and with no advance for the hour: individual_security_2025_q3.zip carries Last-Modified 2026-03-12 02:50 GMT, which is 22:50 ET on 2026-03-11 — SEC published it on the 11th, and reading the UTC date instead would date 18.8M rows a day late. An mtime is only admissible here because the artifacts are excluded BY NAME (see below). The previous occurred_on + 290 generated column was a per-row lag on a per-file event — 290 was never measured against the source at all, only proxied from OUR OWN sec_midas_processed.processed_at — and it cleared SEC's actual 2025-Q4 posting (2026-07-17) by a single day, putting that quarter's first row at 2026-07-18, so one slower quarter would have made it outright look-ahead; 467,191 rows were already dated into the future. Where SEC's server mtime is not a credible publication stamp (the 30 archive quarters it bulk-touched on 2020-12-19, and 3 with no mtime), the measured steady-state schedule (quarter start + 180 days) stands in and errs late.
Known limitation
Six quarters absent at source: 2014 Q2, all of 2016, and 2019 Q4.
Refresh cadence
Obscura refreshes sec_midas_security_metrics daily — 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 — 20 columns
The full public column list for sec_midas_security_metrics, with the meaning of every field. The same
schema is served unauthenticated at https://api.obscura.trade/v1/catalog/sec_midas_security_metrics.
| Column | Type | Description |
|---|---|---|
| security | text · not null | Security TYPE from the MIDAS `Security` CSV column — a free-text class label taking exactly two values across the whole corpus, "Stock" and "ETF". NOT an identifier: it does not name the security, and keying on it collapsed ~8,000 securities/day onto 2 rows. An attribute only; the identity is (occurred_on, ticker). |
| occurred_on | date · not null | Trading day, parsed from the MIDAS `Date` (YYYYMMDD) column; the period/event date these metrics apply to. Half of the composite primary key. |
| ticker | text · not null | Ticker symbol from the MIDAS `Ticker` column — the security's identity, and half of the composite primary key alongside the trading day. Rows whose `Ticker` cell is blank cannot be identified and are dropped at parse time rather than stored unkeyed. |
| mcap_rank | bigint | Market-capitalization decile rank (MIDAS `McapRank`, typically 1-10) assigned to this security for this trading day under SEC's MIDAS market-structure methodology; nullable when the source cell is blank. |
| turn_rank | bigint | Share-turnover decile rank (MIDAS `TurnRank`) for this security on this trading day. |
| volatility_rank | bigint | Intraday-volatility decile rank (MIDAS `VolatilityRank`) for this security on this trading day. |
| price_rank | bigint | Share-price decile rank (MIDAS `PriceRank`) for this security on this trading day. |
| lit_vol_000 | double precision | Lit (publicly displayed, non-hidden) share trading volume for the day, in thousands of shares (MIDAS `LitVol('000)`). |
| order_vol_000 | double precision | Total order share volume submitted for the day, in thousands of shares (MIDAS `OrderVol('000)`) — the order-flow denominator underlying several of the other rate measures. |
| hidden | double precision | Hidden/dark order rate (MIDAS `Hidden`) — the fraction of order flow executed via non-displayed (reserve/iceberg or dark-pool-style) liquidity for this security-day; a ratio, not a share count. |
| trades_for_hidden | bigint | Count of trades used as the denominator/basis when computing the `hidden` rate for this security-day (MIDAS `TradesForHidden`). |
| hidden_vol_000 | double precision | Hidden/non-displayed share volume for the day, in thousands of shares (MIDAS `HiddenVol('000)`). |
| trade_vol_for_hidden_000 | double precision | Trade share volume forming the basis for the hidden-volume calculation, in thousands of shares (MIDAS `TradeVolForHidden('000)`). |
| cancels | bigint | Count of order cancellations for this security on this trading day (MIDAS `Cancels`) — a market-structure quality/HFT-activity indicator. |
| lit_trades | bigint | Count of lit (displayed) trades executed for this security on this trading day (MIDAS `LitTrades`). |
| odd_lots | double precision | Odd-lot trading rate (MIDAS `OddLots`) — fraction of activity occurring in sub-round-lot (odd-lot) sizes, which historically fell outside consolidated tape reporting; a ratio, not a share count. |
| trades_for_odd_lots | bigint | Count of trades used as the basis when computing the `odd_lots` rate for this security-day (MIDAS `TradesForOddLots`). |
| odd_lot_vol_000 | double precision | Odd-lot share volume for the day, in thousands of shares (MIDAS `OddLotVol('000)`). |
| trade_vol_for_odd_lots_000 | double precision | Trade share volume forming the basis for the odd-lot volume calculation, in thousands of shares (MIDAS `TradeVolForOddLots('000)`). |
| available_date | date · not null | PUBLIC-availability date: the day SEC posted the quarterly bulk zip that contains this trading day. Identical for every trading day inside one quarter, because the whole quarter ships as one file that lands at once. Read from the object's HTTP Last-Modified where that is a credible publication stamp, and from SEC's measured steady-state schedule (quarter start + 180 days) where it is not; recorded per quarter in `sec_midas_processed.published_on` so a bronze replay reproduces it. The point-in-time column to filter/join on — NEVER `occurred_on`, which is the trading day itself. |
Access sec_midas_security_metrics
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="sec_midas_security_metrics",
symbols=["NVDA", "AAPL"],
start="2024-01-01",
)
Create a free account Browse all 95 datasets
Frequently asked questions
What is in the sec_midas_security_metrics dataset?
Per-security market-structure metrics from the SEC's MIDAS system: trade sizes, cancellations, and hidden and odd-lot activity. One row is a single security's SEC MIDAS individual-security market-structure metrics for one trading day: market-cap / turnover / volatility / price decile ranks plus lit, hidden, and odd-lot share-volume and trade-count measures, parsed from SEC's free quarterly bulk zip (`individual_security_<YYYY>_q<Q>.zip`), each holding a ~59MB CSV of daily per-security rows. The `_000` fields are in thousands of shares.
How do I avoid look-ahead bias with sec_midas_security_metrics?
Filter on sec_midas_security_metrics.available_date, the day the publisher made the row public. For this dataset that date is derived as follows — published: available_date is the day SEC posted the QUARTERLY bulk zip that contains the row, identical on every row of the quarter, materialized by the collector from the object's HTTP Last-Modified (m20260702_000199). Availability is a property of the FILE: the whole quarter ships as one zip, so a January row and a March row become knowable at the same instant. The date is SEC's OWN DAY on SEC's own clock (Eastern), day-of and with no advance for the hour: individual_security_2025_q3.zip carries Last-Modified 2026-03-12 02:50 GMT, which is 22:50 ET on 2026-03-11 — SEC published it on the 11th, and reading the UTC date instead would date 18.8M rows a day late. An mtime is only admissible here because the artifacts are excluded BY NAME (see below). The previous occurred_on + 290 generated column was a per-row lag on a per-file event — 290 was never measured against the source at all, only proxied from OUR OWN sec_midas_processed.processed_at — and it cleared SEC's actual 2025-Q4 posting (2026-07-17) by a single day, putting that quarter's first row at 2026-07-18, so one slower quarter would have made it outright look-ahead; 467,191 rows were already dated into the future. Where SEC's server mtime is not a credible publication stamp (the 30 archive quarters it bulk-touched on 2020-12-19, and 3 with no mtime), the measured steady-state schedule (quarter start + 180 days) stands in and errs late. A query of the form WHERE available_date <= '<as-of date>' never sees a row before it existed.
In what formats can I get sec_midas_security_metrics?
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="sec_midas_security_metrics". The column schema is public at https://api.obscura.trade/v1/catalog/sec_midas_security_metrics.
Can I filter sec_midas_security_metrics by company or symbol?
Yes. sec_midas_security_metrics carries ticker, the column the API's symbols filter resolves against.
Is sec_midas_security_metrics complete?
Not yet, and the limitation is declared rather than hidden: Six quarters absent at source: 2014 Q2, all of 2016, and 2019 Q4.
How often is sec_midas_security_metrics updated?
Obscura refreshes sec_midas_security_metrics on a daily 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.