Metric registry¶
A metric measures a finished run and draws as a level-less plot. Every metric
registers here under a name; third-party metrics load through the
ob_analytics.metrics entry-point group (see
Extending). A registered value is a
Metric instance — a metric needs no per-run construction, so
the object registered is the object called.
The name is also the plot concept the metric draws under, so a renderer
registered at (name, None, backend) is the metric's face. A registered metric
shows up in available_concepts(), renders through
result.plot(name), and gets its own gallery card — with no edit to
ob-analytics.
Metrics run on demand, not during Pipeline.run: use
PipelineResult.metric for one, PipelineResult.metrics() for
every metric that applies to the run: its resolution is one of the metric's
levels, and each table in the metric's needs has rows, so a run with no
trades skips the trade metrics. Settings are keyword
arguments: result.metric("vpin", n_buckets=20), or
result.plot("vpin", n_buckets=20, threshold=0.8), where each keyword
goes to compute or prepare, whichever names it.
Built-in metrics¶
| Name | Measures | Wraps |
|---|---|---|
l1_ticker |
Best bid, best ask and last trade. Draws the three over time, or the quote card at at=. |
the depth summary and the trades |
book_signals |
Mid, micro-price and order-book imbalance | depth_signals |
vpin |
VPIN per volume bucket | compute_vpin |
kyle_lambda |
Kyle's λ regression | compute_kyle_lambda |
order_flow_imbalance |
Order flow imbalance per window | order_flow_imbalance |
ofi_horizon |
Order flow imbalance over several horizons | ofi_by_horizon |
transaction_costs |
Effective and realized spread and price impact per trade | transaction_costs |
amihud |
Amihud illiquidity per window | amihud |
roll_spread |
Roll's implied spread per window | roll_spread |
Each uses the defaults of the function it wraps, and the run's own
depth_summary wherever that function takes quotes.
Every metric reports in the instrument's own units: prices in the quote
currency and sizes in BTC, shares or contracts. result.metric,
result.plot and the gallery all compute on the run as stored (integer ticks
and lots), and each measure converts with the tick_size and lot_size the
run's tables carry, so the three give the same numbers. A setting means the
same everywhere too: a size such as bucket_volume is in the instrument's own
units and a price in the quote currency, so
result.metric("vpin", bucket_volume=0.5) and
result.plot("vpin", bucket_volume=0.5) use the same 0.5 BTC buckets.
L1TickerMetric ¶
The Level 1 quote: best bid, best ask and last trade through the run.
The table has one row each time the touch or the last trade changes. Its
face draws the three prices over time, or, given at=, the quote card
for that instant (see
:func:~ob_analytics.visualization._data.prepare_l1_ticker_data).
compute ¶
Return timestamp, the touch prices and sizes, and the last trade.
Columns: timestamp, best_bid_price, best_bid_vol,
best_ask_price, best_ask_vol, last_price, last_volume,
prices in the quote currency and sizes in the instrument's units.
Each row carries every value forward from the rows before it, so a
row is the whole quote at that time. last_price is NaN before
the first trade, and a side with no orders has a NaN price and
size (the depth summary writes 0 there), read with the same test
as :func:~ob_analytics.depth.readable_quotes. The other side is
still shown.
prepare ¶
Payload for the face; options are those of prepare_l1_ticker_data.
BookSignalsMetric ¶
Mid, micro-price and order-book imbalance, from :func:~ob_analytics.depth.depth_signals.
The table is the run's depth_summary with the signal columns added,
prices in the quote currency and sizes in the instrument's units. Its
face draws the micro-price against the mid over an imbalance strip.
compute ¶
Return the summary with mid_price, micro_price, obi and obi_depth.
depth_levels is depth_signals's: the depth of obi_depth. The
level count used, after clamping to the bins present, is in
attrs["depth_levels"].
prepare ¶
prepare(
frame: DataFrame,
*,
start_time: Timestamp | None = None,
end_time: Timestamp | None = None,
) -> dict[str, Any]
Payload for the face, for the rows from start_time to end_time.
VpinMetric ¶
VPIN, from :func:~ob_analytics.flow_toxicity.compute_vpin.
compute ¶
compute(
result: Any,
*,
bucket_volume: float | None = None,
n_buckets: int = 50,
sign_method: str | None = None,
) -> pd.DataFrame
Return the per-bucket VPIN table; the settings are compute_vpin's.
bucket_volume is in the instrument's own units, as
compute_vpin takes it.
prepare ¶
Payload for the face; threshold is the alert line.
KyleLambdaMetric ¶
Kyle's λ, from :func:~ob_analytics.flow_toxicity.compute_kyle_lambda.
The table is the per-window regression data. The fit itself is in the
table's attrs: lambda_, t_stat, r_squared, n_windows,
ci_low, ci_high, ci_level and diagnostics, as on
:class:~ob_analytics.flow_toxicity.KyleLambdaResult.
compute ¶
compute(
result: Any,
*,
window: str = "5min",
sign_method: str | None = None,
n_boot: int = 1000,
ci_level: float = 0.95,
seed: int | None = 0,
) -> pd.DataFrame
Return the regression table; the settings are compute_kyle_lambda's.
OrderFlowImbalanceMetric ¶
Order flow imbalance, from :func:~ob_analytics.flow_toxicity.order_flow_imbalance.
The table adds last_price, the last trade price in each window in the
quote currency, which the face draws as a price line behind the bars.
OfiHorizonMetric ¶
Order flow imbalance over several horizons, from :func:~ob_analytics.flow_toxicity.ofi_by_horizon.
compute ¶
compute(
result: Any,
*,
horizons: tuple[str, ...] = OFI_HORIZONS,
grid: str = "5s",
sign_method: str | None = None,
) -> pd.DataFrame
Return the grid table; the settings are ofi_by_horizon's.
prepare ¶
prepare(
frame: DataFrame,
*,
start_time: Timestamp | None = None,
end_time: Timestamp | None = None,
) -> dict[str, Any]
Payload for the horizon graph, for the steps from start_time to end_time.
TransactionCostsMetric ¶
Per-trade costs, from :func:~ob_analytics.cost.transaction_costs.
Measured against the run's own depth_summary. The face draws the
effective and realized spread in basis points, averaged over windows.
AmihudMetric ¶
RollSpreadMetric ¶
Roll's implied spread, from :func:~ob_analytics.cost.roll_spread.
Registry¶
register_metric ¶
Register metric under its own :attr:~ob_analytics.protocols.Metric.name.
Case-insensitive; overwriting an existing registration is allowed (handy for tests and for a plug-in that intentionally shadows a built-in).
Raises:
| Type | Description |
|---|---|
TypeError
|
If metric lacks a member of the
:class: |
get_metric ¶
Return the metric registered under name (case-insensitive).
Raises:
| Type | Description |
|---|---|
UnknownNameError
|
If no metric is registered under name; the message names the registered names closest to it. |
load_metric_plugins ¶
Discover and register metrics advertised via entry points.
Scans the :data:ENTRY_POINT_GROUP entry-point group; each entry's value
is loaded to a :class:~ob_analytics.protocols.Metric class, instantiated
with no arguments, and registered under its own name. This is what
lets a metric live in a separate installable package without editing
ob-analytics.
The scan runs once per process unless force is set. A plug-in that fails to load is skipped with a warning, so one broken package cannot stop the rest from loading.
Returns:
| Type | Description |
|---|---|
list of str
|
The names newly registered by this call. |
skip_reason ¶
Return why metric does not apply to result, or None when it does.
A metric applies when result is at one of its
:attr:~ob_analytics.protocols.Metric.levels and every table it
:attr:~ob_analytics.protocols.Metric.needs has rows. This is the one
test :meth:~ob_analytics.pipeline.PipelineResult.metrics, the gallery
and :func:~ob_analytics.visualization.plot_result use.
applicable_metrics ¶
Return the registered metrics that apply to result, by name.
See :func:skip_reason for what applies.