Skip to content

L2 (price-level) depth

Price-level (L2 / market-by-price) components: the depth loader, trade reader, CSV writer, and DepthCsvSource. For the guide, see Process L2 feeds.

A price-level feed carries [price, quantity] levels and diffs with no order IDs, so the loader yields the depth frame directly and the pipeline skips the per-order stages (see Level).

L2DepthLoader

L2DepthLoader(
    config: PipelineConfig | None = None,
    *,
    venue: str | None = None,
    symbol: str | None = None,
)

Load a price-level depth stream into the canonical depth frame.

Satisfies the :class:~ob_analytics.protocols.DepthSource protocol.

Parameters:

Name Type Description Default
config PipelineConfig

Pipeline configuration. price_divisor scales the raw feed price to the quote currency and tick_size quantises it to integer ticks; volume_decimals rounds size; timestamp_unit interprets integer-epoch timestamps.

None
venue str

Optional instrument identity. When either is supplied, the loaded depth frame gains per-row venue / symbol columns. A generic price-level CSV carries no venue of its own, so venue is left NA unless supplied. Both None (the default) leaves the frame untagged.

None
symbol str

Optional instrument identity. When either is supplied, the loaded depth frame gains per-row venue / symbol columns. A generic price-level CSV carries no venue of its own, so venue is left NA unless supplied. Both None (the default) leaves the frame untagged.

None

load

load(source: str | Path) -> pd.DataFrame

Read source and return a canonical depth DataFrame.

Parameters:

Name Type Description Default
source str or Path

The L2 CSV file, or a directory containing depth.csv.

required

Returns:

Type Description
DataFrame

Columns timestamp, price, volume (absolute level size), direction (categorical bid/ask), sorted by timestamp — a :func:~ob_analytics.schemas.validate_depth_df frame.

L2TradeReader

L2TradeReader(config: PipelineConfig | None = None)

Read raw trade prints from a companion trades.csv.

Projects each print into the canonical trades schema. Price-level feeds have no order IDs, so maker / taker (and their event-id / og columns) are left unset. direction (the taker's aggressor side) is taken from a native side column when present; otherwise it is left unlabelled and the pipeline classifies it (Lee–Ready against the reconstructed BBO — see :meth:~ob_analytics.pipeline.Pipeline._ensure_trade_signs).

Trades are optional for an L2 run: a missing / empty trades.csv yields an empty trades frame (depth analytics still run).

Satisfies the :class:~ob_analytics.protocols.TradeSource protocol.

DepthCsvWriter

DepthCsvWriter(config: PipelineConfig | None = None)

Write a depth frame (and trades) back to the L2 CSV schema.

Round-trips :class:L2DepthLoader / :class:L2TradeReader: writes depth.csv (and a companion trades.csv when trades are supplied) into the dest directory.

Satisfies the :class:~ob_analytics.protocols.DataWriter protocol.

write

write(
    data: dict[str, DataFrame],
    dest: str | Path,
    **kwargs: Any,
) -> Path

Write data['depth'] (and optional data['trades']) to dest.

Parameters:

Name Type Description Default
data dict of str to DataFrame

Must contain a "depth" key (the canonical depth frame). An optional "trades" key triggers a companion trades.csv.

required
dest str or Path

Output directory.

required

Returns:

Type Description
Path

The written depth.csv path.

DepthCsvSource dataclass

DepthCsvSource(
    name: str = "depth_csv",
    level: Level = Level.L2,
    feed_type: FeedType = FeedType.MATCHED_BOOK,
    trade_attribution: TradeAttribution = TradeAttribution.NONE,
    settings: SourceSettings = SourceSettings(),
)

The canonical L2 (price-level) CSV source — offline depth replay.

Declares :attr:~ob_analytics.protocols.Level.L2, so :class:~ob_analytics.pipeline.Pipeline takes the price-level path: depth in, per-order stages skipped. The shared entry point the aggregated venue connectors (Binance, Kalshi, Polymarket) narrow to domain modelling on top of, and the offline replay target for a live L2 capture (e.g. the depth.csv a :class:~ob_analytics.live.ccxt_source.CcxtSource writes).

Conforms structurally to :class:~ob_analytics.protocols.OfflineSource — no inheritance required.

recorded_tick_size

recorded_tick_size(source: str | Path) -> float | None

Return the tick size a live capture recorded in its meta.json.

source is the capture directory or a file inside it. None when there is no meta.json or it records no tick size: a capture from a venue whose metadata gives none, or one written before captures recorded it.

recorded_sequence_kind

recorded_sequence_kind(
    source: str | Path,
    default: SequenceKind = SequenceKind.CONTIGUOUS,
) -> SequenceKind

Return what the venue sequence of a live capture promises.

source is the capture directory or a file inside it. A capture whose meta.json records no sequence_kind (no meta.json, a source that does not declare one, or a capture written before captures recorded it) is read as default. Pass what the source reading the files declares (:func:~ob_analytics.protocols.sequence_kind_of), so a file that is not a live capture is checked the way its source says.

recorded_source

recorded_source(source: str | Path) -> str | None

Return the name of the source that made a live capture.

source is the capture directory, a file inside it, or the output of ob-analytics process, which keeps the capture's meta.json. None when there is no record: a file that is not a capture, or a capture written before captures recorded it.

recorded_feed_type

recorded_feed_type(source: str | Path) -> FeedType | None

Return the :class:~ob_analytics.protocols.FeedType a capture's source declared.

None when the capture records none (see :func:recorded_source).

recorded_trade_attribution

recorded_trade_attribution(
    source: str | Path,
) -> TradeAttribution | None

Return the :class:~ob_analytics.protocols.TradeAttribution a capture's source declared.

None when the capture records none (see :func:recorded_source).