Options Flow Daily
End-of-day options flow per underlying, aggregated from the full option chain: volume, open interest, notional premium, put/call ratios and implied-volatility summaries.
options_flow_daily — the dataset name to pass to the Obscura API.
What one row means
One row is the aggregated end-of-day options-flow summary for a single (ticker, trading day): every per-strike/per-expiry row of that day's end-of-day option chain for that ticker folded into one record of summed call/put volume, open interest, notional premium, put/call ratios, and volume-weighted implied vol. A plain table (not partitioned): ~22M rows over the full history.
One row per (ticker, occurred_on).
Point-in-time availability
Every Obscura dataset carries available_date: the calendar day the publisher made the row
available, day-of, with no session rounding. It is the one column a backtest filters on, and it means the
same thing on every dataset in the catalog.
For options_flow_daily: released: available_date = occurred_on (the chain's trade day) + 1 business day — the EOD chain is usable the following session; materialized by the collector.
Known limitation
Rolling recent window only; deep options history is not yet collected.
Refresh cadence
Obscura refreshes options_flow_daily daily — the most frequent scheduled job that re-collects or re-exports it. This is Obscura's own pipeline cadence, not the upstream publisher's release schedule; when a row became public is recorded per row in available_date.
Schema — 18 columns
The full public column list for options_flow_daily, with the meaning of every field. The same
schema is served unauthenticated at https://api.obscura.trade/v1/catalog/options_flow_daily.
| Column | Type | Description |
|---|---|---|
| ticker | text · not null | Underlying equity ticker symbol, uppercase, as reported on the option chain. Part of the composite key with occurred_on; every strike/expiry for this ticker on the trade date folds into this one row via Aggregator::add. |
| occurred_on | date · not null | The trading day this row summarizes, taken from the end-of-day chain snapshot's own dated identity rather than any per-row cell. Composite PK with ticker. |
| available_date | date | PUBLIC-availability date = occurred_on (trade day) + 1 business day (the end-of-day chain is usable the next session); materialized by the collector. The point-in-time column to filter/join on. |
| stock_px | double precision | Underlying stock's closing price for the day, taken from the first strike row's `stkPx` cell seen for this ticker while streaming the chain (stkPx is constant per ticker/day). NULL if every strike row had an empty stkPx cell. |
| div_rate | double precision | Underlying's annualized dividend rate/yield used as an option pricing-model input, from the chain's `divRate` cell. Constant per ticker/day, so taken from the first strike row seen for this ticker while streaming the CSV (same convention as stock_px). NULL if every strike row had an empty divRate cell. |
| i_rate | double precision | Risk-free interest rate used in the chain's option pricing, from the `iRate` cell. Effectively market-wide per day; taken from the first row seen for this ticker (same convention as stock_px). NULL if every strike row had an empty iRate cell. |
| call_volume | bigint · not null | Sum of `cVolu` (call contract trading volume) across every strike/expiry row for this ticker/day. Missing/empty cells contribute 0, not NULL, to the sum. |
| put_volume | bigint · not null | Sum of `pVolu` (put contract trading volume) across every strike/expiry row for this ticker/day; empty cells contribute 0. |
| call_oi | bigint · not null | Sum of `cOi` (call open interest, contracts outstanding as of that day's close) across every strike/expiry row for this ticker/day. |
| put_oi | bigint · not null | Sum of `pOi` (put open interest) across every strike/expiry row for this ticker/day. |
| call_premium | double precision · not null | Notional dollar premium traded on calls: Σ over strikes of (cVolu × cValue × 100), where cValue is the chain's theoretical/mid option value used as the price proxy and 100 is the standard contract share multiplier. Strikes with 0 volume contribute 0 regardless of cValue. |
| put_premium | double precision · not null | Notional dollar premium traded on puts: Σ over strikes of (pVolu × pValue × 100), the put-side analogue of call_premium. |
| put_call_volume_ratio | double precision | put_volume / call_volume for the ticker/day. NULL only when call_volume is 0 (undefined denominator); a nonzero call_volume with zero put_volume yields the literal value 0.0, not NULL. |
| put_call_oi_ratio | double precision | put_oi / call_oi for the ticker/day. NULL only when call_oi is 0; otherwise 0.0 or a positive ratio, same convention as put_call_volume_ratio. |
| avg_call_iv | double precision | Volume-weighted average call implied volatility: Σ(cVolu × cMidIv) / Σ cVolu across all call strikes for the ticker/day. NULL when call_volume is 0 — there is no volume to weight by. |
| avg_put_iv | double precision | Volume-weighted average put implied volatility: Σ(pVolu × pMidIv) / Σ pVolu across all put strikes for the ticker/day. NULL when put_volume is 0. |
| num_strikes | integer · not null | Count of raw per-strike/expiry CSV rows folded into this ticker/day. Each row already carries both the call and put side of one strike/expiry combination, so this is strikes×expiries seen, not a distinct-strike-price count. |
| num_expiries | integer · not null | Count of distinct option expiration dates (`expirDate`) observed across this ticker's strikes on the day — how many expiry cycles were actively quoted/traded. |
Access options_flow_daily
Two delivery paths, one identifier. Both require an Obscura account and an active subscription; the catalog entry and the schema above are public.
import obscura
client = obscura.Client("obs_live_…")
df = client.query(
dataset="options_flow_daily",
symbols=["NVDA", "AAPL"],
start="2024-01-01",
)
Create a free account Browse all 95 datasets
Frequently asked questions
What is in the options_flow_daily dataset?
End-of-day options flow per underlying, aggregated from the full option chain: volume, open interest, notional premium, put/call ratios and implied-volatility summaries. One row is the aggregated end-of-day options-flow summary for a single (ticker, trading day): every per-strike/per-expiry row of that day's end-of-day option chain for that ticker folded into one record of summed call/put volume, open interest, notional premium, put/call ratios, and volume-weighted implied vol. A plain table (not partitioned): ~22M rows over the full history.
How do I avoid look-ahead bias with options_flow_daily?
Filter on options_flow_daily.available_date, the day the publisher made the row public. For this dataset that date is derived as follows — released: available_date = occurred_on (the chain's trade day) + 1 business day — the EOD chain is usable the following session; materialized by the collector. A query of the form WHERE available_date <= '<as-of date>' never sees a row before it existed.
In what formats can I get options_flow_daily?
As a Parquet bulk export (POST https://api.obscura.trade/v1/download) or as JSON from the typed query API (POST https://api.obscura.trade/v1/query), both with dataset="options_flow_daily". The column schema is public at https://api.obscura.trade/v1/catalog/options_flow_daily.
Can I filter options_flow_daily by company or symbol?
Yes. options_flow_daily carries ticker, the column the API's symbols filter resolves against.
Is options_flow_daily complete?
Not yet, and the limitation is declared rather than hidden: Rolling recent window only; deep options history is not yet collected.
How often is options_flow_daily updated?
Obscura refreshes options_flow_daily on a daily schedule — that is the most frequent scheduled job that re-collects or re-exports the table. It is Obscura's own pipeline cadence, not the upstream publisher's release schedule; when the publisher makes a row available is described by the availability rule above, and is recorded per row in available_date.