Skip to main content

orderflow-metrics (Python)

CI PyPI Python License: MIT

Dependency-free market-microstructure metrics in pure Python: Order Flow Imbalance (OFI), VPIN, information-driven bars, transaction-cost / price-impact metrics, trade-sign classification, limit-order-book reconstruction and execution scheduling. No NumPy, no pandas — just the standard library.

This is the Python port of the TypeScript orderflow-metrics library, with the same API surface in snake_case.

Install

pip install orderflow-metrics

Usage

from orderflow_metrics import ofi, depth_imbalance, trade_imbalance, L1Quote, Trade

quotes = [
    L1Quote(bid_price=100, bid_size=5, ask_price=101, ask_size=4),
    L1Quote(bid_price=100, bid_size=8, ask_price=101, ask_size=1),
    L1Quote(bid_price=100.5, bid_size=2, ask_price=101, ask_size=1),
]
ofi(quotes)  # 8  (net buy-side pressure)

depth_imbalance(quotes[0])  # (5 - 4) / (5 + 4) ~ 0.111

trade_imbalance([Trade(100, 2, "buy"), Trade(100, 1, "sell")])  # 0.333

Order Flow Imbalance

ofi implements the level-1 OFI of Cont, Kukanov & Stoikov (2014). OFI over a window is the sum of per-event contributions; it counts size added to the bid and removed from the ask (buy pressure) against the reverse, and is a strong linear predictor of short-horizon price changes.

  • ofi_contribution(prev, curr) — one transition
  • ofi_series(quotes) — per-step contributions
  • ofi(quotes) — cumulative

VPIN

