Python implementation of Order Flow Imbalance from Cont, Kukanov & Stoikov (2014), the most-cited empirical microstructure paper of the 2010s. Includes a synthetic LOB simulator with embedded latent alpha, the OFI vs TFI head-to-head regression, and a bucket-size sensitivity sweep that shows OFI dominates trade-flow across all sub-second timeframes.
Cont, R., Kukanov, A. & Stoikov, S. (2014). The price impact of order book events. Journal of Financial Econometrics 12(1): 47-88.
$ pytest tests/ -> 13 passed in 0.49s
$ python examples/run_regression.py
delta_mid = +0.0020 + +0.00005 * OFI R^2 = 0.974 t(beta) = +86.13
delta_mid = +0.0092 + -0.00001 * TFI R^2 = 0.000 t(beta) = -0.24
R^2 ratio (OFI / TFI) = 3261x
Companion repo to as-market-maker
and almgren-chriss:
the trio covers theoretical optimal control (passive + aggressive) and
the empirical signal that drives both.
In market microstructure, the question for decades was: what moves the mid? The pre-CKS answer was trade flow (Hasbrouck 1991, Kyle 1985): buys lift, sells press down, net signed volume regresses well on mid-changes.
CKS 2014 made a surprising claim: trades are downstream of order book events. The real signal lives in how the resting book changes - deeper bids appearing, asks retreating, levels improving. They define Order Flow Imbalance to capture this, then show empirically that on NASDAQ:
- OFI explains 60-75% of contemporaneous mid-price variance
- TFI (trade flow) explains 5-15%
- The OFI advantage persists from millisecond to minute scales
This repo provides a clean Python implementation of the OFI definition, plus a controlled synthetic LOB where you can vary parameters to understand what drives the gap.
For each pair of consecutive top-of-book snapshots (prev, curr), the
OFI increment e_n = e_n^bid + e_n^ask decomposes as:
+bid_qty_n if bid_px_n > bid_px_{n-1} (better bid)
e_n^bid = +Δbid_qty if bid_px_n = bid_px_{n-1} (size update)
-bid_qty_{n-1} if bid_px_n < bid_px_{n-1} (retreat)
-ask_qty_n if ask_px_n < ask_px_{n-1} (better ask)
e_n^ask = -Δask_qty if ask_px_n = ask_px_{n-1} (size update)
+ask_qty_{n-1} if ask_px_n > ask_px_{n-1} (retreat)
Sign convention: positive OFI = buying pressure. A better bid, a thicker bid, or a retreating ask all add positively. The mirrored condition on asks holds for selling pressure.
Per-bucket OFI is just the sum of increments over the events that fall inside the bucket. Cumulative OFI predicts cumulative mid change in that bucket - linear regression recovers the coefficient.
Real CKS data is paywalled NASDAQ ITCH. We build a deterministic
in-process generator (ofi/simulator.py) that mirrors the empirical
structure:
- A latent
alpha_tfollows an AR(1):alpha_{t+1} = phi * alpha_t + eps_t alpha_t > 0raises the probability of:- improving the bid, thickening the bid, retreating the ask
- buy-initiated market orders
- Each LOB action emits a fresh snapshot; each market order also.
- Trades fill the top of book; if size exceeds resting qty the price level moves (impact).
This means OFI and TFI are both partially driven by alpha, but the
LOB-event side picks up the signal earlier in the chain. The OFI
regression therefore wins, mirroring the paper.
(Caveat: synthetic R² are unrealistically high - real data has ~60-75%
for OFI. The qualitative ranking OFI >> TFI is what's faithful.)
| Regressor | Slope beta |
R^2 |
t(beta) |
|---|---|---|---|
| OFI | +5.0e-5 | 0.97 | +86.1 |
| TFI | -1.0e-5 | 0.0003 | -0.24 |
The OFI regression slope is 86 standard errors from zero; the TFI regression is statistically zero on this realization. R² ratio 3261×.
buckets bucket size R^2(OFI) R^2(TFI)
20 2000.0 ms 0.987 0.174
50 800.0 ms 0.979 0.058
100 400.0 ms 0.973 0.007
200 200.0 ms 0.977 0.016
400 100.0 ms 0.974 0.011
800 50.0 ms 0.970 0.017
1600 25.0 ms 0.961 0.009
OFI's R² is essentially flat across two decades of timescale; TFI is noise at sub-second scales and only becomes mildly predictive at the two-second bucket. The paper finds the same qualitative pattern on NASDAQ.
pytest tests/ covers:
- Six branches of the OFI increment formula (CKS eq. 2):
- bid: improves / same-price size delta / retreats (3 branches × pos/neg)
- ask: with mirrored sign convention
- Two-sided event: both sides change simultaneously - increments add
- Aggregation: events bucket into correct intervals; mid changes use forward-filled last-of-bucket prices to handle empty intervals
- TFI: signed trade quantities aggregate correctly
- OLS: perfect-fit recovery, zero-slope noise case
pip install -r requirements.txt
pytest tests/ # 13 passed
python examples/run_regression.py # the OFI vs TFI head-to-head
python examples/bucket_sensitivity.py # R^2 across timescalesofi/
events.py - BookSnapshot, Trade dataclasses
compute.py - e_increment, compute_ofi/tfi, aggregate_buckets
regression.py - lightweight OLS with R^2 + t-statistic
simulator.py - synthetic LOB with embedded alpha
tests/
test_ofi.py - 13 unit tests (formula + aggregation + regression)
examples/
run_regression.py - head-to-head plot
bucket_sensitivity.py - R^2 vs bucket size curve
- v0.2.0 - L2 OFI. CKS show in their 2014 paper that adding deeper
book levels (L2: top-3 or top-5) materially raises R² on real data.
Extend
BookSnapshotto carry depth, generalize the increment formula to weighted levels. - v0.2.0 alt - Real data ingestion. ITCH parser + Nasdaq sample data; demonstrate on real (not synthetic) prices.
- v0.3.0 - Cross-impact. Cont-Kukanov 2017 multi-asset OFI: level-1 events in correlated stocks contain information about each other.
- v0.3.0 alt - Permanent vs transient. Hasbrouck-style decomposition of mid-price impact into permanent (information) and transient (liquidity) components.
- Cont, R., Kukanov, A. & Stoikov, S. (2014). The price impact of order book events. Journal of Financial Econometrics 12(1): 47-88.
- Cont, R. & Kukanov, A. (2017). Optimal order placement in limit order markets. Quantitative Finance 17(1).
- Hasbrouck, J. (1991). Measuring the information content of stock trades. Journal of Finance 46(1): 179-207. (the trade-flow benchmark that OFI dethrones)
- Eisler, Z., Bouchaud, J.-P. & Kockelkoren, J. (2012). The price impact of order book events: market orders, limit orders, and cancellations. Quantitative Finance 12(9): 1395-1419. (independent derivation of the same idea)