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.21.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.21.0
File Size Uploaded
orderflow_metrics-0.21.0.tar.gz 44.3 kB Details

Built distribution (wheel)

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

Total release size: 92.5 kB

Release files / orderflow_metrics-0.21.0.tar.gz

Download URL orderflow_metrics-0.21.0.tar.gz
Size 44.3 kB
Tags Source
SHA-256 checksum
How to use checksums
79b946f24395d6fdc02adf5b936d99f59c5ce4f12c2b38e9e6103b221afa9f30
BLAKE2b-256 checksum
How to use checksums
f83aa9aacb5cf6965b91a83c00cd31795eade2cd2e319b432b33062214dfe3a5
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 Sep 3, 2026.

Transparency log

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

Download URL orderflow_metrics-0.21.0-py3-none-any.whl
Size 48.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
a7e99d34489a671588b152475bb67cb74633e681202265363b0d6ff72d1f7127
BLAKE2b-256 checksum
How to use checksums
144a540c06eb83b3fe6d19c51ce6f683018a345603d95ef86fa1a9987a80118f
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 Sep 3, 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