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.14.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.14.0
File Size Uploaded
orderflow_metrics-0.14.0.tar.gz 33.8 kB Details

Built distribution (wheel)

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

Total release size: 71.2 kB

Release files / orderflow_metrics-0.14.0.tar.gz

Download URL orderflow_metrics-0.14.0.tar.gz
Size 33.8 kB
Tags Source
SHA-256 checksum
How to use checksums
0c1385a882995ad3093bf73008d66ee6c4fdc2b9bd16037a11691f27ccf6227c
BLAKE2b-256 checksum
How to use checksums
c6457e6a71c0a937dd38c4a36712dd45bd293a15e362ca5a45931ceb2f71542e
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 27, 2026.

Transparency log

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

Download URL orderflow_metrics-0.14.0-py3-none-any.whl
Size 37.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e3d5c47022c212c84d35f699550114f913313276127809b859d41ee2d8aae1e9
BLAKE2b-256 checksum
How to use checksums
d22baf3d2201c517a59f9b79fe634a6f6247359212652cf1f5162ae8ee85042e
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 27, 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