Skip to content

Analytics

Format-agnostic post-processing analytics. These functions work with the output of any format's pipeline run (Bitstamp, LOBSTER, or custom).

Trade Analysis

order_aggressiveness

order_aggressiveness(
    events: DataFrame, depth_summary: DataFrame
) -> pd.DataFrame

Calculate order aggressiveness with respect to the best bid or ask in BPS.

Parameters:

Name Type Description Default
events DataFrame

The events DataFrame (must contain direction, action, type, timestamp, event_id, price columns).

required
depth_summary DataFrame

The order book summary statistics DataFrame (must contain timestamp and event_id columns).

required

Returns:

Type Description
DataFrame

The events DataFrame with an added aggressiveness_bps column.

trade_impacts

trade_impacts(trades: DataFrame) -> pd.DataFrame

Generate a DataFrame containing order book impact summaries.

Aggregates trade records by taker order ID to summarise how each aggressive order swept through the book (price range, number of fills, total volume, VWAP, duration).

Parameters:

Name Type Description Default
trades DataFrame

The trades DataFrame (must contain taker, price, volume, timestamp, direction columns).

required

Returns:

Type Description
DataFrame

A DataFrame summarising market order impacts with columns: id, min_price, max_price, vwap, hits, vol, start_time, end_time, dir.

Order Type Classification

set_order_types

set_order_types(
    events: DataFrame, trades: DataFrame
) -> pd.DataFrame

Determine limit order types.

Classifies each order as one of: market, resting-limit, flashed-limit, or market-limit, based on how the order interacts with the book over its lifetime.

Parameters:

Name Type Description Default
events DataFrame

The limit order events DataFrame.

required
trades DataFrame

The executions DataFrame.

required

Returns:

Type Description
DataFrame

The events DataFrame with an updated 'type' column indicating order types.

Order Book Reconstruction

order_book

order_book(
    events: DataFrame,
    tp: datetime | None = None,
    max_levels: int | None = None,
    bps_range: int = 0,
    min_bid: float = 0,
    max_ask: float = np.inf,
    uncross: bool = False,
) -> dict[str, datetime | pd.Timestamp | pd.DataFrame]

Reconstruct the order book at a specific point in time.

Parameters:

Name Type Description Default
events DataFrame

DataFrame containing order events.

required
tp datetime or Timestamp

The point in time at which to evaluate the order book. If None, uses the latest event timestamp in the data.

None
max_levels int

The maximum number of price levels to include for bids and asks.

None
bps_range int

Basis points range to filter the bids and asks. Default is 0.

0
min_bid float

Minimum bid price. Default is 0.

0
max_ask float

Maximum ask price. Default is infinity.

inf
uncross bool

When True, evict crossed resting orders so the snapshot satisfies best_bid < best_ask — a display convenience mirroring the depth engine's crossed-level eviction (see :func:_uncross_active_orders). The default is False: the reconstruction stays faithful to the feed, so a diff feed's genuinely crossed resting orders (see :class:~ob_analytics.protocols.FeedType) are replayed as-is rather than silently uncrossed. Has no effect on a matched-book feed, which is never crossed.

False

Returns:

Type Description
dict[str, datetime or DataFrame]

A dictionary containing: - 'timestamp': The evaluation timestamp. - 'asks': DataFrame of active ask orders. - 'bids': DataFrame of active bid orders.

uncross_book_sides

uncross_book_sides(
    bids: DataFrame, asks: DataFrame
) -> tuple[pd.DataFrame, pd.DataFrame]

Evict crossed levels from two reconstructed book sides for display.

The frame-level counterpart of order_book(..., uncross=True) for callers that already hold per-order book sides — e.g. the book_snapshot / depth_chart visualization prepares. Both frames are returned best-first (bids by descending price, asks by ascending price) with the crossed best-end orders removed so best_bid < best_ask; liquidity is recomputed when present and every other column is preserved.

Parameters:

Name Type Description Default
bids DataFrame

Per-order book sides carrying at least price and timestamp (as returned in :func:order_book's "bids" / "asks" frames).

required
asks DataFrame

Per-order book sides carrying at least price and timestamp (as returned in :func:order_book's "bids" / "asks" frames).

required

Returns:

Type Description
tuple of (pandas.DataFrame, pandas.DataFrame)

The uncrossed (bids, asks) sides, best-first.

Data Quality

See Data quality: matched book vs diff feed for the concepts and the validate how-to for the CLI.

data_quality_summary

data_quality_summary(
    events: DataFrame,
    trades: DataFrame,
    *,
    feed_type: FeedType = FeedType.UNKNOWN,
    depth: DataFrame | None = None,
) -> DataQualitySummary

Summarise the data quality of one reconstructed session.

Surfaces the health signals that matter before trusting a feed — most importantly how crossed the resting book is, which distinguishes a matched book from a diff feed (see :class:~ob_analytics.protocols.FeedType).

Parameters:

Name Type Description Default
events DataFrame

Classified events (must carry the canonical columns and the type column from :func:set_order_types).

required
trades DataFrame

The trades frame, with maker_event_id / taker_event_id.

required
feed_type FeedType

The source's declared feed type, recorded on the summary and used to interpret crossed_pct. Read it off the format: getattr(fmt, "feed_type", FeedType.UNKNOWN).

UNKNOWN
depth DataFrame

A faithful price-level-volume frame (e.g. PipelineResult.depth). When None it is computed from events via :func:~ob_analytics.depth.price_level_volume. Do not pass depth_summary — that is already uncrossed and would report ~0%.

None

Returns:

Type Description
DataQualitySummary

DataQualitySummary dataclass

DataQualitySummary(
    feed_type: FeedType,
    n_events: int,
    n_orders: int,
    n_trades: int,
    crossed_pct: float,
    crossed_episodes: int,
    unmatched_trades_pct: float,
    duplicate_event_ids: int,
    duplicate_created_ids: int,
    pre_existing_orders: int,
)

Per-run data-quality metrics for a reconstructed session.

Built by :func:data_quality_summary. All percentages are 0–100 floats.

Attributes:

Name Type Description
feed_type FeedType

The source's declared crossing invariant (see :class:~ob_analytics.protocols.FeedType); sets expectations for crossed_pct.

n_events, n_orders, n_trades int

Row / distinct-order / trade counts.

crossed_pct float

Percentage of session time the faithful book is crossed (best_bid > best_ask). Expected ~0 for a matched book; a genuine, faithfully-replayed property of a diff feed.

crossed_episodes int

Number of distinct crossed intervals.

unmatched_trades_pct float

Percentage of trades missing a resolved maker_event_id or taker_event_id (could not be tied to a resting order).

duplicate_event_ids int

Count of event_id values occurring more than once (event_id should be globally unique — any non-zero value is suspect).

duplicate_created_ids int

Count of order ids with more than one created event.

pre_existing_orders int

Distinct orders resting before the capture window (classifier label pre-existing — structurally unclassifiable, not failures).

to_dict

to_dict() -> dict[str, Any]

Return the summary as a plain, JSON-serialisable dict.

render

render() -> str

Return a fixed-width, human-readable report block.