Data dictionary
Field-level reference for every table Masscrest delivers.
Masscrest covers US-listed single stocks and ETFs. OTC-traded names and index products (SPX, VIX, and similar) are out of scope.
For every listed-option contract in scope, Masscrest tracks buy, sell and net flows across three investor cohorts:
| Cohort | Description |
|---|---|
| Institutional | Long-only, long/short, market-neutral, long-biased, multi-strat and other equity hedge funds; mutual funds, sovereign and endowment funds, family offices and other asset managers; proprietary trading desks, banks and dealers trading on behalf of customers. |
| Retail | Global self-directed retail traders (not investment advisors or private-banking clients). |
| Interdealer / market maker | ~99% of trades take place against a market maker, so this cohort sits opposite to Institutional and Retail flows. Interdealer trades are between dealers, typically to offset greek exposure. |
What we provide
Three product surfaces sit on top of the same underlying inference layer:
- Option flow by contract — buy, sell, and net trading imbalance for every listed contract, expressed in shares, premium, and greek-adjusted notional (delta, gamma, vega). Query with contract-level filters (
dte,abs_delta,callput). Tables:option_flows_01_dayandoption_flows_10_min. - Option flow by underlying ticker — the same trading imbalance aggregated to the underlying root symbol × callput. Pre-aggregated at ingest; use when you don't need contract-level filters. Available at the underlying grain (daily + 10-min) and rolled up to sector / industry / ETF / ADR / single-stock / all cohorts (daily only). Tables:
underlying_option_flows_01_day,underlying_option_flows_10_min, andgrouped_flow_signal_01_day(the grouped table carries the raw flow alongside the z-scored signal — see below). - Signal — proprietary indicator of abnormal net options positioning (delta, gamma, vega exposure) driven by institutional investors on the underlying. Historically correlated with subsequent excess returns; used to surface conviction at the ticker, industry, or sector level. Tables:
underlying_flow_signal_01_day(per underlying) andgrouped_flow_signal_01_day(aggregated to sector / industry / ETF / ADR / single-stock / all).
| Surface | Grain | Daily | 10-min |
|---|---|---|---|
| Option flow by contract | (date, figi, callput, strike, expiration) | ✓ | ✓ |
| Option flow by underlying ticker | (date, figi, callput) | ✓ | ✓ |
| Option flow — grouped (sector / industry / …) | (date, group_key, callput) | ✓ | — |
| Signal — per underlying | (date, figi, callput) | ✓ | — |
| Signal — grouped (sector / industry / …) | (date, group_key, callput) | ✓ | — |
Typical uses
- Follow institutional flow. See where hedge funds and asset managers are building or unwinding positions.
- Spot retail-vs-institutional divergences. Identify names where the two cohorts sit on opposite sides.
- Trade the optionality dimension. Separate directional bets from vega and gamma positioning; know whether a move is premium-driven or forced by dealer hedging.
- Layer market narrative on price action. Explain why a name moved when the tape alone doesn't tell you: accumulation ahead of a break, capitulation into a bottom.
- Control for flow in factor models. A signal orthogonal to price and volume. Wire it in as a regression control alongside conventional risk factors.
Delivery & availability
Daily datasets are keyed on US-equity trading dates and delivered one calendar day later (Friday's data lands Saturday). Real-time notification is available via webhook; a polling fallback is documented below.
Cadence
- Frequency: T+1 — data for trading day T is delivered on calendar day T+1 (Friday's data lands Saturday). Data only exists for US equity trading days; delivery cadence itself is calendar-day, not trading-day.
- Publish window: 05:00 – 09:00 UTC on the calendar day after the trading date.
Webhook (recommended)
Register an HTTPS endpoint via POST /v1/webhooks (returns HTTP 201) with your API key — no admin gesture required, no ticket to open. When each day's data lands, we push a signed JSON payload. Wire the delivery handler to your flat-files sync job and the day's parquets pull automatically the moment they're published, without polling the manifest.
{
"event_type": "daily_options_flow.available",
"trading_date": "2026-07-24",
"published_at": "2026-07-25T04:37:12Z",
"workflow_run_id": "aa1cb0c2-5b47-46f1-9c9a-8c9d1c2b0e33"
}
Field semantics:
trading_date: the US equity session the data covers, inYYYY-MM-DD(UTC-derived, but represents the exchange trading session, not the write time).published_at: ISO-8601 UTC timestamp of when the notification was dispatched. Data is fully written before this fires, so it is safe to start reading immediately.workflow_run_id: unique id for the publishing run. Use as your idempotency key: dedupe on this if you receive the same message twice.event_type: alwaysdaily_options_flow.availabletoday. See "Supported events" below.
Verifying the signature
Every request carries two headers:
X-Masscrest-Timestamp: <unix-seconds>X-Masscrest-Signature: sha256=<hex>
Compute HMAC-SHA256 over {timestamp}.{raw_body} using your webhook secret. Reject requests where the timestamp is more than 300 seconds from your clock to block replay attacks.
The secret returned at registration is a 64-character hex string. Decode it to bytes before using it as the HMAC key; UTF-8-encoding the hex string produces the wrong signature.
Python:
import hmac, hashlib, time
def verify(secret_hex: str, timestamp: str, raw_body: bytes, received_sig: str) -> bool:
# Reject stale requests (replay protection).
if abs(int(time.time()) - int(timestamp)) > 300:
return False
key = bytes.fromhex(secret_hex) # NOT secret_hex.encode()
expected = hmac.new(key, f"{timestamp}.".encode() + raw_body, hashlib.sha256).hexdigest()
# Signature header format: "sha256=<hex>[,sha256=<hex>]" (comma-separated during rotation grace)
for sig in received_sig.split(","):
if hmac.compare_digest(f"sha256={expected}", sig.strip()):
return True
return False
Node.js:
const crypto = require("crypto");
function verify(secretHex, timestamp, rawBody, receivedSig) {
if (Math.abs(Math.floor(Date.now() / 1000) - Number(timestamp)) > 300) return false;
const key = Buffer.from(secretHex, "hex"); // NOT Buffer.from(secretHex)
const expected = crypto
.createHmac("sha256", key)
.update(`${timestamp}.`)
.update(rawBody)
.digest("hex");
// Header may contain two signatures separated by "," during the 24h rotation grace window.
return receivedSig.split(",").some((sig) =>
crypto.timingSafeEqual(Buffer.from(`sha256=${expected}`), Buffer.from(sig.trim()))
);
}
Retry policy
Retry on any non-2xx response or timeout after 10 seconds. One initial delivery plus up to six retries (seven POSTs worst case), spaced 30s, 2m, 10m, 1h, 6h, 24h. Use workflow_run_id as your idempotency key. After the sixth failed retry we disable the webhook and email you.
Supported events
One event type is live today:
| Event type | Fires when |
|---|---|
daily_options_flow.available | The daily options-flow pipeline completes for a session (T+1), between 05:00 and 09:00 UTC on the calendar day after the trading date (Friday's data fires Saturday). |
Additional events will be listed here as we add them. Register only for events you handle; an unrecognized event type is rejected at registration (HTTP 422).
Managing webhooks
Self-service via your API key — every endpoint below authenticates with the same X-API-Key you use for /v0/* reads, and each key only sees and manages its own webhooks. Trial accounts may register up to 2 webhooks; paid accounts are unlimited.
| Method | Path | Purpose |
|---|---|---|
POST | /v1/webhooks | Register a URL. Returns webhook_id + secret (secret shown once). |
GET | /v1/webhooks | List your webhooks (secrets redacted). |
GET | /v1/webhooks/{id} | Fetch one webhook by id (secret redacted). |
DELETE | /v1/webhooks/{id} | Remove a webhook. |
POST | /v1/webhooks/{id}/rotate-secret | Generate a new secret. Old secret stays valid for 24h. |
POST | /v1/webhooks/{id}/send-test | Fire a synthetic delivery to the URL for integration testing. Add ?with_retries=true to engage the retry ladder on 5xx for failure-handling validation. |
Polling (alternative)
Each daily publish lands a manifest file in the flat files area of the customer bucket; poll it programmatically between 05:00 and 11:00 UTC on the day after each session to detect delivery:
gs://prod-masscrest/v0/_manifests/year=YYYY/date=YYYY-MM-DD/manifest.json
The manifest is written as the very last step of the daily publish, after every parquet and every downstream ingest is in place. Its existence is the delivery-complete signal; once visible it is safe to start reading immediately.
Sample payload:
{
"workflow_run_id": "aa1cb0c2-5b47-46f1-9c9a-8c9d1c2b0e33",
"trading_date": "2026-07-31",
"published_at": "2026-08-03T01:42:22Z",
"files": [
{ "path": "gs://prod-masscrest/v0/option_flows/01_day/year=2026/date=2026-07-31/000000000000.parquet", "byte_count": 24898886 },
{ "path": "gs://prod-masscrest/v0/underlying_option_flows/01_day/year=2026/date=2026-07-31/000000000000.parquet", "byte_count": 1479423 },
{ "path": "gs://prod-masscrest/v0/underlying_flow_signal/01_day/year=2026/date=2026-07-31/000000000000.parquet", "byte_count": 3512032 },
"…"
]
}
Data corrections
When we detect an error in already-published data, we notify the client's primary technical contact and communicate the fix within 48 hours.
Corrections are written in place, keyed on the same row grain (date, figi, and contract_id where applicable). Re-sync the affected partition to pick up corrected values.
Trial vs. paid tier
Trial accounts share the paid-tier schemas and endpoints — nothing about the shape of the data changes — but usage is capped so a trial can validate integration and evaluate signal quality without pulling the full historical universe. Paid accounts have none of these limits.
| Surface | Trial | Paid |
|---|---|---|
REST API — per-figi endpoints (/v0/option_flows/*, /v0/underlying_option_flows/01_day, /v0/underlying_flow_signals/01_day) | 25 unique FIGIs / UTC day, cumulative across every per-figi call. The 26th distinct FIGI in a UTC day returns HTTP 403 with a structured JSON body: {"error": "trial_figi_cap_exceeded", "cap": 25, "resets_at": "<iso8601>", "touched": [{"figi": "...", "symbol": "..."}, ...], "requested_new": [{"figi": "...", "symbol": "..."}, ...]}. Cap resets at 00:00 UTC. Must supply an explicit figi or underlying_ticker / traded_underlying filter — a broad sector / industry-only sweep returns HTTP 400. | Full universe, no per-figi cap. Broad stock_metadata filters (sector / industry / is_etf / is_adr) work as documented. |
REST API — per-figi snapshots (/v0/underlying_option_flows/01_day/snapshot, /v0/underlying_flow_signals/01_day/snapshot) | HTTP 403. A wide snapshot would charge every returned FIGI against the 25-figi cap in a single call, so snapshot endpoints are blocked outright on trial. Use the ranged per-figi endpoints with an explicit figi filter, or /v0/grouped_flow_signal/01_day/snapshot (not figi-capped) for broad cross-sectional exploration. | Full snapshot access; stock_metadata filters (sector / industry / is_etf / is_adr) work as documented. |
| Data grain | Aggregate rollups only: per underlying × day, per (underlying, callput) × day, and grouped rollups (sector / industry / ETF / ADR / single-stock). Per-contract data is not available. | Same aggregate rollups plus per-contract data through the flat-files bucket. |
REST API — intraday (/v0/*/10_min, including snapshots) | HTTP 403. Daily grain only. | Full intraday access. |
REST API — cohort rollups (/v0/grouped_flow_signal/01_day(+/snapshot)) and metadata (/v0/stock_mapping) | Not figi-capped. Sector / industry / ETF / ADR / single-stock rollups and metadata browsing are free. | Same. |
| REST API — universe | Full — any FIGI Masscrest tracks is queryable (subject to the 25-figi cap). | Full. |
| REST API — daily history depth | 730 days. | Full history from 2020-01-02. |
| REST API — daily call cap | 100 calls / UTC day (HTTP 429 on the 101st call). | 1,000 calls / UTC day (contact sales for higher). |
| MCP server | All tools remain callable. API 403s / 400s (25-figi cap, intraday block, broad-filter block) surface as tool errors — the assistant sees a plain-language message and stops retrying. No MCP-side role gate. | All tools, no cap. |
| Flat files | Requires the programmatic entitlement (opt-in per account; contact sales). Enabled trials get HMAC keys against gs://prod-masscrest-trial — an aggregates-only, daily-only, 180-day-lagged subset with fresh reference metadata. See the Flat files section for the exact bucket layout. Trials without programmatic see HTTP 403 on any flat-files call. | Full production bucket gs://prod-masscrest — contract-level and intraday parquets, no lag. |
Webhooks (/v1/webhooks) | Self-service registration with your API key, capped at 2 registered webhooks per account. | Self-service registration with your API key, unlimited webhooks. |
| Portfolio saves | Unlimited. | Unlimited. |
Trial-to-paid upgrade
On upgrade, the API-tier changes take effect immediately (up to a 5-minute per-instance principal-cache TTL). The Clerk webhook revokes the trial HMAC key at the moment of upgrade, so any local ~/.boto or gsutil configuration pointing at gs://prod-masscrest-trial becomes invalid. Call POST /v0/flat-files/credentials/rotate (or the create endpoint) to receive new keys against the production bucket gs://prod-masscrest and re-point your pipeline.
option_flows_01_day
Per-contract daily option-flow rows, split by participant class (institutional _i, retail _r, market-maker _m). One row per unique option contract that traded on the session, uniquely identified by (date, figi, symbol, callput, strikeprice, expirationdate).
- Grain:
(date, figi, symbol, callput, strikeprice, expirationdate) - History: 2020-01-02 →
- Timing: T+1 (published between 05:00 and 09:00 UTC on the calendar day after the trading date — Friday's data lands Saturday)
*_qty fields are raw traded contract counts (integer). *_premium fields are dollar premium (qty × traded price × adj_shares_deliverable). *_delta / *_gamma / *_vega fields are the traded contracts as greek-weighted USD notional: dollar notional multiplied by the respective per-contract greek, then scaled by adj_shares_deliverable. Delta-weighted notionals are naturally signed by option type (calls +, puts −); net_* = buy_* − sell_* and inherits the sign. The _i + _r + _m ≈ 0 accounting identity holds row-by-row on the notional columns (up to rounding). floor_* is exchange-floor / broker-committed volume, held in its own columns because Masscrest does not track these trades and their side (buy vs sell) is not available. Additional per-contract context columns carry the last-observed underlying spot, forward, IV and greeks for the session (useful as an end-of-day mark).
Fields
| field_name | type | unit | grain | description | provenance | timing_lag | history_start | null_semantics | example |
|---|---|---|---|---|---|---|---|---|---|
date | Date | trading day (UTC) | (date, figi, symbol, callput, strikeprice, expirationdate) | Session date. US equity trading calendar. | exchange | T+1 | 2020-01-02 | never null | 2026-07-24 |
figi | String(12) | identifier | (date, figi, symbol, callput, strikeprice, expirationdate) | OpenFIGI composite FIGI for the underlying. Stable across ticker changes; join key to stock_metadata, px_01_day, split_factors. | exchange | n/a | 2020-01-02 | never null | BBG000MM2P62 |
symbol | String | ticker | (date, figi, symbol, callput, strikeprice, expirationdate) | OCC OPRA root of the option (no-dot form: BRKB, not BRK.B). Match on this key when joining back to raw OCC / OPRA feeds. Use traded_underlying for equity-side joins. | exchange | T+1 | 2020-01-02 | never null | AAPL |
traded_underlying | String | ticker | (date, figi, symbol, callput, strikeprice, expirationdate) | Point-in-time listed equity ticker for the deliverable underlying on date. Dotted dual-class form (BRK.B). Join key to px_01_day, stock_metadata, dividends. | exchange | T+1 | 2020-01-02 | never null | AAPL |
callput | String(1) | option type | (date, figi, symbol, callput, strikeprice, expirationdate) | 'C' (call) or 'P' (put). | exchange | T+1 | 2020-01-02 | never null | C |
strikeprice | Float64 | USD | (date, figi, symbol, callput, strikeprice, expirationdate) | Contract strike price, in the deliverable equity's price units. Not split-adjusted at this grain; use cumulative_split_factor to convert to a current-share-equivalent strike. | exchange | T+1 | 2020-01-02 | never null | 215.00 |
expirationdate | Date | boundary | (date, figi, symbol, callput, strikeprice, expirationdate) | Contract expiration date (US equity calendar). | exchange | T+1 | 2020-01-02 | never null | 2026-08-15 |
dte | Int64 | days | (date, figi, symbol, callput, strikeprice, expirationdate) | Days to expiry: expirationdate − date (calendar days). 0 on the expiry-day trading session; can be negative on late prints of already-expired contracts (rare). | derived | T+1 | 2020-01-02 | never null | 22 |
contract_id | String | identifier | (date, figi, symbol, callput, strikeprice, expirationdate) | Masscrest-built contract identifier that tracks a contract's economic identity across corporate actions (splits, reverse splits, M&A, deliverable adjustments). Standard OCC / OSI symbols mint a new identifier every time the deliverable changes; contract_id deliberately does not, so a single value follows the same economic contract through its lifetime. Built as a deterministic string from (root_symbol, expiration, callput, root-strike × 1000, corporate-action epoch tag); root_symbol and root-strike are the OCC-root form pre-action, and the E<YYYYMMDD> epoch tag disambiguates recycled OPRA symbols that share the same expiry/strike across pre- and post-action cohorts. Joins to underlying_option_flows_01_day (per underlying) via figi but is unique at the contract grain. | derived | T+1 | 2020-01-02 | null on trades that pre-date a required OCC memo for a not-yet-mapped corporate-action epoch (rare, <0.01% of rows) | AAPL 260815C00215000_E00000000 |
adj_shares_deliverable | Float64 | shares per contract | (date, figi, symbol, callput, strikeprice, expirationdate) | Shares conversion adjustment for OCC contract adjustments such as reverse split, M&A, and other corporate actions. Standard equity option delivers 100 shares → adj_shares_deliverable = 100. Post-adjustment values (fractional deliverables, cash + share basket primary legs) are the OCC-declared per-contract share count. | exchange | T+1 | 2020-01-02 | never null | 100.0 |
cumulative_split_factor | Float64 | ratio | (date, figi, symbol, callput, strikeprice, expirationdate) | Cumulative equity split factor in effect on date (same source as split_factors.cum_split_factor). Divide strikeprice by this factor to convert to a current-shares-equivalent strike. 1.0 when no split applies on or after date. | derived | T+1 | 2020-01-02 | never null | 1.0 |
is_index | Bool | flag | (date, figi, symbol, callput, strikeprice, expirationdate) | Whether the underlying is a cash-settled index (SPX, NDX, RUT, VIX, XSP, MRUT, NANOS, XND). false for every single-stock and ETF contract. Currently always false in the served surface (Masscrest does not sell index-option data). Retained for schema stability. | exchange | T+1 | 2020-01-02 | never null | false |
last_underprice | Float64 | USD | (date, figi, symbol, callput, strikeprice, expirationdate) | Underlying spot price observed at the last option trade of the session. Not split-adjusted (contemporaneous mark). | exchange | T+1 | 2020-01-02 | null when the contract has no trades in the session | 224.31 |
last_fwd_underprice | Float64 | USD | (date, figi, symbol, callput, strikeprice, expirationdate) | Forward price on the underlying, adjusted for dividends and the risk-free rate. Not adjusted for splits. | derived | T+1 | 2020-01-02 | null when the contract has no trades in the session | 224.68 |
last_price | Float64 | USD | (date, figi, symbol, callput, strikeprice, expirationdate) | Last traded option price on the session. Per-contract price (not scaled by adj_shares_deliverable). | exchange | T+1 | 2020-01-02 | null when the contract has no trades in the session | 9.42 |
last_iv | Float64 | annualised vol (0.30 = 30%) | (date, figi, symbol, callput, strikeprice, expirationdate) | Implied volatility at the last trade of the session, fit against last_fwd_underprice and last_price. | derived | T+1 | 2020-01-02 | null when the contract has no trades / IV inversion fails | 0.2418 |
last_delta | Float64 | delta per contract | (date, figi, symbol, callput, strikeprice, expirationdate) | Contract delta at the last trade of the session. Signed by option type (calls +, puts −). | derived | T+1 | 2020-01-02 | null when the contract has no trades in the session | 0.5620 |
last_gamma | Float64 | gamma per contract | (date, figi, symbol, callput, strikeprice, expirationdate) | Contract gamma at the last trade of the session. | derived | T+1 | 2020-01-02 | null when the contract has no trades in the session | 0.0184 |
last_vega | Float64 | vega per contract | (date, figi, symbol, callput, strikeprice, expirationdate) | Contract vega at the last trade of the session (dollar P&L per 1 vol point change). | derived | T+1 | 2020-01-02 | null when the contract has no trades in the session | 0.2712 |
qty | Int64 | contracts | (date, figi, symbol, callput, strikeprice, expirationdate) | Total unique traded contract volume for the session (each print contributes its quantity once; m_qty is not double-counted). | exchange | T+1 | 2020-01-02 | 0 on no-volume rows (present only when other fields exist) | 1_842 |
buy_r_qty / sell_r_qty / net_r_qty | Int64 | contracts | (date, figi, symbol, callput, strikeprice, expirationdate) | Retail buy / sell / net contract count. net = buy − sell. | model | T+1 | 2020-01-02 | 0 when no qualifying retail flow | 241 |
buy_r_premium / sell_r_premium / net_r_premium | Float64 | USD | (date, figi, symbol, callput, strikeprice, expirationdate) | Retail dollar premium paid on buys, received on sells, and their net. Signed on net. Scaled by adj_shares_deliverable (deliverable-adjusted). | model | T+1 | 2020-01-02 | 0.0 when no qualifying retail flow | 312_040.0 |
buy_r_delta / sell_r_delta / net_r_delta | Float64 | USD | (date, figi, symbol, callput, strikeprice, expirationdate) | Retail buy / sell / net flow as USD notional × delta (deliverable-adjusted). Naturally signed by option type (calls +, puts −); net = buy − sell. Positive net = net long-delta demand from retail on this contract. | model | T+1 | 2020-01-02 | 0.0 when no qualifying retail flow | -38_720.55 |
buy_r_gamma / sell_r_gamma / net_r_gamma | Float64 | USD | (date, figi, symbol, callput, strikeprice, expirationdate) | Retail buy / sell / net flow as USD-notional-converted gamma (dollar notional multiplied by the per-contract gamma, deliverable-adjusted). | model | T+1 | 2020-01-02 | 0.0 when no qualifying retail flow | 12_450.30 |
buy_r_vega / sell_r_vega / net_r_vega | Float64 | USD | (date, figi, symbol, callput, strikeprice, expirationdate) | Retail buy / sell / net flow as USD-notional-converted vega (deliverable-adjusted). | model | T+1 | 2020-01-02 | 0.0 when no qualifying retail flow | 88_012.40 |
buy_i_qty / sell_i_qty / net_i_qty | Int64 | contracts | (date, figi, symbol, callput, strikeprice, expirationdate) | Institutional buy / sell / net contract count. Same convention as retail. | model | T+1 | 2020-01-02 | 0 when no qualifying institutional flow | 987 |
buy_i_premium / sell_i_premium / net_i_premium | Float64 | USD | (date, figi, symbol, callput, strikeprice, expirationdate) | Institutional dollar premium buy / sell / net (deliverable-adjusted). | model | T+1 | 2020-01-02 | 0.0 when no qualifying institutional flow | 1_120_338.55 |
buy_i_delta / sell_i_delta / net_i_delta | Float64 | USD | (date, figi, symbol, callput, strikeprice, expirationdate) | Institutional buy / sell / net flow as USD notional × delta (deliverable-adjusted). Naturally signed; positive net = net long-delta demand from the institutional class on this contract. | model | T+1 | 2020-01-02 | 0.0 when no qualifying institutional flow | 892_310.00 |
buy_i_gamma / sell_i_gamma / net_i_gamma | Float64 | USD | (date, figi, symbol, callput, strikeprice, expirationdate) | Institutional buy / sell / net flow as USD-notional-converted gamma (deliverable-adjusted). | model | T+1 | 2020-01-02 | 0.0 when no qualifying institutional flow | 41_882.70 |
buy_i_vega / sell_i_vega / net_i_vega | Float64 | USD | (date, figi, symbol, callput, strikeprice, expirationdate) | Institutional buy / sell / net flow as USD-notional-converted vega (deliverable-adjusted). | model | T+1 | 2020-01-02 | 0.0 when no qualifying institutional flow | 312_048.80 |
buy_m_qty / sell_m_qty / net_m_qty | Int64 | contracts | (date, figi, symbol, callput, strikeprice, expirationdate) | Market-maker buy / sell / net contract count. Includes the residual absorption of customer (retail + institutional) net imbalance on the opposite side, so the row-level accounting identity _i + _r + _m ≈ 0 holds by construction on the notionals. | model | T+1 | 2020-01-02 | 0 when no qualifying market-maker flow | -1_098 |
buy_m_premium / sell_m_premium / net_m_premium | Float64 | USD | (date, figi, symbol, callput, strikeprice, expirationdate) | Market-maker dollar premium buy / sell / net (deliverable-adjusted). Mirror of _i + _r on the same row up to floor / rounding. | model | T+1 | 2020-01-02 | 0.0 when no qualifying market-maker flow | -1_432_378.65 |
buy_m_delta / sell_m_delta / net_m_delta | Float64 | USD | (date, figi, symbol, callput, strikeprice, expirationdate) | Market-maker buy / sell / net flow as USD notional × delta (deliverable-adjusted). Mirror of _i + _r on the same row. | model | T+1 | 2020-01-02 | 0.0 when no qualifying market-maker flow | -853_590.00 |
buy_m_gamma / sell_m_gamma / net_m_gamma | Float64 | USD | (date, figi, symbol, callput, strikeprice, expirationdate) | Market-maker buy / sell / net flow as USD-notional-converted gamma (deliverable-adjusted). | model | T+1 | 2020-01-02 | 0.0 when no qualifying market-maker flow | -54_333.00 |
buy_m_vega / sell_m_vega / net_m_vega | Float64 | USD | (date, figi, symbol, callput, strikeprice, expirationdate) | Market-maker buy / sell / net flow as USD-notional-converted vega (deliverable-adjusted). | model | T+1 | 2020-01-02 | 0.0 when no qualifying market-maker flow | -400_172.00 |
floor_qty | Int64 | contracts | (date, figi, symbol, callput, strikeprice, expirationdate) | Total floor-executed contract count (direct-negotiation outcry trades on the exchange floor). No directional classification provided; reported for volume completeness. | exchange | T+1 | 2020-01-02 | 0 when no floor prints | 24 |
floor_premium | Float64 | USD | (date, figi, symbol, callput, strikeprice, expirationdate) | Total floor-executed dollar premium (deliverable-adjusted). No directional classification provided; reported for volume completeness. | exchange | T+1 | 2020-01-02 | 0.0 when no floor prints | 24_120.0 |
floor_delta | Float64 | USD | (date, figi, symbol, callput, strikeprice, expirationdate) | Total floor-executed USD notional × delta (deliverable-adjusted). No directional classification provided; reported for volume completeness. Naturally signed by option type. | exchange | T+1 | 2020-01-02 | 0.0 when no floor prints | 13_492.20 |
floor_gamma | Float64 | USD | (date, figi, symbol, callput, strikeprice, expirationdate) | Total floor-executed USD-notional-converted gamma (deliverable-adjusted). No directional classification provided; reported for volume completeness. | exchange | T+1 | 2020-01-02 | 0.0 when no floor prints | 1_842.10 |
floor_vega | Float64 | USD | (date, figi, symbol, callput, strikeprice, expirationdate) | Total floor-executed USD-notional-converted vega (deliverable-adjusted). No directional classification provided; reported for volume completeness. | exchange | T+1 | 2020-01-02 | 0.0 when no floor prints | 9_820.60 |
Join hints
For per-underlying daily aggregates (rolled up across every contract on the same (date, figi)), use underlying_option_flows_01_day. For underlying prices and turnover, join to px_01_day on (date, figi) and self-adjust using split_factors. For contract-level metadata (deliverable per contract, corporate-action epochs) the values in this table are already point-in-time; no secondary join is needed.
Gross-volume accounting
Each trade has a customer side (buy_{r,i}_qty / sell_{r,i}_qty) and a market-maker counterparty (buy_m_qty / sell_m_qty, rebuilt to absorb the customer imbalance so the row-level _i + _r + _m ≈ 0 identity holds on notionals).
DO: aggregate on qty — one entry per trade.
DON'T: sum the cohort legs (buy_r_qty + sell_r_qty + buy_i_qty + sell_i_qty + buy_m_qty + sell_m_qty + floor_qty) — inflates volume by ~30-35% because the market-maker leg gets added on top of the customer legs.
option_flows_10_min
10-minute-bucketed sibling of option_flows_01_day. Per-contract option-flow rows at a 10-minute cadence: one row per unique option contract that traded within the bucket, keyed on (date, ten_min_timeframe, figi, symbol, callput, strikeprice, expirationdate).
- Grain:
(date, ten_min_timeframe, figi, symbol, callput, strikeprice, expirationdate) - History: 2020-01-02 →
- Timing: T+1 (published between 05:00 and 09:00 UTC on the calendar day after the trading date — Friday's data lands Saturday)
Request window is capped at 30 days per call on the REST endpoint. Omitted dates default to the most recent 30. For multi-year intraday history use flat files at gs://prod-masscrest/v0/option_flows/10_min/; the REST cap keeps response sizes bounded.
Bucket boundary convention
ten_min_timeframe is the end of the 10-minute bucket, in New York wall-clock time stored as a naive DateTime. Bucket covers (ten_min_timeframe − 10 min, ten_min_timeframe]. First RTH bucket ends at 09:40:00, last at 16:00:00 (39 buckets per full RTH session). Join to px_10_min on (date, ten_min_timeframe, figi); both sides use the same NY-wall-clock convention.
Field semantics match option_flows_01_day exactly: the same buy / sell / net triples across the participant classes, greek-weighted USD notionals, the accounting identity _i + _r + _m ≈ 0 (row-by-row), and the same last_* end-of-bucket context columns. The only structural difference is the added ten_min_timeframe dimension.
Fields
| field_name | type | unit | grain | description | provenance | timing_lag | history_start | null_semantics | example |
|---|---|---|---|---|---|---|---|---|---|
date | Date | trading day (UTC) | (date, ten_min_timeframe, figi, symbol, callput, strikeprice, expirationdate) | Session date. US equity trading calendar. | exchange | T+1 | 2020-01-02 | never null | 2026-07-24 |
ten_min_timeframe | DateTime | NY wall-clock, bucket close | (date, ten_min_timeframe, figi, symbol, callput, strikeprice, expirationdate) | End timestamp of the 10-min bucket (naive NY-time). Bucket covers (ten_min_timeframe − 10 min, ten_min_timeframe]. | exchange | T+1 | 2020-01-02 | never null | 2026-07-24 09:40:00 |
figi | String(12) | identifier | (date, ten_min_timeframe, figi, symbol, callput, strikeprice, expirationdate) | OpenFIGI composite FIGI for the underlying. Stable across ticker changes; join key to stock_metadata, px_10_min, split_factors. | exchange | n/a | 2020-01-02 | never null | BBG000MM2P62 |
symbol | String | ticker | (date, ten_min_timeframe, figi, symbol, callput, strikeprice, expirationdate) | OCC OPRA root of the option (no-dot form: BRKB, not BRK.B). Match on this key when joining back to raw OCC / OPRA feeds. Use traded_underlying for equity-side joins. | exchange | T+1 | 2020-01-02 | never null | AAPL |
traded_underlying | String | ticker | (date, ten_min_timeframe, figi, symbol, callput, strikeprice, expirationdate) | Point-in-time listed equity ticker for the deliverable underlying on date. Dotted dual-class form (BRK.B). Join key to px_10_min, stock_metadata, dividends. | exchange | T+1 | 2020-01-02 | never null | AAPL |
callput | String(1) | option type | (date, ten_min_timeframe, figi, symbol, callput, strikeprice, expirationdate) | 'C' (call) or 'P' (put). | exchange | T+1 | 2020-01-02 | never null | C |
strikeprice | Float64 | USD | (date, ten_min_timeframe, figi, symbol, callput, strikeprice, expirationdate) | Contract strike price, in the deliverable equity's price units. Not split-adjusted at this grain; use cumulative_split_factor to convert to a current-share-equivalent strike. | exchange | T+1 | 2020-01-02 | never null | 215.00 |
expirationdate | Date | boundary | (date, ten_min_timeframe, figi, symbol, callput, strikeprice, expirationdate) | Contract expiration date (US equity calendar). | exchange | T+1 | 2020-01-02 | never null | 2026-08-15 |
dte | Int64 | days | (date, ten_min_timeframe, figi, symbol, callput, strikeprice, expirationdate) | Days to expiry: expirationdate − date (calendar days). 0 on the expiry-day trading session. | derived | T+1 | 2020-01-02 | never null | 22 |
contract_id | String | identifier | (date, ten_min_timeframe, figi, symbol, callput, strikeprice, expirationdate) | Masscrest-built contract identifier that tracks a contract's economic identity across corporate actions (splits, reverse splits, M&A, deliverable adjustments), unlike standard OCC / OSI symbols which mint a new identifier every time the deliverable changes. Built as a deterministic string from (root_symbol, expiration, callput, root-strike × 1000, corporate-action epoch tag); the trailing E<YYYYMMDD> epoch tag disambiguates recycled OPRA symbols that share expiry/strike across pre- and post-action cohorts. Same value across every 10-min bucket of the contract's session and across option_flows_01_day. | derived | T+1 | 2020-01-02 | null on trades that pre-date a required OCC memo for a not-yet-mapped corporate-action epoch (rare) | AAPL 260815C00215000_E00000000 |
adj_shares_deliverable | Float64 | shares per contract | (date, ten_min_timeframe, figi, symbol, callput, strikeprice, expirationdate) | Shares conversion adjustment for OCC contract adjustments such as reverse split, M&A, and other corporate actions. Standard equity option delivers 100 shares → adj_shares_deliverable = 100. | exchange | T+1 | 2020-01-02 | never null | 100.0 |
cumulative_split_factor | Float64 | ratio | (date, ten_min_timeframe, figi, symbol, callput, strikeprice, expirationdate) | Cumulative equity split factor in effect on date (same source as split_factors.cum_split_factor). | derived | T+1 | 2020-01-02 | never null | 1.0 |
is_index | Bool | flag | (date, ten_min_timeframe, figi, symbol, callput, strikeprice, expirationdate) | Whether the underlying is a cash-settled index. Currently always false in the served surface. | exchange | T+1 | 2020-01-02 | never null | false |
last_underprice | Float64 | USD | (date, ten_min_timeframe, figi, symbol, callput, strikeprice, expirationdate) | Underlying spot at the last option trade within the bucket. Not split-adjusted. | exchange | T+1 | 2020-01-02 | null when the contract has no trades in the bucket | 224.10 |
last_fwd_underprice | Float64 | USD | (date, ten_min_timeframe, figi, symbol, callput, strikeprice, expirationdate) | Forward price on the underlying, adjusted for dividends and the risk-free rate. Not adjusted for splits. | derived | T+1 | 2020-01-02 | null when the contract has no trades in the bucket | 224.48 |
last_price | Float64 | USD | (date, ten_min_timeframe, figi, symbol, callput, strikeprice, expirationdate) | Last traded option price in the bucket. Per-contract price (not scaled by adj_shares_deliverable). | exchange | T+1 | 2020-01-02 | null when the contract has no trades in the bucket | 9.38 |
last_iv | Float64 | annualised vol (0.30 = 30%) | (date, ten_min_timeframe, figi, symbol, callput, strikeprice, expirationdate) | Implied volatility at the last trade of the bucket. | derived | T+1 | 2020-01-02 | null when the contract has no trades / IV inversion fails | 0.2418 |
last_delta | Float64 | delta per contract | (date, ten_min_timeframe, figi, symbol, callput, strikeprice, expirationdate) | Contract delta at the last trade of the bucket. Signed by option type. | derived | T+1 | 2020-01-02 | null when the contract has no trades in the bucket | 0.5620 |
last_gamma | Float64 | gamma per contract | (date, ten_min_timeframe, figi, symbol, callput, strikeprice, expirationdate) | Contract gamma at the last trade of the bucket. | derived | T+1 | 2020-01-02 | null when the contract has no trades in the bucket | 0.0184 |
last_vega | Float64 | vega per contract | (date, ten_min_timeframe, figi, symbol, callput, strikeprice, expirationdate) | Contract vega at the last trade of the bucket. | derived | T+1 | 2020-01-02 | null when the contract has no trades in the bucket | 0.2712 |
qty | Int64 | contracts | (date, ten_min_timeframe, figi, symbol, callput, strikeprice, expirationdate) | Total unique traded contract volume in the bucket. | exchange | T+1 | 2020-01-02 | 0 on no-volume rows | 184 |
buy_r_qty / sell_r_qty / net_r_qty | Int64 | contracts | (date, ten_min_timeframe, figi, symbol, callput, strikeprice, expirationdate) | Retail buy / sell / net contract count within the bucket. | model | T+1 | 2020-01-02 | 0 when no qualifying retail flow | 24 |
buy_r_premium / sell_r_premium / net_r_premium | Float64 | USD | (date, ten_min_timeframe, figi, symbol, callput, strikeprice, expirationdate) | Retail dollar premium buy / sell / net for the bucket (deliverable-adjusted). | model | T+1 | 2020-01-02 | 0.0 when no qualifying retail flow | 31_204.0 |
buy_r_delta / sell_r_delta / net_r_delta | Float64 | USD | (date, ten_min_timeframe, figi, symbol, callput, strikeprice, expirationdate) | Retail buy / sell / net flow as USD notional × delta (deliverable-adjusted). Naturally signed by option type; positive net = net long-delta demand from retail on this contract in the bucket. | model | T+1 | 2020-01-02 | 0.0 when no qualifying retail flow | -3_872.55 |
buy_r_gamma / sell_r_gamma / net_r_gamma | Float64 | USD | (date, ten_min_timeframe, figi, symbol, callput, strikeprice, expirationdate) | Retail buy / sell / net flow as USD-notional-converted gamma (deliverable-adjusted). | model | T+1 | 2020-01-02 | 0.0 when no qualifying retail flow | 1_245.30 |
buy_r_vega / sell_r_vega / net_r_vega | Float64 | USD | (date, ten_min_timeframe, figi, symbol, callput, strikeprice, expirationdate) | Retail buy / sell / net flow as USD-notional-converted vega (deliverable-adjusted). | model | T+1 | 2020-01-02 | 0.0 when no qualifying retail flow | 8_801.40 |
buy_i_qty / sell_i_qty / net_i_qty | Int64 | contracts | (date, ten_min_timeframe, figi, symbol, callput, strikeprice, expirationdate) | Institutional buy / sell / net contract count for the bucket. | model | T+1 | 2020-01-02 | 0 when no qualifying institutional flow | 98 |
buy_i_premium / sell_i_premium / net_i_premium | Float64 | USD | (date, ten_min_timeframe, figi, symbol, callput, strikeprice, expirationdate) | Institutional dollar premium buy / sell / net (deliverable-adjusted). | model | T+1 | 2020-01-02 | 0.0 when no qualifying institutional flow | 112_034.55 |
buy_i_delta / sell_i_delta / net_i_delta | Float64 | USD | (date, ten_min_timeframe, figi, symbol, callput, strikeprice, expirationdate) | Institutional buy / sell / net flow as USD notional × delta (deliverable-adjusted). Positive net = net long-delta demand from the institutional class on this contract in the bucket. | model | T+1 | 2020-01-02 | 0.0 when no qualifying institutional flow | 89_231.00 |
buy_i_gamma / sell_i_gamma / net_i_gamma | Float64 | USD | (date, ten_min_timeframe, figi, symbol, callput, strikeprice, expirationdate) | Institutional buy / sell / net flow as USD-notional-converted gamma (deliverable-adjusted). | model | T+1 | 2020-01-02 | 0.0 when no qualifying institutional flow | 4_188.70 |
buy_i_vega / sell_i_vega / net_i_vega | Float64 | USD | (date, ten_min_timeframe, figi, symbol, callput, strikeprice, expirationdate) | Institutional buy / sell / net flow as USD-notional-converted vega (deliverable-adjusted). | model | T+1 | 2020-01-02 | 0.0 when no qualifying institutional flow | 31_204.80 |
buy_m_qty / sell_m_qty / net_m_qty | Int64 | contracts | (date, ten_min_timeframe, figi, symbol, callput, strikeprice, expirationdate) | Market-maker buy / sell / net contract count for the bucket. Includes the residual absorption of customer (retail + institutional) net imbalance on the opposite side. | model | T+1 | 2020-01-02 | 0 when no qualifying market-maker flow | -108 |
buy_m_premium / sell_m_premium / net_m_premium | Float64 | USD | (date, ten_min_timeframe, figi, symbol, callput, strikeprice, expirationdate) | Market-maker dollar premium buy / sell / net (deliverable-adjusted). Mirror of _i + _r on the same row up to floor / rounding. | model | T+1 | 2020-01-02 | 0.0 when no qualifying market-maker flow | -143_237.65 |
buy_m_delta / sell_m_delta / net_m_delta | Float64 | USD | (date, ten_min_timeframe, figi, symbol, callput, strikeprice, expirationdate) | Market-maker buy / sell / net flow as USD notional × delta (deliverable-adjusted). Mirror of _i + _r on the same row. | model | T+1 | 2020-01-02 | 0.0 when no qualifying market-maker flow | -85_359.00 |
buy_m_gamma / sell_m_gamma / net_m_gamma | Float64 | USD | (date, ten_min_timeframe, figi, symbol, callput, strikeprice, expirationdate) | Market-maker buy / sell / net flow as USD-notional-converted gamma (deliverable-adjusted). | model | T+1 | 2020-01-02 | 0.0 when no qualifying market-maker flow | -5_433.30 |
buy_m_vega / sell_m_vega / net_m_vega | Float64 | USD | (date, ten_min_timeframe, figi, symbol, callput, strikeprice, expirationdate) | Market-maker buy / sell / net flow as USD-notional-converted vega (deliverable-adjusted). | model | T+1 | 2020-01-02 | 0.0 when no qualifying market-maker flow | -40_017.20 |
floor_qty | Int64 | contracts | (date, ten_min_timeframe, figi, symbol, callput, strikeprice, expirationdate) | Total floor-executed contract count within the bucket (direct-negotiation outcry trades on the exchange floor). No directional classification provided; reported for volume completeness. | exchange | T+1 | 2020-01-02 | 0 when no floor prints | 4 |
floor_premium | Float64 | USD | (date, ten_min_timeframe, figi, symbol, callput, strikeprice, expirationdate) | Total floor-executed dollar premium within the bucket (deliverable-adjusted). No directional classification provided; reported for volume completeness. | exchange | T+1 | 2020-01-02 | 0.0 when no floor prints | 4_120.0 |
floor_delta | Float64 | USD | (date, ten_min_timeframe, figi, symbol, callput, strikeprice, expirationdate) | Total floor-executed USD notional × delta within the bucket (deliverable-adjusted). No directional classification provided; reported for volume completeness. Naturally signed. | exchange | T+1 | 2020-01-02 | 0.0 when no floor prints | 2_349.20 |
floor_gamma | Float64 | USD | (date, ten_min_timeframe, figi, symbol, callput, strikeprice, expirationdate) | Total floor-executed USD-notional-converted gamma within the bucket (deliverable-adjusted). No directional classification provided; reported for volume completeness. | exchange | T+1 | 2020-01-02 | 0.0 when no floor prints | 184.10 |
floor_vega | Float64 | USD | (date, ten_min_timeframe, figi, symbol, callput, strikeprice, expirationdate) | Total floor-executed USD-notional-converted vega within the bucket (deliverable-adjusted). No directional classification provided; reported for volume completeness. | exchange | T+1 | 2020-01-02 | 0.0 when no floor prints | 982.60 |
Join hints
For per-underlying 10-min aggregates (rolled up across every contract on the same (date, ten_min_timeframe, figi)), use underlying_option_flows_10_min. For underlying prices and turnover, join to px_10_min on (date, ten_min_timeframe, figi) and self-adjust using split_factors. For daily rollups of the same contracts, sum across ten_min_timeframe or use option_flows_01_day directly.
Gross-volume accounting
Each trade has a customer side (buy_{r,i}_qty / sell_{r,i}_qty) and a market-maker counterparty (buy_m_qty / sell_m_qty, rebuilt to absorb the customer imbalance so the row-level _i + _r + _m ≈ 0 identity holds on notionals).
DO: aggregate on qty — one entry per trade per bucket.
DON'T: sum the cohort legs (buy_r_qty + sell_r_qty + buy_i_qty + sell_i_qty + buy_m_qty + sell_m_qty + floor_qty) — inflates per bucket volume by ~30-35% because the market-maker leg gets added on top of the customer legs.
underlying_option_flows_01_day
Per-underlying × callput daily aggregation. Same participant-split option-flow columns as option_flows_01_day, rolled up across every contract on the same (date, figi, callput) grain rather than kept at contract resolution. Every underlying has up to two rows per session: callput = 'C' and callput = 'P'. Adds context columns (contract count, aggregate share count, session-end underlying mark, 30-day ATM IV).
- Grain:
(date, figi, callput) - History: 2020-01-02 →
- Timing: T+1 (published between 05:00 and 09:00 UTC on the calendar day after the trading date — Friday's data lands Saturday)
Underlying price, turnover, and metadata are not baked into this table. Join to px_01_day (adjust locally with split_factors) and stock_metadata on figi.
Difference vs option_flows_01_day
option_flows_01_day is per-contract. underlying_option_flows_01_day collapses every contract on (date, figi, callput) into a single row, preserving the call vs put dimension for cross-sectional or callput-aware research (put-only skew, gross calls-vs-puts turnover, callput-aware Δ). Query with callput=CP to have both rows summed back into one at query time; query with callput=C or callput=P for a single side. No contract-level filters here (no dte / abs_delta axes); this table is pre-aggregated inside the pipeline.
Fields
| field_name | type | unit | grain | description | provenance | timing_lag | history_start | null_semantics | example |
|---|---|---|---|---|---|---|---|---|---|
date | Date | trading day (UTC) | (date, figi, callput) | Session date. US equity trading calendar. | exchange | T+1 | 2020-01-02 | never null | 2026-07-24 |
figi | String(12) | identifier | (date, figi, callput) | OpenFIGI composite FIGI for the underlying. Join key to stock_metadata, px_01_day, split_factors. | exchange | n/a | 2020-01-02 | never null | BBG000MM2P62 |
traded_underlying | String | ticker | (date, figi, callput) | Point-in-time listed equity ticker on date. Dotted dual-class form (BRK.B). | exchange | T+1 | 2020-01-02 | never null | AAPL |
callput | String(1) | option type | (date, figi, callput) | 'C' (call side) or 'P' (put side). When queried with callput=CP the router sums the two rows and emits the literal 'CP' in this column. | exchange | T+1 | 2020-01-02 | never null | C |
n_contracts | UInt32 | contracts | (date, figi, callput) | Distinct option contracts that traded on this underlying × callput on date. | exchange | T+1 | 2020-01-02 | 0 on no-volume days | 184 |
total_shares | Float64 | delta-adjusted share equivalents | (date, figi, callput) | Sum of all traded contract volume converted to underlying-share equivalents (qty × adj_shares_deliverable), regardless of side. | exchange | T+1 | 2020-01-02 | 0.0 on no-volume days | 2_384_100.0 |
last_underprice | Float64 | USD | (date, figi, callput) | Underlying spot price observed against the last option trade of the session. Not split-adjusted (contemporaneous mark). | exchange | T+1 | 2020-01-02 | null on no-volume days | 224.31 |
last_fwd_underprice | Float64 | USD | (date, figi, callput) | Forward price on the underlying, adjusted for dividends and the risk-free rate. Not adjusted for splits. | derived | T+1 | 2020-01-02 | null on no-volume days | 224.68 |
atm_iv_30d | Float64 | annualised vol (0.30 = 30%) | (date, figi, callput) | 30-day at-the-money implied volatility of the underlying, from the last IV surface fit of the session. | derived | T+1 | 2020-01-02 | null on no-volume days | 0.2418 |
buy_r_shares / sell_r_shares / net_r_shares | Float64 | delta-adjusted share equivalents | (date, figi, callput) | Retail buy / sell / net share equivalents for the (underlying, callput) row. | model | T+1 | 2020-01-02 | 0.0 when no qualifying volume | 24_100.0 |
buy_r_premium / sell_r_premium / net_r_premium | Float64 | USD | (date, figi, callput) | Retail dollar premium buy / sell / net. | model | T+1 | 2020-01-02 | 0.0 when no qualifying volume | 312_040.0 |
buy_r_delta / sell_r_delta / net_r_delta | Float64 | USD | (date, figi, callput) | Retail buy / sell / net flow as USD notional × delta for the (underlying, callput) row. Naturally signed (calls +, puts −); positive net = net long-delta demand from retail on this call/put side. | model | T+1 | 2020-01-02 | 0.0 when no qualifying volume | -3_872_000.55 |
buy_r_gamma / sell_r_gamma / net_r_gamma | Float64 | USD | (date, figi, callput) | Retail buy / sell / net flow as USD-notional-converted gamma. | model | T+1 | 2020-01-02 | 0.0 when no qualifying volume | 1_245_030.30 |
buy_r_vega / sell_r_vega / net_r_vega | Float64 | USD | (date, figi, callput) | Retail buy / sell / net flow as USD-notional-converted vega. | model | T+1 | 2020-01-02 | 0.0 when no qualifying volume | 8_801_240.40 |
buy_i_shares / sell_i_shares / net_i_shares | Float64 | delta-adjusted share equivalents | (date, figi, callput) | Institutional buy / sell / net share equivalents. | model | T+1 | 2020-01-02 | 0.0 when no qualifying volume | 128_450.0 |
buy_i_premium / sell_i_premium / net_i_premium | Float64 | USD | (date, figi, callput) | Institutional dollar premium buy / sell / net. | model | T+1 | 2020-01-02 | 0.0 when no qualifying volume | 412_034.55 |
buy_i_delta / sell_i_delta / net_i_delta | Float64 | USD | (date, figi, callput) | Institutional buy / sell / net flow as USD notional × delta for the (underlying, callput) row. Positive net = net long-delta demand from the institutional class on this call/put side. | model | T+1 | 2020-01-02 | 0.0 when no qualifying volume | 89_231_000.00 |
buy_i_gamma / sell_i_gamma / net_i_gamma | Float64 | USD | (date, figi, callput) | Institutional buy / sell / net flow as USD-notional-converted gamma. | model | T+1 | 2020-01-02 | 0.0 when no qualifying volume | 4_188_270.70 |
buy_i_vega / sell_i_vega / net_i_vega | Float64 | USD | (date, figi, callput) | Institutional buy / sell / net flow as USD-notional-converted vega. | model | T+1 | 2020-01-02 | 0.0 when no qualifying volume | 31_200_480.80 |
buy_m_shares / sell_m_shares / net_m_shares | Float64 | delta-adjusted share equivalents | (date, figi, callput) | Market-maker buy / sell / net share equivalents. _i + _r + _m = 0 per row. | model | T+1 | 2020-01-02 | 0.0 when no qualifying volume | -130_860.0 |
buy_m_premium / sell_m_premium / net_m_premium | Float64 | USD | (date, figi, callput) | Market-maker dollar premium buy / sell / net. | model | T+1 | 2020-01-02 | 0.0 when no qualifying volume | -824_067.10 |
buy_m_delta / sell_m_delta / net_m_delta | Float64 | USD | (date, figi, callput) | Market-maker buy / sell / net flow as USD notional × delta. Mirror of _i + _r on the same row (identity _i + _r + _m = 0). | model | T+1 | 2020-01-02 | 0.0 when no qualifying volume | -85_359_000.00 |
buy_m_gamma / sell_m_gamma / net_m_gamma | Float64 | USD | (date, figi, callput) | Market-maker buy / sell / net flow as USD-notional-converted gamma. | model | T+1 | 2020-01-02 | 0.0 when no qualifying volume | -5_433_300.00 |
buy_m_vega / sell_m_vega / net_m_vega | Float64 | USD | (date, figi, callput) | Market-maker buy / sell / net flow as USD-notional-converted vega. | model | T+1 | 2020-01-02 | 0.0 when no qualifying volume | -40_001_720.00 |
Gross-volume accounting
Each trade has a customer side (buy_{r,i}_shares / sell_{r,i}_shares) and a market-maker counterparty (buy_m_shares / sell_m_shares, rebuilt to absorb the customer imbalance so the row-level _i + _r + _m ≈ 0 identity holds on notionals). Same convention applies to _premium / _delta / _gamma / _vega.
DO: aggregate on total_shares — one entry per trade.
DON'T: sum the cohort legs (buy_r_shares + sell_r_shares + buy_i_shares + sell_i_shares + buy_m_shares + sell_m_shares) — inflates volume by ~30-35% because the market-maker leg gets added on top of the customer legs.
underlying_option_flows_10_min
10-minute-bucketed sibling of underlying_option_flows_01_day. Per-underlying × callput option-flow aggregation at a 10-minute cadence, with contract-count context and session-end marks.
- Grain:
(date, ten_min_timeframe, figi, callput). Up to two rows per underlying per 10-min bucket ('C'and'P'). - History: 2020-01-02 →
- Timing: T+1 (published between 05:00 and 09:00 UTC on the calendar day after the trading date — Friday's data lands Saturday)
Underlying price, turnover, and metadata are not baked into this table. Join to px_10_min (adjust locally with split_factors) and stock_metadata on figi.
Request window is capped at 30 days per call on the REST endpoint. For multi-year intraday history use flat files at gs://prod-masscrest/v0/underlying_option_flows/10_min/.
Bucket boundary convention
ten_min_timeframe is the end of the 10-minute bucket, NY wall-clock, naive DateTime. Bucket covers (ten_min_timeframe − 10 min, ten_min_timeframe]. First RTH bucket: 09:40:00; last: 16:00:00. Same convention as option_flows_10_min and px_10_min; join directly on (date, ten_min_timeframe, figi).
Difference vs option_flows_10_min
option_flows_10_min is per-contract. underlying_option_flows_10_min collapses every contract on (date, ten_min_timeframe, figi, callput) into a single row, keeping the call vs put dimension and adding contract-count / session-mark / IV context columns. This is the intended surface for cross-sectional or callput-aware research.
buy_m_shares / sell_m_shares are for directional cohort analysis (net market-maker positioning on the row), not for gross volume totals. The same convention applies to the _premium, _delta, _gamma, and _vega cohort columns — sum buy_r + sell_r + buy_i + sell_i + buy_m + sell_m and you double-count the market-maker leg on every unit.
Fields
| field_name | type | unit | grain | description | provenance | timing_lag | history_start | null_semantics | example |
|---|---|---|---|---|---|---|---|---|---|
date | Date | trading day (UTC) | (date, ten_min_timeframe, figi, callput) | Session date. | exchange | T+1 | 2020-01-02 | never null | 2026-07-24 |
ten_min_timeframe | DateTime | NY wall-clock, bucket close | (date, ten_min_timeframe, figi, callput) | End timestamp of the 10-min bucket (naive NY-time). | exchange | T+1 | 2020-01-02 | never null | 2026-07-24 09:40:00 |
figi | String(12) | identifier | (date, ten_min_timeframe, figi, callput) | OpenFIGI composite FIGI for the underlying. | exchange | n/a | 2020-01-02 | never null | BBG000MM2P62 |
traded_underlying | String | ticker | (date, ten_min_timeframe, figi, callput) | Point-in-time listed equity ticker on date. Dotted dual-class form. | exchange | T+1 | 2020-01-02 | never null | AAPL |
callput | String(1) | option type | (date, ten_min_timeframe, figi, callput) | 'C' or 'P'. callput=CP on the endpoint sums the two rows at query time. | exchange | T+1 | 2020-01-02 | never null | C |
n_contracts | UInt32 | contracts | (date, ten_min_timeframe, figi, callput) | Distinct option contracts traded on this underlying × callput within the bucket. | exchange | T+1 | 2020-01-02 | 0 on no-volume buckets | 48 |
total_shares | Float64 | delta-adjusted share equivalents | (date, ten_min_timeframe, figi, callput) | Sum of all traded volume converted to share equivalents within the bucket. | exchange | T+1 | 2020-01-02 | 0.0 on no-volume buckets | 184_500.0 |
last_underprice | Float64 | USD | (date, ten_min_timeframe, figi, callput) | Underlying spot at the last option trade within the bucket. Not split-adjusted. | exchange | T+1 | 2020-01-02 | null on no-volume buckets | 224.10 |
last_fwd_underprice | Float64 | USD | (date, ten_min_timeframe, figi, callput) | Forward price on the underlying, adjusted for dividends and the risk-free rate. Not adjusted for splits. | derived | T+1 | 2020-01-02 | null on no-volume buckets | 224.48 |
atm_iv_30d | Float64 | annualised vol | (date, ten_min_timeframe, figi, callput) | 30-day at-the-money implied vol at the last option trade of the bucket. | derived | T+1 | 2020-01-02 | null on no-volume buckets | 0.2418 |
buy_r_shares / sell_r_shares / net_r_shares | Float64 | delta-adjusted share equivalents | (date, ten_min_timeframe, figi, callput) | Retail buy / sell / net share equivalents within the bucket. | model | T+1 | 2020-01-02 | 0.0 when no qualifying volume | 2_410.0 |
buy_r_premium / sell_r_premium / net_r_premium | Float64 | USD | (date, ten_min_timeframe, figi, callput) | Retail dollar premium buy / sell / net. | model | T+1 | 2020-01-02 | 0.0 when no qualifying volume | 31_204.0 |
buy_r_delta / sell_r_delta / net_r_delta | Float64 | USD | (date, ten_min_timeframe, figi, callput) | Retail buy / sell / net flow as USD notional × delta for the (underlying, callput) row within the bucket. Naturally signed by option type; positive net = net long-delta demand from retail on this call/put side in the bucket. | model | T+1 | 2020-01-02 | 0.0 when no qualifying volume | -387_200.55 |
buy_r_gamma / sell_r_gamma / net_r_gamma | Float64 | USD | (date, ten_min_timeframe, figi, callput) | Retail buy / sell / net flow as USD-notional-converted gamma for the bucket. | model | T+1 | 2020-01-02 | 0.0 when no qualifying volume | 124_530.30 |
buy_r_vega / sell_r_vega / net_r_vega | Float64 | USD | (date, ten_min_timeframe, figi, callput) | Retail buy / sell / net flow as USD-notional-converted vega for the bucket. | model | T+1 | 2020-01-02 | 0.0 when no qualifying volume | 880_140.40 |
buy_i_shares / sell_i_shares / net_i_shares | Float64 | delta-adjusted share equivalents | (date, ten_min_timeframe, figi, callput) | Institutional buy / sell / net share equivalents. _i + _r + _m = 0 per row. | model | T+1 | 2020-01-02 | 0.0 when no qualifying volume | 12_845.0 |
buy_i_premium / sell_i_premium / net_i_premium | Float64 | USD | (date, ten_min_timeframe, figi, callput) | Institutional dollar premium buy / sell / net. | model | T+1 | 2020-01-02 | 0.0 when no qualifying volume | 41_203.55 |
buy_i_delta / sell_i_delta / net_i_delta | Float64 | USD | (date, ten_min_timeframe, figi, callput) | Institutional buy / sell / net flow as USD notional × delta for the bucket. Positive net = net long-delta demand from the institutional class on this call/put side in the bucket. | model | T+1 | 2020-01-02 | 0.0 when no qualifying volume | 8_923_100.00 |
buy_i_gamma / sell_i_gamma / net_i_gamma | Float64 | USD | (date, ten_min_timeframe, figi, callput) | Institutional buy / sell / net flow as USD-notional-converted gamma for the bucket. | model | T+1 | 2020-01-02 | 0.0 when no qualifying volume | 418_870.70 |
buy_i_vega / sell_i_vega / net_i_vega | Float64 | USD | (date, ten_min_timeframe, figi, callput) | Institutional buy / sell / net flow as USD-notional-converted vega for the bucket. | model | T+1 | 2020-01-02 | 0.0 when no qualifying volume | 3_120_080.80 |
buy_m_shares / sell_m_shares / net_m_shares | Float64 | delta-adjusted share equivalents | (date, ten_min_timeframe, figi, callput) | Market-maker buy / sell / net share equivalents. | model | T+1 | 2020-01-02 | 0.0 when no qualifying volume | -13_086.0 |
buy_m_premium / sell_m_premium / net_m_premium | Float64 | USD | (date, ten_min_timeframe, figi, callput) | Market-maker dollar premium buy / sell / net. | model | T+1 | 2020-01-02 | 0.0 when no qualifying volume | -82_406.71 |
buy_m_delta / sell_m_delta / net_m_delta | Float64 | USD | (date, ten_min_timeframe, figi, callput) | Market-maker buy / sell / net flow as USD notional × delta for the bucket. Mirror of _i + _r on the same row (identity _i + _r + _m = 0). | model | T+1 | 2020-01-02 | 0.0 when no qualifying volume | -8_535_900.00 |
buy_m_gamma / sell_m_gamma / net_m_gamma | Float64 | USD | (date, ten_min_timeframe, figi, callput) | Market-maker buy / sell / net flow as USD-notional-converted gamma for the bucket. | model | T+1 | 2020-01-02 | 0.0 when no qualifying volume | -543_330.00 |
buy_m_vega / sell_m_vega / net_m_vega | Float64 | USD | (date, ten_min_timeframe, figi, callput) | Market-maker buy / sell / net flow as USD-notional-converted vega for the bucket. | model | T+1 | 2020-01-02 | 0.0 when no qualifying volume | -4_001_720.00 |
Gross-volume accounting
Each trade has a customer side (buy_{r,i}_shares / sell_{r,i}_shares) and a market-maker counterparty (buy_m_shares / sell_m_shares, rebuilt to absorb the customer imbalance so the row-level _i + _r + _m ≈ 0 identity holds on notionals). Same convention applies to _premium / _delta / _gamma / _vega.
DO: aggregate on total_shares — one entry per trade per bucket.
DON'T: sum the cohort legs (buy_r_shares + sell_r_shares + buy_i_shares + sell_i_shares + buy_m_shares + sell_m_shares) — inflates per bucket volume by ~30-35% because the market-maker leg gets added on top of the customer legs.
underlying_flow_signal_01_day
Daily flow-signal derivatives computed on the underlying-level nets (net_i_*, net_r_*, greeks included) from underlying_option_flows_01_day. Per-(date, figi, callput) grain. All fields are trailing-window transforms (no forward-looking information), so a row at date = D is safe to use for a decision at close of D (or, more conservatively, at open of D+1).
- Grain:
(date, figi, callput)wherecallput ∈ {'C', 'P', 'CP'}. - History: 2020-01-02 →
- Timing: T+1 (published between 05:00 and 09:00 UTC on the calendar day after the trading date — Friday's data lands Saturday; same publish window as flows).
Signal design
This is an in-house Masscrest signal built to flag options activity that is extreme against a stock's own history. Each raw daily net is summed over a 21-trading-day trailing window and then z-scored against its own 2-year rolling mean and standard deviation, scoped to (figi, callput).
_21dma= 21-trading-day rolling SUM of the raw daily net, PARTITION BY(figi, callput). (Historically shipped as a rolling mean; arithmetically equivalent for the z-score, since the sum is just the mean multiplied by 21. The distributed series is now the sum.)z_net_*_21dma= z-score of_21dmaagainst its 2-year (504 trading day) trailing mean and sample standard deviation, computed at query time. Minimum 63 non-null observations in the trailing window required, else null. Rounded to 2 decimals on emit.
The raw rolling μ and σ series are computed on the fly at query time and are not distributed as separate columns — only the resulting z-score ships.
The calculation is deliberately simple. Options activity is not stationary across stocks or over time, and z-scores can reach unrealistic multiples of 3 SD during earnings, M&A, or other catalysts. Masscrest does not cap, winsorise, or otherwise regularise the output: keeping the formula plain avoids overfitting to any specific regime and lets clients replicate the transform end-to-end from underlying_option_flows_01_day if they want to. Validation of the single-name spike predicate lives at /research/systematic-single-stock-signal; the industry-aggregated version and its long-short performance live at /research/industry-flow-signal.
callput semantics
Every row is scoped to one callput bucket:
C: calls only. Raw nets and greeks are direct sums of the call-side contracts.P: puts only. Raw nets and greeks are direct sums of the put-side contracts.CP: pre-computed combined view. Nets (shares/premium/delta) areC − Pbecause bullish call flow and bearish put flow both express bullish conviction, so the nets combine sign-flipped. Greeks (gamma/vega) areC + Pbecause they are naturally signed by option type (calls +, puts −) and summing captures total book exposure.
Rolling windows PARTITION BY (figi, callput); each callput row has its own independent trailing 21dma and 2y baseline, so z(C) + z(P) ≠ z(CP). Filter to exactly one callput per query or triple-count.
Warm-up
All fields are computed from 2020-01-02 forward. The 21-day rolling sum needs 21 non-null daily nets; the z-score needs ≥ 63 non-null observations in the trailing 504-session (2-year) window and emits NULL until that threshold is met.
Transform chain: daily net → 21-day trailing sum (_21dma) → z-score against 2y rolling μ/σ of the 21dma (z_*).
Fire semantics live at the consumer
The signal table does not persist signal_* (2σ / 3σ fire) or hp_* (22-day holding-period) columns; derive them at query time from the z-scores. Masscrest's canonical spike predicate is:
WHERE z_net_i_delta_21dma > 2 AND callput = 'CP' -- 2σ institutional-delta spike
WHERE z_net_i_delta_21dma > 3 AND callput = 'CP' -- 3σ institutional-delta spike
Both retail (net_r_*) and institutional (net_i_*) transforms ship. By convention Masscrest treats large institutional-side deviations as the primary tradable spike; the retail-side z-scores are available for symmetric analysis (crowded-consensus vs smart-money-vs-retail divergence checks, see the crowding_tag in the taxonomy resource).
Adding liquidity and stock-return context
This table only carries the signal itself, not stock liquidity or stock returns. If you want to filter for liquid names (e.g. "ignore anything under $10M average daily dollar turnover") or overlay stock returns for validation, join px_01_day on (date, figi). Dollar turnover (turnover) can be averaged directly; for split-adjusted returns from close, also join split_factors.
Fields
| field_name | type | unit | grain | description | provenance | timing_lag | history_start | null_semantics | example |
|---|---|---|---|---|---|---|---|---|---|
date | Date | trading day (UTC) | (date, figi, callput) | Session date. US equity trading calendar. | exchange | T+1 | 2020-01-02 | never null | 2026-07-24 |
figi | String(12) | identifier | (date, figi, callput) | OpenFIGI composite FIGI for the underlying. Stable across ticker changes; join key to stock_metadata, px_01_day, split_factors. | exchange | n/a | 2020-01-02 | never null | BBG000MM2P62 |
underlying_ticker | String | ticker | (date, figi, callput) | Point-in-time listed equity ticker on date. Dotted dual-class form (BRK.B). Named underlying_ticker here rather than traded_underlying; the API SELECT aliases it back to traded_underlying on the wire. | exchange | T+1 | 2020-01-02 | never null | AAPL |
callput | LowCardinality(String) | enum | (date, figi, callput) | One of 'C', 'P', 'CP'. See the callput note above for the CP synthesis rule. | derived | T+1 | 2020-01-02 | never null | CP |
net_i_shares | Float64 | underlying-share equivalents | (date, figi, callput) | Institutional net share-equivalent flow for the callput bucket. Calculated as sum(net_i_qty × adj_shares_deliverable): the underlying-share equivalent of the traded contracts (standard OCC contract = 100 shares, adjusted for corporate actions). On callput='CP' rows: C − P (bullish-conviction sign convention). | model | T+1 | 2020-01-02 | 0.0 when no qualifying institutional flow | 18_450.0 |
net_r_shares | Float64 | underlying-share equivalents | (date, figi, callput) | Retail net share-equivalent flow. Same formula (sum(net_r_qty × adj_shares_deliverable)) and CP-synthesis rule as net_i_shares. | model | T+1 | 2020-01-02 | 0.0 when no qualifying retail flow | 4_120.0 |
net_i_premium | Float64 | USD | (date, figi, callput) | Institutional net dollar premium flow. On CP rows: C − P. | model | T+1 | 2020-01-02 | 0.0 when no qualifying institutional flow | 1_820_038.55 |
net_r_premium | Float64 | USD | (date, figi, callput) | Retail net dollar premium flow. | model | T+1 | 2020-01-02 | 0.0 when no qualifying retail flow | 312_040.0 |
net_i_delta | Float64 | USD | (date, figi, callput) | Institutional net flow as USD notional × delta. Naturally signed; positive = net long-delta demand. On CP rows: C − P. | model | T+1 | 2020-01-02 | 0.0 when no qualifying institutional flow | 12_530_000.00 |
net_r_delta | Float64 | USD | (date, figi, callput) | Retail net flow as USD notional × delta. | model | T+1 | 2020-01-02 | 0.0 when no qualifying retail flow | -870_000.00 |
net_i_gamma | Float64 | USD × gamma | (date, figi, callput) | Institutional net flow as USD notional × gamma. On CP rows: C + P (gamma is naturally signed by option type). Positive = net gamma demand. | model | T+1 | 2020-01-02 | 0.0 when no qualifying institutional flow | 84_000.0 |
net_r_gamma | Float64 | USD × gamma | (date, figi, callput) | Retail net gamma flow. | model | T+1 | 2020-01-02 | 0.0 when no qualifying retail flow | 12_100.0 |
net_i_vega | Float64 | USD × vega | (date, figi, callput) | Institutional net flow as USD notional × vega. On CP rows: C + P. Positive = net long-vol demand. | model | T+1 | 2020-01-02 | 0.0 when no qualifying institutional flow | 1_400_000.0 |
net_r_vega | Float64 | USD × vega | (date, figi, callput) | Retail net vega flow. | model | T+1 | 2020-01-02 | 0.0 when no qualifying retail flow | -210_000.0 |
net_i_shares_21dma | Float64 | underlying-share equivalents | (date, figi, callput) | Rolling sum of net_i_shares over the prior 21 trading days (inclusive of date), scoped to this callput. | derived | T+1 | 2020-01-02 | null when the trailing 21-day window has fewer than 21 non-null observations | 319_284.0 |
net_r_shares_21dma | Float64 | underlying-share equivalents | (date, figi, callput) | Rolling 21-day sum of net_r_shares. | derived | T+1 | 2020-01-02 | null when the trailing 21-day window has fewer than 21 non-null observations | 68_040.0 |
net_i_premium_21dma | Float64 | USD | (date, figi, callput) | Rolling 21-day sum of net_i_premium. | derived | T+1 | 2020-01-02 | null when the trailing 21-day window has fewer than 21 non-null observations | 25_294_500.0 |
net_r_premium_21dma | Float64 | USD | (date, figi, callput) | Rolling 21-day sum of net_r_premium. | derived | T+1 | 2020-01-02 | null when the trailing 21-day window has fewer than 21 non-null observations | 5_040_252.0 |
net_i_delta_21dma | Float64 | USD | (date, figi, callput) | Rolling 21-day sum of net_i_delta. | derived | T+1 | 2020-01-02 | null when the trailing 21-day window has fewer than 21 non-null observations | 206_220_000.0 |
net_r_delta_21dma | Float64 | USD | (date, figi, callput) | Rolling 21-day sum of net_r_delta. | derived | T+1 | 2020-01-02 | null when the trailing 21-day window has fewer than 21 non-null observations | -13_020_000.0 |
net_i_gamma_21dma | Float64 | USD × gamma | (date, figi, callput) | Rolling 21-day sum of net_i_gamma. | derived | T+1 | 2020-01-02 | null when the trailing 21-day window has fewer than 21 non-null observations | 1_512_000.0 |
net_r_gamma_21dma | Float64 | USD × gamma | (date, figi, callput) | Rolling 21-day sum of net_r_gamma. | derived | T+1 | 2020-01-02 | null when the trailing 21-day window has fewer than 21 non-null observations | 218_400.0 |
net_i_vega_21dma | Float64 | USD × vega | (date, figi, callput) | Rolling 21-day sum of net_i_vega. | derived | T+1 | 2020-01-02 | null when the trailing 21-day window has fewer than 21 non-null observations | 24_780_000.0 |
net_r_vega_21dma | Float64 | USD × vega | (date, figi, callput) | Rolling 21-day sum of net_r_vega. | derived | T+1 | 2020-01-02 | null when the trailing 21-day window has fewer than 21 non-null observations | -3_780_000.0 |
z_net_i_shares_21dma | Float64 | z-score | (date, figi, callput) | Z-score of net_i_shares_21dma against its trailing 2-year rolling mean and sample standard deviation, computed at query time. Rounded to 2 decimals on emit. | derived | T+1 | 2020-01-02 | null when the trailing 2y window has fewer than 63 non-null observations or its sample stddev is 0 | 1.34 |
z_net_r_shares_21dma | Float64 | z-score | (date, figi, callput) | Same construction as z_net_i_shares_21dma, applied to the retail 21dma. | derived | T+1 | 2020-01-02 | null when the trailing 2y window is unwarmed or its sample stddev is 0 | 0.42 |
z_net_i_premium_21dma | Float64 | z-score | (date, figi, callput) | Standardised institutional-premium 21dma vs its 2y baseline. | derived | T+1 | 2020-01-02 | null when the trailing 2y window is unwarmed or its sample stddev is 0 | 1.18 |
z_net_r_premium_21dma | Float64 | z-score | (date, figi, callput) | Standardised retail-premium 21dma vs its 2y baseline. | derived | T+1 | 2020-01-02 | null when the trailing 2y window is unwarmed or its sample stddev is 0 | -0.24 |
z_net_i_delta_21dma | Float64 | z-score | (date, figi, callput) | Standardised institutional-delta 21dma vs its 2y baseline. Masscrest's canonical "spike" predicate is z > 2 (2σ) or z > 3 (3σ) with callput = 'CP'. | derived | T+1 | 2020-01-02 | null when the trailing 2y window is unwarmed or its sample stddev is 0 | 2.08 |
z_net_r_delta_21dma | Float64 | z-score | (date, figi, callput) | Standardised retail-delta 21dma vs its 2y baseline. | derived | T+1 | 2020-01-02 | null when the trailing 2y window is unwarmed or its sample stddev is 0 | -0.55 |
z_net_i_gamma_21dma | Float64 | z-score | (date, figi, callput) | Standardised institutional-gamma 21dma vs its 2y baseline. | derived | T+1 | 2020-01-02 | null when the trailing 2y window is unwarmed or its sample stddev is 0 | 0.86 |
z_net_r_gamma_21dma | Float64 | z-score | (date, figi, callput) | Standardised retail-gamma 21dma vs its 2y baseline. | derived | T+1 | 2020-01-02 | null when the trailing 2y window is unwarmed or its sample stddev is 0 | 0.11 |
z_net_i_vega_21dma | Float64 | z-score | (date, figi, callput) | Standardised institutional-vega 21dma vs its 2y baseline. Masscrest's ≤ −3σ vega tail is historically followed by ~1.6 vol-point IV declines over 21 days (see research/vega-iv-signal). | derived | T+1 | 2020-01-02 | null when the trailing 2y window is unwarmed or its sample stddev is 0 | -1.42 |
z_net_r_vega_21dma | Float64 | z-score | (date, figi, callput) | Standardised retail-vega 21dma vs its 2y baseline. | derived | T+1 | 2020-01-02 | null when the trailing 2y window is unwarmed or its sample stddev is 0 | 0.30 |
Z-score precision
z_* fields are rounded to 2 decimals on emit. When comparing a client-side derived spike predicate (z > 2) against the rounded value, expect edge cases on low-vol names where the true unrounded z sits just under 2.00 but the rounded value equals 2.00.
CP synthesis is pre-computed, not query-time
The 'CP' rows are materialised at publish time, not derived at query time. Each (figi, callput) bucket has its own independent 21dma and 2y baseline trajectory; z_net_i_delta_21dma on the CP row is derived from CP's own trailing series, not from summing per-side z-scores.
Deriving fire flags and holding periods
The table does not persist pre-computed fire flags (e.g. "2σ spike today = TRUE") or holding-period booleans. Compute them at query time from the z-scores: WHERE z_net_i_delta_21dma > 2 AND callput = 'CP' for the canonical 2σ institutional-delta spike. For a 22-day holding-period rule (fire within the last N days and the same z has not gone negative since), a self-join or a rolling max(z) window on the same series is enough.
grouped_flow_signal_01_day
Group-level daily flow-signal derivatives: sector / industry / etf / adr / single_stock / all rollups of the underlying-level nets and greeks aggregated in underlying_flow_signal_01_day. Same 50-flow-metric shape across 5 layers × 10 metrics. Per-(date, group_key, callput) grain.
- Grain:
(date, group_key, callput) - History: 2020-01-02 →
- Timing: T+1 (published shortly after
underlying_flow_signal_01_dayon the option-analytics workflow, typically 06:00-11:00 UTC on the calendar day after the trading date — Friday's data lands Saturday).
Response-shape rewrite (2026-08-14)
Every row is keyed by a single group_key STRING column. group_type on the REST endpoint takes the same set of canonical values (case-insensitive on input) — a mixed-case sector name (e.g. "Communication Services"), a mixed-case industry name (e.g. "Semiconductors"), or one of the rollup literals "etf" / "adr" / "single_stock" / "all". The row echoes that value back in group_key.
Group semantics
Query group_type | group_key shape (on the row) | Row count per (date, callput) | Notes |
|---|---|---|---|
sector | Canonical mixed-case sector name (e.g. Technology, Financial Services) | ~11 distinct values | Excludes ETFs and ADRs. Figis missing a sector label drop from these rows. |
industry | Canonical mixed-case industry name (e.g. Semiconductors, Software - Application) | ~150 distinct values (matches the FMP industry taxonomy) | Excludes ETFs and ADRs. Same drop-on-missing rule. Every industry-day is emitted (gap-free time series) with n_figi populated for downstream filtering — see "Thin-industry handling" below. |
etf | Literal string etf | 1 | Aggregate over all figis with isEtf='true' in the latest-known phase (live or delisted). |
adr | Literal string adr | 1 | Aggregate over all figis with isAdr='true' in the latest-known phase (live or delisted). |
single_stock | Literal string single_stock | 1 | Everything else (non-ETF, non-ADR). Figis missing from stock_metadata are treated as single_stock. |
all | Literal string all | 1 | Every figi in the flow universe, no filter. |
Why sector / industry exclude ETFs and ADRs
FMP tags each ETF's sector with the issuer's legal-entity sector (typically Financial Services for the sponsor, not the underlying-exposure sector). Pooling ETFs into sector rollups inflated Financial Services gross flow by 85%+ — meaningless for cohort analysis. Same-shape distortion for ADRs. The 2026-08-11 pipeline change excludes both from sector and industry aggregations; they get their own top-level etf and adr branches. As a consequence, sum(sector) ≠ all — the residual is precisely the etf + adr contribution.
Valid sector values
The ~11 distinct group_key strings emitted when group_type = 'sector'. Case-insensitive on input; canonical mixed-case on the wire. As-of 2026-08-14 snapshot; may drift as figis are reclassified or new sectors are added.
| Sector | Description |
|---|---|
Basic Materials | Companies extracting and processing raw commodities used across the economy: metals and mining, chemicals, forestry, and construction materials. Cyclically exposed to global industrial demand. |
Communication Services | Firms that carry information or entertainment to end users: telecom carriers, media conglomerates, interactive-media platforms, publishers, and gaming. Combines legacy telecom with digital-native content. |
Consumer Cyclical | Businesses selling discretionary goods and services whose demand rises and falls with the business cycle: automakers, apparel, restaurants, travel, leisure, and specialty retail. Highly sensitive to consumer confidence. |
Consumer Defensive | Producers of everyday essentials that consumers buy regardless of the economy: packaged food, beverages, tobacco, household staples, and discount retailers. Stable revenue through downturns. |
Energy | The oil, gas, coal and related supply chain: exploration and production, refining, midstream infrastructure, and oilfield services. Tied to commodity prices and global demand cycles. |
Financial Services | Firms that intermediate capital: banks, insurers, asset managers, brokerages, exchanges, and credit-services companies. Rate-sensitive and cycle-exposed. |
Healthcare | Businesses across the health value chain: drug and biotech developers, medical-device makers, diagnostics labs, healthcare providers, health insurers, and pharma distributors. Mix of defensive demand and secular growth. |
Industrials | Capital goods and services that keep the economy moving: aerospace, defence, machinery, transportation, construction, and logistics. Cyclically exposed to capex spending. |
Real Estate | Property-owning and property-servicing companies, dominated by REITs across residential, retail, office, industrial, healthcare, and specialty sub-types. Highly interest-rate-sensitive. |
Technology | Hardware and software firms including semiconductors, application and infrastructure software, IT services, computer hardware, and consumer electronics. Growth-biased, with high cyclicality on the semiconductor side. |
Utilities | Regulated and independent providers of electricity, natural gas, water, and renewable power. Defensive cash flows, bond-like return profile. |
Valid industry values
The ~150 distinct group_key strings emitted when group_type = 'industry'. Case-insensitive on input; canonical mixed-case on the wire. As-of 2026-08-14 snapshot; may drift as existing figis are reclassified or new industries are added. For the live authoritative list, call the grouped-flow-signal endpoint with group_type=industry and take the distinct group_key values from the response.
Every industry with any flow on a given date is emitted (2026-08-28 revision — the time series is gap-free). Every industry-day carries populated raw daily nets AND populated rolling / z fields; n_figi is exposed on the row so consumers can filter thin-breadth days at query time. See "Thin-industry handling" below for the z-magnitude comparability caveat on structurally-thin industries such as Copper, Uranium, Consulting Services, Regulated Water, Conglomerates, Waste Management, and Railroads.
| Industry | Description |
|---|---|
Advertising Agencies | Agencies that plan, create and place advertising across traditional and digital channels for brand and direct-response clients. |
Aerospace & Defense | Manufacturers of civil aircraft, military platforms, missiles, satellites and defence-electronics systems for governments and commercial airlines. |
Agricultural - Machinery | Producers of tractors, combines, harvesters and other equipment used in commercial farming. |
Agricultural Farm Products | Growers, processors and marketers of grains, oilseeds, produce, meat and other primary agricultural output. |
Agricultural Inputs | Suppliers of seeds, fertilisers, pesticides and other inputs consumed by farms. |
Airlines, Airports & Air Services | Passenger and cargo airlines, airport operators, ground-handling firms and other air-transport service providers. |
Aluminum | Miners, smelters and rolled-product manufacturers of aluminium. |
Apparel - Footwear & Accessories | Designers and makers of shoes, handbags, jewellery, watches and other fashion accessories. |
Apparel - Manufacturers | Companies that design and produce clothing lines under owned or licensed brands. |
Apparel - Retail | Retailers selling clothing and accessories through stores or online, including specialty and off-price chains. |
Asset Management | Firms managing pooled investment vehicles (mutual funds, ETFs, separate accounts) across broad multi-asset strategies. |
Asset Management - Bonds | Managers specialising in fixed-income mutual funds and bond ETFs. |
Asset Management - Cryptocurrency | Managers of cryptocurrency-linked funds, trusts and ETFs. |
Asset Management - Global | Managers of internationally-diversified equity and multi-asset funds. |
Asset Management - Income | Managers focused on dividend-equity and income-oriented fund products. |
Asset Management - Leveraged | Sponsors of leveraged and inverse ETFs. |
Auto - Dealerships | Retailers of new and used vehicles, plus related service, parts and financing operations. |
Auto - Manufacturers | OEMs producing passenger cars, trucks and, increasingly, electric vehicles. |
Auto - Parts | Suppliers of components, systems and modules used in vehicle assembly and aftermarket repair. |
Auto - Recreational Vehicles | Makers of RVs, motorcycles, boats and other personal-use motorised recreational vehicles. |
Banks - Diversified | Large multi-line banks combining consumer, commercial, investment-banking and wealth divisions. |
Banks - Regional | Banks concentrated in a specific geographic footprint, focused on retail deposits and commercial lending. |
Beverages - Alcoholic | Brewers, distillers and vintners producing beer, spirits and packaged alcoholic drinks at scale. |
Beverages - Non-Alcoholic | Producers of soft drinks, bottled water, juices, energy drinks and other non-alcoholic packaged beverages. |
Beverages - Wineries & Distilleries | Craft and specialty wine and spirits producers, generally smaller-scale than the mass-market alcoholic-beverage majors. |
Biotechnology | Companies developing novel therapeutics using biological processes, typically pre-commercial or single-product-focused. |
Broadcasting | Owners of TV and radio stations, local networks and syndicated content distributors. |
Business Equipment & Supplies | Manufacturers of office equipment, printers, copiers and workplace supplies. |
Chemicals | Producers of commodity petrochemicals, plastics, industrial gases and basic chemical intermediates. |
Chemicals - Specialty | Producers of higher-value differentiated chemicals used in coatings, adhesives, catalysts and formulations. |
Coal | Miners and marketers of thermal and metallurgical coal. |
Communication Equipment | Makers of network hardware, routers, switches and telecom infrastructure gear. |
Computer Hardware | Manufacturers of PCs, servers, storage systems and other computing hardware. |
Conglomerates | Multi-industry holding companies spanning several unrelated business lines. |
Construction | General contractors and construction firms building commercial, industrial and infrastructure projects. |
Construction Materials | Producers of cement, aggregates, gypsum, insulation and other bulk building materials. |
Consulting Services | Management, technology, HR and strategy consulting firms selling professional advisory services. |
Consumer Electronics | Makers of smartphones, tablets, audio devices, wearables and other consumer-facing electronic products. |
Copper | Miners and processors of copper ore and refined copper products. |
Department Stores | Multi-category retailers under a single store format spanning apparel, home and accessories. |
Discount Stores | Mass-market retailers competing primarily on price across broad general merchandise. |
Diversified Utilities | Utilities operating across multiple regulated categories (electric, gas, water) rather than a single service. |
Drug Manufacturers - General | Large pharmaceutical companies with broad marketed portfolios and multi-therapeutic pipelines. |
Drug Manufacturers - Specialty & Generic | Pharma companies focused on generic drugs, biosimilars or niche specialty therapeutic areas. |
Education & Training Services | For-profit universities, career schools, tutoring and corporate training providers. |
Electrical Equipment & Parts | Manufacturers of electrical components, motors, transformers, cables and industrial electrical systems. |
Electronic Gaming & Multimedia | Video-game publishers, developers, esports operators and interactive-entertainment firms. |
Engineering & Construction | Firms providing engineering-design and heavy-construction services for large infrastructure projects. |
Entertainment | Film, TV and content-production studios and integrated entertainment companies. |
Environmental Services | Waste-water treatment, environmental consulting and remediation service providers. |
Financial - Capital Markets | Investment banks, broker-dealers and trading firms operating in equity, fixed-income and derivatives markets. |
Financial - Conglomerates | Diversified financial holding companies spanning several finance subsectors. |
Financial - Credit Services | Consumer-finance companies, credit-card networks, payment processors and buy-now-pay-later providers. |
Financial - Data & Stock Exchanges | Exchange operators, index providers, financial-data vendors and market-infrastructure firms. |
Financial - Diversified | Miscellaneous financial-services companies that do not fit the more specific finance subsectors. |
Financial - Mortgages | Mortgage originators, servicers and secondary-market intermediaries. |
Food Confectioners | Producers of chocolate, candy, chewing gum and other confectionery products. |
Food Distribution | Wholesalers distributing food and related goods to restaurants, retailers and institutional customers. |
Furnishings, Fixtures & Appliances | Makers of home furniture, bedding, kitchen appliances and household fixtures. |
Gambling, Resorts & Casinos | Operators of casinos, integrated resorts and online-gambling platforms. |
General Transportation | Diversified transportation companies that do not fit the more specific rail, trucking or air subsectors. |
Gold | Miners and refiners of gold ore and physical gold, plus gold-focused streaming and royalty firms. |
Grocery Stores | Traditional supermarkets and grocery chains selling food and household goods. |
Hardware, Equipment & Parts | General hardware and industrial-equipment manufacturers and distributors. |
Home Improvement | Big-box home-improvement retailers and specialty tool, paint and hardware chains. |
Household & Personal Products | Manufacturers of cleaning products, personal-care items and consumer packaged household goods. |
Independent Power Producers | Non-utility power generators selling electricity into wholesale or contracted markets. |
Industrial - Distribution | Wholesalers of industrial equipment, parts, fasteners and MRO supplies. |
Industrial - Infrastructure Operations | Operators of ports, pipelines, terminals and other industrial-infrastructure assets. |
Industrial - Machinery | Manufacturers of heavy machinery for construction, mining, agriculture and industrial processes. |
Industrial - Pollution & Treatment Controls | Providers of air, water and industrial pollution-control equipment and services. |
Industrial - Specialties | Specialty industrial firms in niche categories that do not fit broader industrial subsectors. |
Industrial Materials | Producers of steel-alternatives, industrial ceramics, composites and other engineered materials. |
Information Technology Services | IT-consulting, systems-integration, outsourcing and managed-services firms. |
Insurance - Brokers | Insurance and reinsurance brokers acting as intermediaries between clients and underwriters. |
Insurance - Diversified | Multi-line insurers writing across life, P&C and other coverage types. |
Insurance - Life | Insurers focused on individual and group life insurance, plus annuity products. |
Insurance - Property & Casualty | Insurers writing property, auto, liability and other short-tail coverage. |
Insurance - Reinsurance | Firms providing insurance to primary insurers to cover concentrated or catastrophic risk. |
Insurance - Specialty | Insurers focused on niche or hard-to-place risks (marine, aviation, cyber, professional liability). |
Integrated Freight & Logistics | Multi-modal freight and logistics operators spanning trucking, rail, air and ocean. |
Internet Content & Information | Digital-content platforms, search engines, social networks and online-information providers. |
Investment - Banking & Investment Services | Full-service investment banks and firms providing M&A, underwriting and advisory services. |
Leisure | Manufacturers of leisure goods, hobby products, toys and personal-recreation equipment. |
Luxury Goods | Producers of high-end fashion, jewellery, watches, leather goods and other luxury consumer categories. |
Manufacturing - Metal Fabrication | Firms fabricating metal parts, structures and assemblies for industrial and consumer use. |
Manufacturing - Miscellaneous | Diversified manufacturers that do not fit more specific industrial subsectors. |
Manufacturing - Textiles | Producers of yarn, fabric and finished textiles for apparel and industrial applications. |
Manufacturing - Tools & Accessories | Makers of power tools, hand tools and related industrial and consumer tool accessories. |
Marine Shipping | Ocean-freight carriers operating tankers, dry-bulk vessels and container ships. |
Media & Entertainment | Diversified media conglomerates spanning television, film, publishing and digital content. |
Medical - Care Facilities | Hospital operators, nursing-home chains and specialty care-facility providers. |
Medical - Devices | Manufacturers of medical implants, surgical tools, monitoring and therapeutic devices. |
Medical - Diagnostics & Research | Clinical-diagnostics labs, life-science research tools and diagnostic-imaging providers. |
Medical - Distribution | Wholesale distributors of drugs, medical supplies and healthcare products. |
Medical - Equipment & Services | Providers of medical equipment plus related installation, maintenance and services. |
Medical - Healthcare Information Services | Health-IT firms providing electronic health records, clinical software and data-analytics platforms. |
Medical - Healthcare Plans | Managed-care organisations and health-insurance plans covering employer, individual and government populations. |
Medical - Instruments & Supplies | Manufacturers of medical instruments, consumables and disposable healthcare supplies. |
Medical - Pharmaceuticals | Broadly-focused pharmaceutical companies not classified under the more specific drug-manufacturer subsectors. |
Medical - Specialties | Specialty medical companies operating in niche healthcare categories. |
Oil & Gas Drilling | Contract drilling firms operating onshore and offshore rigs for oil-and-gas producers. |
Oil & Gas Energy | Diversified oil-and-gas firms that do not fit the more specific upstream, midstream or downstream categories. |
Oil & Gas Equipment & Services | Oilfield-services providers offering drilling, completion and reservoir-management equipment and expertise. |
Oil & Gas Exploration & Production | Upstream producers exploring for and producing crude oil and natural gas. |
Oil & Gas Integrated | Integrated majors operating across upstream, midstream and downstream oil-and-gas businesses. |
Oil & Gas Midstream | Pipelines, storage terminals and processing operators moving oil and gas from wellhead to market. |
Oil & Gas Refining & Marketing | Downstream refiners and fuel-marketing companies converting crude into gasoline, diesel and petrochemical feedstocks. |
Other Precious Metals | Miners of platinum, palladium and other precious metals not classified under gold or silver. |
Packaged Foods | Producers of branded packaged and processed foods sold through retail and foodservice channels. |
Packaging & Containers | Manufacturers of paper, plastic, glass and metal packaging for consumer and industrial products. |
Paper, Lumber & Forest Products | Producers of pulp, paper, lumber and other wood-based industrial and consumer products. |
Personal Products & Services | Personal-care product makers, beauty firms and personal-services businesses. |
Publishing | Publishers of books, newspapers, magazines and other periodical content in print and digital. |
REIT - Diversified | REITs owning property portfolios spanning multiple real-estate categories. |
REIT - Healthcare Facilities | REITs owning hospitals, medical-office buildings, senior housing and other healthcare properties. |
REIT - Hotel & Motel | REITs owning hotel, motel and hospitality properties. |
REIT - Industrial | REITs owning warehouses, logistics facilities and light-industrial properties. |
REIT - Mortgage | Mortgage REITs earning spread on residential and commercial mortgage assets rather than owning property directly. |
REIT - Office | REITs owning office buildings across urban and suburban markets. |
REIT - Residential | REITs owning apartment buildings, single-family rentals and manufactured-home communities. |
REIT - Retail | REITs owning shopping malls, strip centres and standalone retail properties. |
REIT - Specialty | REITs owning niche property types such as data centres, cell towers, self-storage and infrastructure. |
Railroads | Class I and short-line freight-rail operators plus passenger-rail companies. |
Real Estate - Development | Property developers building residential, commercial and mixed-use projects for sale or lease. |
Real Estate - Diversified | Diversified real-estate operating companies not structured as REITs. |
Real Estate - Services | Real-estate brokerages, property-management firms and title-and-appraisal services. |
Regulated Electric | Rate-regulated electric utilities serving retail customers in defined service territories. |
Regulated Gas | Rate-regulated natural-gas distribution utilities. |
Regulated Water | Rate-regulated water and wastewater utilities. |
Renewable Utilities | Utilities and power generators focused on solar, wind, hydro and other renewable-energy assets. |
Rental & Leasing Services | Firms renting equipment, vehicles and other assets to industrial and consumer customers. |
Residential Construction | Homebuilders constructing single-family homes and residential communities for sale. |
Restaurants | Restaurant operators and franchisors across quick-service, casual-dining and fine-dining categories. |
Security & Protection Services | Providers of guarding, cash-in-transit, alarm-monitoring and security-technology services. |
Semiconductors | Designers and manufacturers of integrated circuits, memory, logic chips and related semiconductor equipment. |
Shell Companies | Publicly-listed holding entities without significant operations, often SPACs or blank-check vehicles. |
Silver | Miners and refiners of silver ore and silver products. |
Software - Application | Vendors of packaged and SaaS application software for business, industry-vertical and consumer use. |
Software - Infrastructure | Vendors of infrastructure software including databases, operating systems, security and developer tools. |
Software - Services | Software-enabled services firms delivering platform-hosted business solutions. |
Solar | Manufacturers of solar panels, inverters and installers of solar-power systems. |
Specialty Business Services | Business-services firms in specialty categories (data processing, marketing services, testing, inspection). |
Specialty Retail | Retailers focused on specific product categories such as electronics, sporting goods, jewellery or auto parts. |
Staffing & Employment Services | Temporary-staffing, executive-search and human-capital-management firms. |
Steel | Integrated and mini-mill producers of carbon and specialty steel products. |
Technology Distributors | Distributors of IT hardware, software and networking products to resellers and enterprise buyers. |
Telecommunications Services | Wireless and wireline telecom carriers providing voice and data services to consumers and businesses. |
Tobacco | Cigarette manufacturers plus producers of cigars, smokeless tobacco and next-generation nicotine products. |
Travel Lodging | Hotel and lodging operators and franchisors across the value, mid-scale and luxury segments. |
Travel Services | Online travel agencies, tour operators and travel-booking platforms. |
Trucking | Long-haul and less-than-truckload freight-trucking companies. |
Uranium | Miners of uranium ore and producers of nuclear-fuel feedstock. |
Waste Management | Solid-waste collection, disposal, recycling and hazardous-waste management firms. |
Signal formula
_21dma= 21-trading-day rolling SUM of the raw group-level net, PARTITION BY(group_key, callput). (Historically shipped as a rolling mean; arithmetically equivalent for the z-score, since the sum is just the mean multiplied by 21. The distributed series is now the sum.)z_net_*_21dma= z-score of_21dmaagainst its 2-year (504 trading day) trailing mean and sample standard deviation, computed at query time. Minimum 63 non-null observations in the trailing window required, else null. Rounded to 2 decimals on emit.
The raw rolling μ and σ series are computed on the fly at query time and are not distributed as separate columns — only the resulting z-score ships.
Every industry-day is emitted with populated rolling / z fields. The 21dma and 2y baseline include ALL days regardless of n_figi — thin days contribute their (smaller) raw values to the trailing window, so each industry's z is calibrated against its own historical breadth mix and populates on every day. Cross-industry z magnitudes aren't directly comparable when breadth profiles differ meaningfully — filter on n_figi at query time if comparability matters. See "Thin-industry handling" below.
Aggregate identities
single_stock + etf + adr = allper (date, callput), 0 residual.sum(sector) ≈ single_stockper (date, callput); small residual (< 1% of gross flow) attributable to single-stock figis without a sector label.- Because sector / industry exclude ETFs and ADRs,
sum(sector) ≠ all— the difference is precisely theetf + adrgross flow. Historical rollups produced before 2026-08-11 rolled ETFs+ADRs into sector; those runs have been superseded. sum(industry) ≈ single_stockper (date, callput). Every industry row (thin or full-breadth) contributes its raw flow to the sum, so this identity holds tighter than it did before 2026-08-28.
Thin-industry handling
Every group with any flow on a given date is emitted — the time series is gap-free. Every row (thin or full-breadth) carries populated raw daily nets AND populated rolling / z fields:
n_figiis populated with the honest constituent count (visible in the response) — consumers filter thin-breadth days at query time.- Raw daily nets (
net_i_shares,net_r_shares, …,net_r_vega) are populated with the actual group sum. - Rolling / derived columns (
_21dma,z_*) are populated on every row. The 21dma and 2y baseline include ALL days regardless ofn_figi— thin days contribute their (smaller) raw values to the trailing window and to the 2y μ/σ used to z-score. Each industry's z-score is therefore calibrated against its own historical breadth mix — a chronically-thin industry's baseline is set to its own thin-day scale, so z fires when flow is unusually large for that industry. Cross-industry z magnitudes aren't directly comparable when breadth profiles differ meaningfully (a +2σ on a 5-FIGI industry is not directly comparable to a +2σ on a 50-FIGI industry). Filter onn_figiat query time when magnitude comparability matters.
Sector, etf, adr, single_stock, and all branches always exceed 10 contributing FIGIs so the caveat is a no-op for those branches. Only industries — historically ~46 including Copper, Uranium, Consulting Services, Regulated Water, Conglomerates, Waste Management, Railroads — are materially affected. Before 2026-08-28 those industries were dropped entirely and visible as gaps in the served time series; now they emit continuous rows with populated raw flow AND populated (but caveated) z-scores. Live coverage: 11 sectors + ~150 industries + 4 rollups (all, etf, adr, single_stock) — every group with flow that day appears in the cross-section.
Classification is not strictly PIT
The underlying flow data is point-in-time, but each figi's sector, industry, and ETF / ADR classification uses the most recent labelling rather than the label in force at the time. META, for example, rolls up under Communication Services for its entire history even though it was classified as Technology in 2019. This keeps historical rollups comparable under a single consistent scheme as companies drift between sectors over time.
callput semantics
Every row is scoped to one callput bucket. C = calls only, P = puts only, CP = pre-computed combined view (nets are C − P because bullish call flow and bearish put flow both express bullish conviction, so nets combine sign-flipped; greeks are C + P because they are naturally signed by option type). Rolling windows partition by (group_key, callput); each callput row has its own independent trailing 21dma and 2y baseline, so z(C) + z(P) ≠ z(CP). Filter to exactly one callput per query or triple-count.
Warmup NULL conventions
..._21dmaNULL when a(group_key, callput)has < 21 days of history in the trailing 21-row window.z_..._21dmaNULL when the 21dma series has < 63 non-null observations in the trailing 504-session (2-year) window, or the window's sample stddev is 0.- These are legitimate NULLs; do not fill.
REST endpoints
GET /v0/grouped_flow_signal/01_day: ranged. Requiresgroup_type= a single canonicalgroup_keyvalue (sector / industry name or one of the rollup literalsetf/adr/single_stock/all; case-insensitive on input, fuzzy-suggestion on unknown values). Returns rows for a date range at that one key.GET /v0/grouped_flow_signal/01_day/snapshot: single-day cross-sectional. All filters optional.datedefaults to latest. Omit bothcategoryandgroup_type→ everygroup_keywith any flow on the day (up to ~168 rows on the defaultcallput = 'CP').category(snapshot-only:industry/sector/rollup/all) narrows to a whole family in one call.group_type(single canonicalgroup_keyvalue) narrows to one key.categoryandgroup_typeare mutually exclusive.
Fields
| field_name | type | unit | grain | description | provenance | timing_lag | history_start | null_semantics | example |
|---|---|---|---|---|---|---|---|---|---|
date | Date | trading day (UTC) | (date, group_key, callput) | Session date. US equity trading calendar. | exchange | T+1 | 2020-01-02 | never null | 2026-07-24 |
group_key | LowCardinality(String) | text | key | Canonical mixed-case sector or industry name (e.g. Communication Services, Semiconductors); or the literal etf / adr / single_stock / all for the rollup branches. Single key column — the same value you pass in the REST group_type query parameter. | derived | T+1 | 2020-01-02 | never null | Technology |
callput | LowCardinality(String) | enum | key | One of C, P, CP. See the callput note above. | derived | T+1 | 2020-01-02 | never null | CP |
n_figi | Nullable(Int64) | count | (date, group_key, callput) | Number of distinct FIGIs contributing to this group-day. Every row is emitted with raw nets AND rolling / z fields populated; the 21dma and 2y baseline include all days regardless of n_figi, so each industry's z is calibrated against its own historical breadth mix. Consumers filter on n_figi at query time when z-magnitude comparability across breadth matters. Sector, etf, adr, single_stock, and all branches always carry n_figi >> 10; only certain industries can dip below. | derived | T+1 | 2020-01-02 | never null in practice | 24 |
net_i_shares | Float64 | delta-adjusted share equivalents | (date, group_key, callput) | Institutional net share-equivalent flow, summed across every figi in this grouping. On CP rows: C − P (bullish-conviction sign convention). Populated on every emitted row (even n_figi < 10 days). | model | T+1 | 2020-01-02 | 0.0 when no qualifying institutional flow | 1_820_000.0 |
net_r_shares | Float64 | delta-adjusted share equivalents | (date, group_key, callput) | Retail net share-equivalent flow, same CP-synthesis rule. | model | T+1 | 2020-01-02 | 0.0 when no qualifying retail flow | 412_000.0 |
net_i_premium | Float64 | USD | (date, group_key, callput) | Institutional net dollar premium flow. | model | T+1 | 2020-01-02 | 0.0 when no qualifying institutional flow | 182_000_000.0 |
net_r_premium | Float64 | USD | (date, group_key, callput) | Retail net dollar premium flow. | model | T+1 | 2020-01-02 | 0.0 when no qualifying retail flow | 31_000_000.0 |
net_i_delta | Float64 | USD | (date, group_key, callput) | Institutional net USD × delta flow. Positive = net long-delta demand across the grouping. | model | T+1 | 2020-01-02 | 0.0 when no qualifying institutional flow | 1_250_000_000.0 |
net_r_delta | Float64 | USD | (date, group_key, callput) | Retail net USD × delta flow. | model | T+1 | 2020-01-02 | 0.0 when no qualifying retail flow | -87_000_000.0 |
net_i_gamma | Float64 | USD × gamma | (date, group_key, callput) | Institutional net USD × gamma. On CP rows: C + P. | model | T+1 | 2020-01-02 | 0.0 when no qualifying institutional flow | 8_400_000.0 |
net_r_gamma | Float64 | USD × gamma | (date, group_key, callput) | Retail net USD × gamma. | model | T+1 | 2020-01-02 | 0.0 when no qualifying retail flow | 1_210_000.0 |
net_i_vega | Float64 | USD × vega | (date, group_key, callput) | Institutional net USD × vega. On CP rows: C + P. Positive = net long-vol demand across the grouping. | model | T+1 | 2020-01-02 | 0.0 when no qualifying institutional flow | 140_000_000.0 |
net_r_vega | Float64 | USD × vega | (date, group_key, callput) | Retail net USD × vega. | model | T+1 | 2020-01-02 | 0.0 when no qualifying retail flow | -21_000_000.0 |
net_*_21dma | Float64 | (matches base metric) | (date, group_key, callput) | 21-trading-day rolling SUM of the corresponding raw net, scoped to this (group_key, callput). Ten of these, one per raw metric. | derived | T+1 | 2020-01-02 | null when the trailing 21-day window has fewer than 21 non-null observations | (varies by metric) |
z_net_*_21dma | Float64 | z-score | (date, group_key, callput) | Z-score of the corresponding 21dma against its trailing 2-year (504-session) rolling mean and sample standard deviation, computed at query time. Rounded to 2 decimals on emit. Masscrest's canonical spike predicate for the group-level table is z_net_i_delta_21dma > 2 AND callput = 'CP' (or > 3 for 3σ), same rule as the underlying-level table. Ten of these. | derived | T+1 | 2020-01-02 | null when the trailing 2y window is unwarmed or its sample stddev is 0 | (varies) |
CP synthesis is pre-computed, not query-time
Same rule as underlying_flow_signal_01_day: the 'CP' rows are materialised at publish time, and each (group_key, callput) bucket has its own independent 21dma and 2y baseline trajectory.
Group classification is snapshot-only
Load-bearing, worth repeating: the sector / industry / etf / adr / single_stock labels used to route flow into each row come from each figi's latest-known stock_metadata phase (current phase for live names, last-live phase for delisted names) applied across every historical date. Do NOT use this table for PIT backtests where a stock's historical group membership matters; use underlying_flow_signal_01_day and roll up client-side.
px_01_day
Daily close (unadjusted) for the covered US single-stock and ETF universe, keyed on FIGI.
Access: this table is not directly queryable via the MCP or REST API. Split-adjusted price columns (adj_close, adj_open, adj_volume, total_turnover) are returned as LEFT-JOIN columns on get_underlying_option_flows_daily (MCP) and GET /v0/underlying_option_flows/01_day (REST). Use those endpoints for daily price context — passing traded_underlying=<TICKER> and callput='CP' returns one row per date with prices attached to the flow payload. For bulk historical pulls, the parquet flat-file surface is at gs://prod-masscrest/v0/px_data/01_day/.
- Grain:
(date, figi, symbol)[1] - History: 2020-01-02 →
- Timing: T+1 (published between 05:00 and 09:00 UTC on the calendar day after the trading date — Friday's data lands Saturday)
[1] The underlying storage carries symbol to preserve point-in-time ticker context, but every join to Masscrest surfaces should use figi.
Fields
| field_name | type | unit | grain | description | provenance | timing_lag | history_start | null_semantics | example |
|---|---|---|---|---|---|---|---|---|---|
date | Date | trading day (UTC) | (date, figi) | Session date. US equity trading calendar. | exchange | T+1 | 2020-01-02 | never null | 2026-07-24 |
figi | String(12) | identifier | (date, figi) | OpenFIGI composite FIGI for the underlying. Stable across ticker changes; join key to every other Masscrest table. | exchange | n/a | 2020-01-02 | never null | BBG000MM2P62 |
symbol | String | ticker | (date, figi) | Point-in-time listed ticker on date. Dotted dual-class form (BRK.B). Preserved for readability; do not use as a join key (the same ticker can be recycled across entities over time). | exchange | T+1 | 2020-01-02 | never null | AAPL |
open | Float64 | USD | (date, figi) | Session opening print (unadjusted, contemporaneous). No split adjustment applied. | exchange | T+1 | 2020-01-02 | null on non-trading days for the underlying (delistings, halts) | 223.85 |
close | Float64 | USD | (date, figi) | Session closing print (unadjusted, contemporaneous). No split adjustment applied. | exchange | T+1 | 2020-01-02 | null on non-trading days for the underlying | 224.31 |
volume | Float64 | shares | (date, figi) | Session share volume (unadjusted, contemporaneous). No split adjustment applied (a share count on a pre-split day is a real economic quantity that doesn't rescale post-split). | exchange | T+1 | 2020-01-02 | null on non-trading days | 52_308_400.0 |
turnover | Float64 | USD | (date, figi) | Dollar turnover of the underlying on date (sum(price × volume) across all intraday prints). Dollar amounts are unit-invariant across splits. | exchange | T+1 | 2020-01-02 | null on non-trading days | 11_724_390_012.0 |
Unadjusted semantics
Prices and volume in this table are unadjusted (contemporaneous). To compute split-adjusted series (safe returns across split events, share-count normalisation, historical strike comparisons), join to split_factors on figi where date BETWEEN valid_from AND valid_to and apply cum_split_factor per the reconstruction snippet in the flat-files section. The split is deliberate: it lets you reload px_01_day and split_factors independently, and gives you an explicit knob when you need to invert an adjustment.
px_10_min
10-minute OHLCV bars (unadjusted) for the covered US single-stock and ETF universe, keyed on FIGI. Same underlying universe and FIGI join key as px_01_day.
Access: this table is not directly queryable via the MCP or REST API. Split-adjusted price columns (adj_close, adj_open, adj_volume, total_turnover) are returned as LEFT-JOIN columns on get_underlying_option_flows_10min (MCP), intraday_flow_day (MCP fat tool for a single symbol × single day), and GET /v0/underlying_option_flows/10_min (REST). Use those endpoints for intraday price context — the LEFT-join emits one row per (date, ten_min_timeframe, figi) with prices attached to the flow payload. For bulk historical pulls, the parquet flat-file surface is at gs://prod-masscrest/v0/px_data/10_min/.
- Grain:
(date, ten_min_timeframe, figi, symbol) - History: 2020-01-02 →
- Timing: T+1 (published between 05:00 and 09:00 UTC on the calendar day after the trading date — Friday's data lands Saturday)
Bucket boundary convention
ten_min_timeframe is the end of the 10-minute bucket, in New York wall-clock time stored as a naive DateTime. Bucket covers (ten_min_timeframe − 10 min, ten_min_timeframe]. First RTH bucket ends at 09:40:00, last at 16:00:00 (39 buckets per full session). On-boundary 1-minute bars (e.g. 10:00:00 close) land in the closing bucket, not the opening bucket of the next.
Coverage
Regular trading hours only (09:30–16:00 ET). No pre-market, no after-hours. Halted sessions produce no rows for the halted intervals.
Fields
| field_name | type | unit | grain | description | provenance | timing_lag | history_start | null_semantics | example |
|---|---|---|---|---|---|---|---|---|---|
ten_min_timeframe | DateTime | NY wall-clock, bucket close | (date, ten_min_timeframe, figi) | End timestamp of the 10-min bucket (naive NY-time). Bucket covers (ten_min_timeframe − 10 min, ten_min_timeframe]. | exchange | T+1 | 2020-01-02 | never null | 2026-07-24 09:40:00 |
date | Date | trading day (UTC) | (date, ten_min_timeframe, figi) | Session date. US equity trading calendar. | exchange | T+1 | 2020-01-02 | never null | 2026-07-24 |
figi | String(12) | identifier | (date, ten_min_timeframe, figi) | OpenFIGI composite FIGI for the underlying. Stable across ticker changes. | exchange | n/a | 2020-01-02 | never null | BBG000MM2P62 |
symbol | String | ticker | (date, ten_min_timeframe, figi) | Point-in-time listed ticker on date. Dotted dual-class form. Preserved for readability; do not use as a join key. | exchange | T+1 | 2020-01-02 | never null | AAPL |
open | Float64 | USD | (date, ten_min_timeframe, figi) | Unadjusted price of the first 1-minute bar in the bucket. Note: the source 1-minute feed carries open and close only (no high/low), so bar-internal high/low is not available at this grain. | exchange | T+1 | 2020-01-02 | null when the underlying has no trading activity in the bucket | 223.90 |
close | Float64 | USD | (date, ten_min_timeframe, figi) | Unadjusted price of the last 1-minute bar in the bucket. | exchange | T+1 | 2020-01-02 | null when the underlying has no trading activity in the bucket | 224.02 |
volume | Float64 | shares | (date, ten_min_timeframe, figi) | Underlying share volume within the bucket. Unadjusted (contemporaneous). | exchange | T+1 | 2020-01-02 | null when the underlying has no trading activity | 1_204_812.0 |
turnover | Float64 | USD | (date, ten_min_timeframe, figi) | Dollar turnover of the underlying within the bucket. Dollar amounts are unit-invariant across splits. | exchange | T+1 | 2020-01-02 | null when the underlying has no trading activity | 270_881_400.0 |
Unadjusted semantics
Prices and volume in this table are unadjusted (contemporaneous). To compute split-adjusted series, join to split_factors on figi where date BETWEEN valid_from AND valid_to and apply cum_split_factor per the reconstruction snippet in the flat-files section. The split is deliberate: it lets you reload px_10_min and split_factors independently, and gives you an explicit knob when you need to invert an adjustment.
Ticker-renamed FIGIs
A very small number of FIGIs carry rows under two different symbol values within a single day (the point-in-time symbol at the moment of the trade). If you aggregate over a universe by figi alone, use sum(turnover) for turnover and argMax(close, turnover) for a representative close per (date, ten_min_timeframe, figi). Don't collapse via any(...) or you'll pick a stale legacy row.
stock_metadata
Point-in-time (PIT) reference table for every underlying Masscrest tracks. Maps FIGI to listed ticker, company name, sector / industry, ETF and ADR flags, and the activity window during which that (ticker, FIGI) pair was live. Historical ticker changes, dual-class shares, and shell-reuse events are all encoded as separate phase rows.
- Grain:
(figi, symbol, phase_start), one row per contiguous period during which a FIGI traded under a given symbol. - History: all open phases plus historical phases as far back as the OpenFIGI record supports (many phases start
1900-01-01as a "no constraint" sentinel). - Timing: reference table, rebuilt in full each trading day. Re-sync daily to pick up new phases and any corrections.
- Typical use: join to any flow / price table on
figiwithdate BETWEEN phase_start AND phase_endto attach a point-in-time symbol, sector, name, ETF flag, etc.
Known quirks
- For ETFs (
isEtf='true', which includes ETCs and ETPs),sectorandindustrydescribe the sponsor legal entity, not the fund's underlying exposure. All BlackRock / iShares sector ETFs showsector='Financial Services'because BlackRock is a financial-services firm. FilterisEtf='true'out before aggregating flow by sector, otherwiseFinancial Servicesgross flow inflates by 85%+. - For ADRs (
isAdr='true'),sectorandindustrydescribe the underlying foreign company's business. HDB isFinancial Services(HDFC Bank), BABA isConsumer Cyclical(Alibaba). Usually the label you want. Filter onisAdrif you need to separate US-domiciled sector totals from foreign ADRs. - The served rollup
v0.grouped_flow_signal_01_dayalready excludes ETFs and ADRs from its sector and industrygroup_keys. ADRs have their ownadrgroup_keyand ETFs their ownetf. This quirk only matters when joiningv0.stock_metadatadirectly.
Symbol conventions
- Equity tickers use the dotted dual-class convention (
BRK.B,RDS.A), matching every other Masscrest surface. When OPRA options data references the same underlying via its no-dot OCC root (BRKB), the equity join still uses the dotted form. Options tables carry both:traded_symbol(OCC root) for options joins andtraded_underlying(dotted equity) for FIGI / equity joins. - Open phases use
phase_end = 2099-12-31as the sentinel. Closed phases (renames, delistings, ticker recycles) carry a real end date. terminal_symbolis the current ticker for the same FIGI as of today. Historical phases point forward at their entity's today-identity; join on it for "all history for whatever is called META today," even for the older FB rows.
Multi-phase tickers
~1% of tickers have multiple stock_metadata rows across time — one per FIGI-era — from corporate reorgs (ISIN flip, e.g. XOM's 2026-07-07 Exxon → ExxonMobil Holdings restructure) or ticker recycles after a delisting (PARA was Paramount, then Banzai after 2026-08-07 under a different FIGI).
- Current era only:
WHERE symbol='X' AND phase_end='2099-12-31' - Full history across eras:
WHERE symbol='X', resolve joins withdate BETWEEN phase_start AND phase_end - Isolate one era: filter by
figirather thansymbol
Flow, price, and split tables are already attributed to the FIGI authoritative on each row's date.
Fields
| field_name | type | unit | grain | description | provenance | timing_lag | history_start | null_semantics | example |
|---|---|---|---|---|---|---|---|---|---|
symbol | String | ticker | (figi, symbol, phase_start) | Point-in-time listed ticker during [phase_start, phase_end]. Dotted dual-class form (BRK.B). | exchange | n/a | 1900-01-01 (sentinel) | never null | FB |
figi | String(12) | identifier | (figi, symbol, phase_start) | OpenFIGI composite FIGI for the underlying entity. Stable across ticker changes. | exchange | n/a | n/a | never null | BBG000NDYB67 |
phase_start | Date | boundary | (figi, symbol, phase_start) | First trading date this (symbol, figi) pair was active. 1900-01-01 is a "no constraint" sentinel for entities with unknown pre-history. | exchange | n/a | n/a | never null | 2012-05-18 |
phase_end | Date | boundary | (figi, symbol, phase_start) | Last trading date this (symbol, figi) pair was active. 2099-12-31 sentinel means the phase is currently open (still trading under this ticker today). | exchange | n/a | n/a | never null | 2022-06-08 |
terminal_symbol | String | ticker | (figi, symbol, phase_start) | Current ticker for the same FIGI. On the FB row you'll see terminal_symbol = 'META'; on the META row it's also 'META'. Use this to fetch the full history of a currently-listed name. | exchange | daily refresh | n/a | never null | META |
companyName | String | name | (figi, symbol, phase_start) | Registered legal / operating name for the entity during this phase. | exchange | daily refresh | n/a | null when no vendor record is available for the phase | Meta Platforms, Inc. |
sector | String | sector | (figi, symbol, phase_start) | Sector classification for the entity during this phase. Investor-oriented 11-sector taxonomy (companies grouped by demand-cycle and macro exposure, not by production process). | exchange | daily refresh | n/a | null when unresolved | Technology |
industry | String | industry | (figi, symbol, phase_start) | Industry classification for the entity during this phase. Investor-oriented 154-industry taxonomy nested under the 11 sectors. | exchange | daily refresh | n/a | null when unresolved | Software - Application |
isin | String(12) | identifier | (figi, symbol, phase_start) | ISIN for the entity. Not a unique join key: roughly 200 ISINs map to two active FIGIs simultaneously (the primary listing and the US OTC F-share composite of the same foreign entity). Join on figi, not isin. | exchange | daily refresh | n/a | null when the vendor lacks an ISIN for the phase | US30303M1027 |
country | String | ISO country | (figi, symbol, phase_start) | Country of incorporation. | exchange | daily refresh | n/a | null when the vendor lacks a country for the phase | US |
isEtf | String | flag ('true' / 'false') | (figi, symbol, phase_start) | Whether the underlying is an ETF or ETP. String-typed for compatibility with the customer-facing endpoints. | exchange | daily refresh | n/a | 'false' when unresolved (defaults to non-ETF) | false |
isAdr | String | flag ('true' / 'false') | (figi, symbol, phase_start) | Whether the underlying is an American Depositary Receipt. | exchange | daily refresh | n/a | 'false' when unresolved | false |
isActivelyTrading | String | flag ('true' / 'false') | (figi, symbol, phase_start) | Whether the entity is actively trading today. Falls back to 'true' when the phase is still open (phase_end = 2099-12-31) and the vendor lacks an explicit record, 'false' otherwise. | exchange | daily refresh | n/a | never null (default fallback based on phase_end) | true |
split_factors
Cumulative split-adjustment factors per FIGI, structured as a slowly-changing dimension (SCD2). Delivered so clients can back-adjust unadjusted historical prices (see px_01_day / px_10_min), or invert a Masscrest split-adjusted price back to the raw contemporaneous print for a specific period.
- Grain: one row per continuous split-factor phase per
figi,(figi, valid_from, valid_to), non-overlapping intervals covering each FIGI's timeline.date BETWEEN valid_from AND valid_tomatches exactly one row per(figi, date). - History: full history for each covered FIGI, back to the earliest known split. Pre-split-history phases use
valid_from = 1900-01-01as a "no earlier bound" sentinel. - Timing: reference table, rebuilt in full each trading day whenever a new split lands. Re-sync daily.
- Coverage: currently ~30k FIGIs. Historical splits back to 1962 and forward-looking upcoming ex-dates are both covered.
How to use the factor
cum_split_factor on a date X means: to convert a raw close on date X into a current-shares-equivalent price, divide by this factor. It equals 1.0 on and after the most recent split; > 1 before a forward split (e.g. 4.0 before a 4-for-1); < 1 before a reverse split. On or after the latest split within an entity's active period, the factor is 1.0.
Fields
| field_name | type | unit | grain | description | provenance | timing_lag | history_start | null_semantics | example |
|---|---|---|---|---|---|---|---|---|---|
figi | String(12) | identifier | (figi, valid_from, valid_to) | OpenFIGI composite FIGI for the underlying entity. Join key to stock_metadata, px_01_day, px_10_min. | exchange | n/a | n/a | never null | BBG000MM2P62 |
valid_from | Date | boundary (inclusive) | (figi, valid_from, valid_to) | Start date this cumulative factor applies to. 1900-01-01 for the earliest period. | derived | n/a | 1900-01-01 (sentinel) | never null | 2019-08-30 |
valid_to | Date | boundary (inclusive) | (figi, valid_from, valid_to) | Last date this cumulative factor applies to. Open-ended periods (no future split yet) use the phase's phase_end; entities in a currently-active phase carry 2099-12-31. | derived | n/a | n/a | never null | 2020-08-30 |
cum_split_factor | Float64 | ratio | (figi, valid_from, valid_to) | Cumulative product of all splits from valid_from + 1 day forward within the entity's active phase. Divide a raw close on any date in [valid_from, valid_to] by this factor to get a current-shares-equivalent price. 1.0 for the most recent period (no pending split). | derived | n/a | n/a | null for extreme reverse-split cases where the true cumulative factor underflows Float64 precision (~1e-15). Treat null as "no valid split adjustment available for this period" and either skip or fail loudly; never coerce to 0.0. | 4.0 |
Precision
Cumulative factors are stored at 12 decimal places to preserve heavy reverse-split stacks (e.g. UVXY has thirteen reverse splits; its true cum factor at 1900-01-01 is ~6.7e-11). Do NOT round to 6 decimals when consuming; that historically truncated ~200 heavy-reverse-splitter FIGIs to 0.0 and silently zeroed downstream price adjustments. For the handful of penny-stock cases where the true cumulative product underflows Float64 precision entirely (e.g. stacked 1-for-50000 × 1-for-19000 × 1-for-10000 ≈ 3.5e-20), we emit NULL rather than 0.0 so consumers can detect and skip rather than silently multiplying prices by zero.
No-split entities
FIGIs that never split carry a single row spanning the entity's full active phase with cum_split_factor = 1.0. Same shape as those that split; no special-case handling needed.