Volume-Synchronized Probability of Informed Trading (Easley, López de Prado & O'Hara, 2012). Trades are grouped into equal-volume buckets; each bucket is split into buy/sell volume by Bulk Volume Classification, and VPIN is the average absolute imbalance over a rolling window.

from orderflow_metrics import bucket_by_volume, vpin

buckets = bucket_by_volume(trades, 1_000)
vpin(buckets, window=50)  # flow toxicity in [0, 1]

Execution cost & price impact

Transaction-cost analysis building blocks (buys +1, sells -1):

from orderflow_metrics import effective_spread, realized_spread, price_impact, kyle_lambda, FlowObservation

effective_spread(101, 100, "buy")   # 2 — cost vs the midpoint
realized_spread(101, 100.5, "buy")  # 1 — LP revenue after reversion
price_impact(100, 100.5, "buy")     # 1 — permanent impact

kyle_lambda([
    FlowObservation(price_change=1, signed_volume=2),
    FlowObservation(price_change=-1, signed_volume=-2),
])  # 0.5 — price impact per unit signed flow

Also: effective_half_spread, roll_spread (Roll 1984).

Fair value

from orderflow_metrics import weighted_mid, relative_spread_bps, L1Quote

weighted_mid(L1Quote(100, 9, 101, 1))          # ~100.9 — heavy bid pulls toward ask
relative_spread_bps(L1Quote(99.99, 1, 100.01, 1))  # 2 (bps)

Trade-sign classification

from orderflow_metrics import tick_rule, lee_ready, PriceVsMid

tick_rule([100, 101, 101, 100])                       # [0, 1, 1, -1]
lee_ready([PriceVsMid(101, 100), PriceVsMid(99, 100)])  # [1, -1]

Liquidity, volatility, efficiency

from orderflow_metrics import (
    amihud_illiquidity, ReturnVolume,
    realized_volatility, annualized_volatility,
    variance_ratio, autocorrelation,
)

amihud_illiquidity([ReturnVolume(0.02, 100), ReturnVolume(-0.01, 50)])  # 0.0002
realized_volatility([0.03, 0.04])                                       # 0.05
variance_ratio(returns, 2)   # <1 mean-reverting · ~1 random walk · >1 trending
autocorrelation(returns, 1)  # lag-1 autocorrelation

Order book & market-order simulation

from orderflow_metrics import OrderBook, simulate_market_order

ob = OrderBook()
ob.update("bid", 100, 5)
ob.update("ask", 101, 3)
ob.mid()          # 100.5
ob.imbalance(1)   # 0.25 — top-of-book size imbalance
ob.update("bid", 100, 0)  # size 0 removes the level

r = simulate_market_order(ob, "buy", 4)
r.avg_price      # volume-weighted fill price
r.slippage_bps   # cost vs mid, in basis points
r.remaining_size # > 0 if the book was too thin

OrderBook.mid(), spread(), best_bid(), best_ask() return None on an empty side.

Information-driven bars

Sampling on activity rather than the clock — a bar every N ticks, N units of volume, or N units of traded value — gives returns with far better statistical properties (López de Prado, Advances in Financial ML, ch. 2). Build them first, then run the other metrics on the resulting series.

from orderflow_metrics import tick_bars, volume_bars, dollar_bars

tick_bars(trades, 100)       # a bar per 100 trades
volume_bars(trades, 5_000)   # a bar per 5,000 units of volume
dollar_bars(trades, 250_000) # a bar per $250k of traded value

Each Bar carries open/high/low/close, volume, dollar, vwap, ticks, and signed buy_volume / sell_volume (plus start / end timestamps when the feed provides them). Dollar bars are usually preferred.

Execution scheduling

from orderflow_metrics import twap, pov

twap(100, 4)                    # [25, 25, 25, 25] — even time slices
pov(30, [100, 100, 100], 0.1)   # [10, 10, 10] — 10% of each interval's volume

Market impact

from orderflow_metrics import square_root_impact, almgren_chriss_cost, markout

square_root_impact(0.02, 1_000, 1_000_000)    # Y·σ·√(Q/V) — empirical impact
almgren_chriss_cost(10_000, 30, 1e-6, 2e-7)   # ImpactCost(permanent, temporary, total)
markout("buy", 100, 100.5)                    # +0.5 — price moved with the trade
  • square_root_impact — the empirical square-root law of impact
  • linear_permanent_impact / linear_temporary_impact — Almgren-Chriss terms
  • almgren_chriss_cost — expected TWAP cost, split into permanent vs temporary
  • markout / average_markout — realized post-trade adverse-selection drift

Implementation shortfall

from orderflow_metrics import implementation_shortfall, arrival_slippage_bps

implementation_shortfall("buy", 100, 100.5, 800, 1000, 101, 5)
# ShortfallResult(execution=400, opportunity=200, fees=5, total=605)

arrival_slippage_bps("buy", 100, 100.5)   # 50 bps paid up vs arrival
  • implementation_shortfall — Perold's execution + opportunity + fees decomposition
  • arrival_slippage_bps — signed slippage of the fill vs the arrival price

Tests

pip install -e ".[dev]"
pytest

License

MIT © RATE LTD (TwoWayMind). See LICENSE.


Part of TwoWayMind's open microstructure tooling. Educational and technical material only — not investment advice.

Metadata

Release files for orderflow-metrics 0.5.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for orderflow-metrics 0.5.0
File Size Uploaded
orderflow_metrics-0.5.0.tar.gz 21.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for orderflow-metrics 0.5.0
File Interpreter ABI Platform
orderflow_metrics-0.5.0-py3-none-any.whl Python 3 none any Details

Total release size: 47.1 kB

Release files / orderflow_metrics-0.5.0.tar.gz

Download URL orderflow_metrics-0.5.0.tar.gz
Size 21.6 kB
Tags Source
SHA-256 checksum
How to use checksums
581f5ec6898fecbd6bad6ced0eb6b756f19cdac21a55d38d2199926c4c8255bc
BLAKE2b-256 checksum
How to use checksums
64163b506dddca203f5f1be22c609925b70d5ba4067811ba7956297bdccce818
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 15, 2026.

Transparency log

Release files / orderflow_metrics-0.5.0-py3-none-any.whl

Download URL orderflow_metrics-0.5.0-py3-none-any.whl
Size 25.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
f18b94e1ffa3f0f10396b705310c34a1954797a9a8cfc557f94f70a6b7f3329d
BLAKE2b-256 checksum
How to use checksums
f77dea2f9be5a6a841e3efb94c6590eaf579055ea564e6b6a81027d17d8f577a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 15, 2026.

Transparency log

Release history Release notifications | RSS feed

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page