Flow Metrics
Trade-flow metrics per symbol in fixed time windows: taker (aggressor) buy versus sell volume and trade counts, broken out by order size.
flow_metrics — the dataset name to pass to the Obscura API.
What one row means
One row is the finalized set of ~119 derived order-flow microstructure factors for one equity symbol over one aggregation bucket (currently only daily, bucket_seconds=86400): every top-of-book trade print during that bucket is aggressor-classified (quote-rule with tick-rule fallback) and folded into taker buy/sell flow, order-size composition, price/tick distributions, volatility, impact/slippage, run-structure, and order-flow-imbalance factors, plus a cross-bar flow_toxicity_score.
One row per (symbol, bucket_seconds, event_time).
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 flow_metrics: published: available_date = date(event_time) — the session's own day. WHY: event_time marks the START of the daily bucket, i.e. the trading session the bar aggregates, and the session's order flow is available on the session day itself. So the day the data was published is the session day, and that is what this column records. WHAT IT IS NOT: this was previously date(event_time) + 1, on two arguments that are both rejected. (a) 'the bar only settles after the close, so it is a T+1 fact' — an availability date is the day the publisher published, never an adjustment for when a consumer could act; the next tradeable session is always derivable forward from this date, and is never recoverable once a lag has been baked in. (b) 'the vendor file's last_modified_date lands on session+1' — an mtime is evidence about a filesystem, not about publication, and it moves for unrelated reasons (a site migration once touched 257 SEC FTD files to one 2020 date, which would have dated 11 years of history 11.5 years late). Corrected by migration m20260702_000204.
Refresh cadence
Obscura refreshes flow_metrics every 6 hours — the most frequent scheduled job that re-collects or re-exports it. This is Obscura's own pipeline cadence, not the upstream publisher's release schedule; when a row became public is recorded per row in available_date.
Schema — 126 columns
The full public column list for flow_metrics, with the meaning of every field. The same
schema is served unauthenticated at https://api.obscura.trade/v1/catalog/flow_metrics.
| Column | Type | Description |
|---|---|---|
| symbol | text · not null | Equity ticker symbol (uppercase), resolved from the source feed's raw-symbol map at decode time. Part of the primary key. |
| bucket_seconds | integer · not null | Aggregation bucket width in seconds; defaults to 86400 (daily bars) and is the only value the scheduled collector produces today. Part of the primary key. |
| event_time | timestamp with time zone · not null | UTC midnight timestamp marking the START of the bucket (the trading day/session the bar aggregates). Renamed from bucket_start. Part of the primary key with symbol + bucket_seconds; source column for the generated available_date column. |
| dataset | text · not null | Internal feed code identifying which consolidated equities tape the bar was built from; constant for a given collection run and carried for lineage. |
| taker_buy_volume | double precision · not null | Total traded quantity (shares) across prints where the aggressor (price-crossing taker) was classified Buy via the quote rule (price vs. BBO mid) with tick-rule fallback. |
| taker_sell_volume | double precision · not null | Total traded quantity (shares) across prints classified taker-Sell. |
| taker_buy_count | bigint · not null | Number of individual tbbo prints classified taker-Buy in the bucket. |
| taker_sell_count | bigint · not null | Number of individual tbbo prints classified taker-Sell in the bucket. |
| volume_delta | double precision · not null | Net signed taker volume in shares: taker_buy_volume − taker_sell_volume. |
| volume_delta_notional | double precision · not null | Net signed taker flow in dollars (buy_notional − sell_notional). Feeds flow_toxicity_score as one of its two z-scored inputs. |
| flow_entropy | double precision · not null | Shannon entropy (nats) of the {buy, sell} volume split. Low ⇒ concentrated, one-sided flow; higher (max ln2) ⇒ balanced buy/sell activity. |
| taker_buy_sell_ratio | double precision · not null | taker_buy_volume / taker_sell_volume — volume-weighted buy/sell skew. |
| taker_buy_sell_count_ratio | double precision · not null | taker_buy_count / taker_sell_count — print-count buy/sell skew. |
| taker_buy_sell_percentage | double precision · not null | taker_buy_volume as a share (0-1) of (taker_buy_volume + taker_sell_volume). |
| taker_buy_sell_count_percentage | double precision · not null | taker_buy_count as a share (0-1) of (taker_buy_count + taker_sell_count). |
| taker_buy_small_order_volume | double precision · not null | NOTIONAL DOLLARS from taker-Buy prints whose per-print notional is < $100. Despite the `_volume` suffix this is money, not shares: the collector sums `price * size` per print into the size buckets. Dividing it by `taker_buy_volume` (which IS shares) yields a number that just tracks the share price — compare against `buy_notional`-scaled quantities instead. |
| taker_buy_small_order_count | bigint · not null | Count of taker-Buy prints with per-print notional < $100. |
| taker_buy_medium_order_volume | double precision · not null | Notional DOLLARS from taker-Buy prints with per-print notional in [$100, $1000). Money, not shares — see `taker_buy_small_order_volume`. |
| taker_buy_medium_order_count | bigint · not null | Count of taker-Buy prints with per-print notional in [$100, $1000). |
| taker_buy_large_order_volume | double precision · not null | Notional DOLLARS from taker-Buy prints with per-print notional ≥ $1000. Money, not shares — see `taker_buy_small_order_volume`. |
| taker_buy_large_order_count | bigint · not null | Count of taker-Buy prints with per-print notional ≥ $1000. |
| taker_sell_small_order_volume | double precision · not null | Notional DOLLARS from taker-Sell prints with per-print notional < $100. Money, not shares — see `taker_buy_small_order_volume`. |
| taker_sell_small_order_count | bigint · not null | Count of taker-Sell prints with per-print notional < $100. |
| taker_sell_medium_order_volume | double precision · not null | Notional DOLLARS from taker-Sell prints with per-print notional in [$100, $1000). Money, not shares — see `taker_buy_small_order_volume`. |
| taker_sell_medium_order_count | bigint · not null | Count of taker-Sell prints with per-print notional in [$100, $1000). |
| taker_sell_large_order_volume | double precision · not null | Notional DOLLARS from taker-Sell prints with per-print notional ≥ $1000. Money, not shares — see `taker_buy_small_order_volume`. |
| taker_sell_large_order_count | bigint · not null | Count of taker-Sell prints with per-print notional ≥ $1000. |
| taker_buy_large_order_percentage | double precision · not null | taker_buy_large_order_volume as a share (0-1) of taker-buy NOTIONAL — how much buy flow is institutional-sized. Dollars over dollars, so this ratio is sound; the denominator is buy notional, NOT `taker_buy_volume`. |
| taker_sell_large_order_percentage | double precision · not null | taker_sell_large_order_volume as a share (0-1) of taker-sell NOTIONAL (dollars over dollars). |
| large_order_volume | double precision · not null | Combined large-order (≥$1000 notional) DOLLARS across both sides: taker_buy_large_order_volume + taker_sell_large_order_volume. |
| trade_count | bigint · not null | Total number of tbbo prints (both sides) in the bucket; legacy name for n_trades in the factor catalog. Same underlying count as n_prints. |
| mean_trade_size | double precision · not null | Mean per-print notional ($) across all prints in the bucket. Trade-size basis is dollar notional, not share quantity. |
| trade_size_skewness | double precision · not null | Skewness of the per-print notional ($) distribution; high ⇒ a few outsized prints dominate the bar's flow. |
| range_bps | double precision · not null | Intrabar (high − low) / mean_price, in basis points — normalized trading range. |
| mean_price | double precision · not null | Arithmetic (unweighted) mean of trade prices across all prints in the bucket. |
| price_std | double precision · not null | Standard deviation of trade prices across prints in the bucket. |
| price_skewness | double precision · not null | Skewness of the intrabar trade-price distribution. |
| price_kurtosis | double precision · not null | Kurtosis of the intrabar trade-price distribution. |
| price_cv | double precision · not null | Coefficient of variation of price: price_std / mean_price. Scale-free price dispersion, comparable across symbols at very different price levels. |
| vwap | double precision · not null | Notional-weighted average trade price across the bucket: sum(price×size)/sum(size). |
| open | double precision · not null | First trade price recorded in the bucket. |
| high | double precision · not null | Maximum trade price recorded in the bucket. |
| low | double precision · not null | Minimum trade price recorded in the bucket. |
| close | double precision · not null | Last trade price recorded in the bucket. |
| uptick_volume | double precision · not null | Volume (shares) traded on prints whose price rose vs. the immediately preceding print (tick rule). |
| downtick_volume | double precision · not null | Volume (shares) traded on prints whose price fell vs. the immediately preceding print. |
| unchanged_volume_pct | double precision · not null | Zero-tick volume as a share (0-1) of ALL tick volume (uptick + downtick + unchanged). Legacy pre-existing column. |
| uptick_volume_pct | double precision · not null | uptick_volume / (uptick_volume + downtick_volume) — legacy column; denominator EXCLUDES unchanged-tick volume, unlike the newer *_percentage siblings below. |
| uptick_count_pct | double precision · not null | uptick_count / (uptick_count + downtick_count) — legacy column; denominator excludes unchanged-tick prints. |
| uptick_downtick_volume_ratio | double precision · not null | uptick_volume / downtick_volume. |
| uptick_downtick_count_ratio | double precision · not null | uptick_count / downtick_count. |
| realized_vol | double precision · not null | Realized volatility: sqrt(Σ r_t²) over intrabar log returns between consecutive prints. Feeds flow_toxicity_score as its second z-scored input. |
| bipower_variation | double precision · not null | (π/2)·Σ|r_t||r_t-1| — the jump-robust (continuous) component of realized variation (Barndorff-Nielsen & Shephard). |
| jump_ratio | double precision · not null | max(0, (realized_vol² − bipower_variation) / realized_vol²) — the fraction of the bar's variance attributable to price jumps rather than continuous diffusion. |
| trendiness | double precision · not null | Directional efficiency of the intrabar price path: |Σ r_t| / Σ|r_t|. 1 ⇒ pure trend, 0 ⇒ pure chop. |
| amihud_illiquidity | double precision · not null | Amihud (2002) illiquidity: |bar log-return| / dollar volume traded in the bucket. Higher ⇒ price moves more per dollar of gross flow (less liquid). |
| kyle_lambda | double precision · not null | Kyle's λ price-impact coefficient: slope of per-print price change on signed trade size, Σ(Δp·q)/Σq². Higher ⇒ more price impact per unit of signed order flow. |
| vwap_slippage_bps | double precision · not null | Signed gap between the simple mean print price and VWAP, in bps: (mean_price − vwap)/vwap × 10,000. A VWAP-dispersion proxy requiring no quote data. |
| slippage_std_bps | double precision · not null | Standard deviation of print prices around their mean, expressed in bps of VWAP. |
| max_buy_run_length | bigint · not null | Longest consecutive streak of taker-Buy-classified prints in the bucket (run-length in trade count). |
| max_sell_run_length | bigint · not null | Longest consecutive streak of taker-Sell-classified prints in the bucket. |
| flip_rate | double precision · not null | Fraction of prints where the aggressor side flips vs. the immediately preceding print (flip_count / total prints). |
| price_change_on_flip | double precision · not null | Mean absolute price move at the moment the aggressor side flips. |
| taker_buy_small_order_percentage | double precision · not null | taker_buy_small_order_volume as a share (0-1) of taker-buy NOTIONAL (dollars over dollars). |
| taker_buy_medium_order_percentage | double precision · not null | taker_buy_medium_order_volume as a share (0-1) of taker-buy NOTIONAL (dollars over dollars). |
| taker_sell_small_order_percentage | double precision · not null | taker_sell_small_order_volume as a share (0-1) of taker-sell NOTIONAL (dollars over dollars). |
| taker_sell_medium_order_percentage | double precision · not null | taker_sell_medium_order_volume as a share (0-1) of taker-sell NOTIONAL (dollars over dollars). |
| taker_buy_small_order_count_percentage | double precision · not null | taker_buy_small_order_count as a share (0-1) of taker_buy_count. |
| taker_buy_medium_order_count_percentage | double precision · not null | taker_buy_medium_order_count as a share (0-1) of taker_buy_count. |
| taker_buy_large_order_count_percentage | double precision · not null | taker_buy_large_order_count as a share (0-1) of taker_buy_count. |
| taker_sell_small_order_count_percentage | double precision · not null | taker_sell_small_order_count as a share (0-1) of taker_sell_count. |
| taker_sell_medium_order_count_percentage | double precision · not null | taker_sell_medium_order_count as a share (0-1) of taker_sell_count. |
| taker_sell_large_order_count_percentage | double precision · not null | taker_sell_large_order_count as a share (0-1) of taker_sell_count. |
| small_order_volume | double precision · not null | Combined (buy+sell) NOTIONAL DOLLARS from prints with per-print notional < $100: taker_buy_small_order_volume + taker_sell_small_order_volume. |
| small_order_count | bigint · not null | Combined (buy+sell) count of prints with per-print notional < $100. |
| medium_order_volume | double precision · not null | Combined (buy+sell) NOTIONAL DOLLARS from prints with per-print notional in [$100, $1000). |
| medium_order_count | bigint · not null | Combined (buy+sell) count of prints with per-print notional in [$100, $1000). |
| large_order_count | bigint · not null | Combined (buy+sell) count of prints with per-print notional ≥ $1000. |
| volume | double precision · not null | Total traded quantity (shares) across all prints in the bucket, both sides: taker_buy_volume + taker_sell_volume. |
| small_order_percentage | double precision · not null | small_order_volume as a share (0-1) of `dollar_volume` — dollars over dollars, NOT of `volume` (shares). |
| medium_order_percentage | double precision · not null | medium_order_volume as a share (0-1) of `dollar_volume` — dollars over dollars, NOT of `volume` (shares). |
| large_order_percentage | double precision · not null | large_order_volume as a share (0-1) of `dollar_volume` — dollars over dollars, NOT of `volume` (shares). |
| small_order_count_percentage | double precision · not null | small_order_count as a share (0-1) of trade_count. |
| medium_order_count_percentage | double precision · not null | medium_order_count as a share (0-1) of trade_count. |
| large_order_count_percentage | double precision · not null | large_order_count as a share (0-1) of trade_count. |
| trade_amount_median | double precision · not null | Median per-print notional ($) in the bucket. Streaming P² estimate — exact below 5 prints, ~1-2% error on well-mixed streams. |
| trade_amount_std | double precision · not null | Standard deviation of per-print notional ($) across the bucket. |
| trade_amount_variance | double precision · not null | Variance of per-print notional ($) across the bucket. |
| trade_amount_kurtosis | double precision · not null | Kurtosis of the per-print notional ($) distribution. |
| trade_amount_min | double precision · not null | Smallest per-print notional ($) observed in the bucket (0 if no prints). |
| trade_amount_max | double precision · not null | Largest per-print notional ($) observed in the bucket (0 if no prints). |
| trade_amount_range_ratio | double precision · not null | trade_amount_max / trade_amount_min — spread of print sizes traded in the bucket. |
| trade_amount_cv | double precision · not null | Coefficient of variation of per-print notional: trade_amount_std / mean_trade_size. |
| price_median | double precision · not null | Median trade price across prints in the bucket. |
| price_variance | double precision · not null | Variance of trade prices across prints in the bucket (price_std squared). |
| range | double precision · not null | Raw intrabar trading range in price units: high − low. |
| price_range_ratio | double precision · not null | high / low — multiplicative intrabar range. |
| uptick_count | bigint · not null | Number of prints classified as an uptick (price rose vs. prior print). |
| downtick_count | bigint · not null | Number of prints classified as a downtick (price fell vs. prior print). |
| unchanged_count | bigint · not null | Number of prints with unchanged price vs. the prior print (zero tick). |
| unchanged_volume | double precision · not null | Volume (shares) traded on zero-tick prints. |
| downtick_count_percentage | double precision · not null | downtick_count as a share (0-1) of ALL tick events (uptick+downtick+unchanged counts). Unlike the legacy uptick_count_pct, this denominator includes unchanged ticks. |
| unchanged_count_percentage | double precision · not null | unchanged_count as a share (0-1) of ALL tick events (uptick+downtick+unchanged). |
| downtick_volume_percentage | double precision · not null | downtick_volume as a share (0-1) of ALL tick volume (uptick+downtick+unchanged), unlike the legacy uptick_volume_pct which excludes unchanged volume from its denominator. |
| buy_run_mean_len | double precision · not null | Mean length of taker-Buy runs: total buy-print count / number of distinct buy runs. |
| sell_run_mean_len | double precision · not null | Mean length of taker-Sell runs: total sell-print count / number of distinct sell runs. |
| run_imbalance | double precision · not null | Normalized difference of the longest buy vs. sell run, in [-1,1]: (max_buy_run_length − max_sell_run_length) / (max_buy_run_length + max_sell_run_length). |
| logret_var | double precision · not null | Mean-centered variance of intrabar log returns (distinct from realized_vol, which is the un-centered sum of squared returns). |
| impact_per_notional | double precision · not null | |bar log-return| / |signed (net) notional flow| — like amihud_illiquidity but normalized by directional pressure rather than gross dollar volume. |
| large_trade_reversal | double precision · not null | Mean 5-print-ahead return following prints in the running top decile by notional. Negative ⇒ big prints tend to reverse; 0 on bars with fewer than 6 prints. |
| directional_impact_asymmetry | double precision · not null | Mean per-print price change on buy-classified prints minus mean per-print price change on sell-classified prints. Positive ⇒ buys push price up more than sells push it down. |
| slippage_mean | double precision · not null | Mean signed quote-relative slippage in price units ($): buy prints priced above the prevailing BBO mid, sell prints priced below it, averaged across prints with a valid attached quote. |
| slippage_bps_mean | double precision · not null | Mean signed quote-relative slippage in bps across all sided prints with a valid quote. Positive ⇒ paid up / adverse execution. |
| slippage_bps_median | double precision · not null | Median quote-relative slippage in bps. Streaming P² estimate. |
| slippage_bps_buy_mean | double precision · not null | Mean quote-relative slippage in bps restricted to taker-Buy prints only. |
| slippage_bps_sell_mean | double precision · not null | Mean quote-relative slippage in bps restricted to taker-Sell prints only. |
| slippage_bps_buy_sell_ratio | double precision · not null | slippage_bps_buy_mean / slippage_bps_sell_mean. |
| slippage_bps_sell_buy_ratio | double precision · not null | slippage_bps_sell_mean / slippage_bps_buy_mean. |
| ofi | double precision · not null | Order-Flow Imbalance (Cont, Kukanov & Stoikov 2014): accumulated signed change in best-bid/ask queue depth across consecutive BBO snapshots attached to tbbo prints. Positive ⇒ net demand added / supply pulled at the touch. |
| ofi_normalized | double precision · not null | ofi divided by the bucket's mean (bid_size+ask_size) depth — scale-free, suitable for cross-sectional ranking. 0 when no valid BBO snapshot was seen. |
| bid_count_at_touch_mean | double precision | Bucket-mean number of distinct resting orders at the best BID across the BBO snapshots attached to trades (raw `levels[0].bid_ct`, averaged over valid-quote prints). A queue-fragmentation / order-count-at-touch signal orthogonal to the bid_sz share depth folded into ofi. NULL/0 when no valid BBO snapshot was seen. |
| ask_count_at_touch_mean | double precision | Bucket-mean number of distinct resting orders at the best ASK across the BBO snapshots attached to trades (raw `levels[0].ask_ct`, averaged over valid-quote prints). Companion to bid_count_at_touch_mean. NULL/0 when no valid BBO snapshot was seen. |
| dollar_volume | double precision · not null | Total notional ($) traded across all prints in the bucket (sum of price×size, both sides) — the denominator for amihud_illiquidity. |
| n_prints | bigint · not null | Number of raw tbbo prints folded into this bucket after price/size validity filtering (price finite & >0, size >0). Same underlying count as trade_count. |
| flow_toxicity_score | double precision · not null | z(volume_delta_notional) × z(realized_vol), where each z-score is computed in a post-pass over the symbol's own trailing bucket series in the current upsert run. Highlights destabilizing, one-sided bars. |
| available_date | date | PUBLIC-availability date: STORED generated column = date(event_time) — the session's own day, because a session's order flow is available on that session day. The point-in-time column to filter/join on. Previously date(event_time) + 1, which encoded a trading-lag adjustment and a file mtime rather than a publication date; see the entity-level availability note and migration m20260702_000204. |
Access flow_metrics
Two delivery paths, one identifier. Both require an Obscura account and an active subscription; the catalog entry and the schema above are public.
import obscura
client = obscura.Client("obs_live_…")
df = client.query(
dataset="flow_metrics",
symbols=["NVDA", "AAPL"],
start="2024-01-01",
)
Create a free account Browse all 95 datasets
Frequently asked questions
What is in the flow_metrics dataset?
Trade-flow metrics per symbol in fixed time windows: taker (aggressor) buy versus sell volume and trade counts, broken out by order size. One row is the finalized set of ~119 derived order-flow microstructure factors for one equity symbol over one aggregation bucket (currently only daily, bucket_seconds=86400): every top-of-book trade print during that bucket is aggressor-classified (quote-rule with tick-rule fallback) and folded into taker buy/sell flow, order-size composition, price/tick distributions, volatility, impact/slippage, run-structure, and order-flow-imbalance factors, plus a cross-bar flow_toxicity_score.
How do I avoid look-ahead bias with flow_metrics?
Filter on flow_metrics.available_date, the day the publisher made the row public. For this dataset that date is derived as follows — published: available_date = date(event_time) — the session's own day. WHY: event_time marks the START of the daily bucket, i.e. the trading session the bar aggregates, and the session's order flow is available on the session day itself. So the day the data was published is the session day, and that is what this column records. WHAT IT IS NOT: this was previously date(event_time) + 1, on two arguments that are both rejected. (a) 'the bar only settles after the close, so it is a T+1 fact' — an availability date is the day the publisher published, never an adjustment for when a consumer could act; the next tradeable session is always derivable forward from this date, and is never recoverable once a lag has been baked in. (b) 'the vendor file's last_modified_date lands on session+1' — an mtime is evidence about a filesystem, not about publication, and it moves for unrelated reasons (a site migration once touched 257 SEC FTD files to one 2020 date, which would have dated 11 years of history 11.5 years late). Corrected by migration m20260702_000204. A query of the form WHERE available_date <= '<as-of date>' never sees a row before it existed.
In what formats can I get flow_metrics?
As a Parquet bulk export (POST https://api.obscura.trade/v1/download) or as JSON from the typed query API (POST https://api.obscura.trade/v1/query), both with dataset="flow_metrics". The column schema is public at https://api.obscura.trade/v1/catalog/flow_metrics.
Can I filter flow_metrics by company or symbol?
Yes. flow_metrics carries symbol, the column the API's symbols filter resolves against.
How often is flow_metrics updated?
Obscura refreshes flow_metrics on a every 6 hours schedule — that is the most frequent scheduled job that re-collects or re-exports the table. It is Obscura's own pipeline cadence, not the upstream publisher's release schedule; when the publisher makes a row available is described by the availability rule above, and is recorded per row in available_date.