Order Flow Imbalance: The Cont-Kukanov-Stoikov Event Decomposition
Sebagian besar sinyal yang diturunkan dari order book di blog ini adalah snapshot: berapa banyak volume yang sedang menunggu di setiap sisi saat ini. Ketidakseimbangan arus order adalah objek yang berbeda. Ini merupakan dekomposisi aliran pembaruan di antara dua snapshot menjadi satu nilai bertanda — yang menghitung pembatalan pada bid dengan cara yang sama seperti market sell.
Dekomposisi itu adalah pokok bahasan artikel ini. Tepatnya: indikator peristiwa Cont-Kukanov-Stoikov (2014) yang mendefinisikannya, ekstensi multi-level Xu-Gould-Howison (2019) beserta reduksi komponen utamanya, serta aturan Lee-Ready dan Bulk Volume Classification yang diperlukan ketika feed Anda tidak memberi label arah perdagangan.
Satu catatan kerangka di awal, karena ini menentukan cara membaca setiap angka di bawah. R-squared 50-65% yang terkenal dari paper CKS adalah regresi kontemporer: perubahan harga dalam suatu interval diregresikan terhadap arus order pada interval yang sama. Ini adalah dekomposisi pergerakan harga, bukan prakiraan pergerakan tersebut. Membandingkannya dengan 1-2% varians yang dijelaskan model return saham harian adalah perbandingan yang tidak sepadan, dan blog ini telah berargumen panjang — dalam DeepLOB dan kesenjangan prediksi-vs-profit serta hasil negatif yang jujur — bahwa mencampuradukkan keduanya adalah cara tutorial berubah menjadi jebakan. Regresi OFI yang sepenuhnya menggunakan lag adalah angka yang valid dan jauh lebih kecil. Artikel ini tidak melaporkannya.
Mengapa Arus Order, Bukan Perdagangan

Perubahan harga dalam limit order book kontinu terjadi melalui tepat empat mekanisme: market buy mengonsumsi ask yang menunggu; market sell mengonsumsi bid yang menunggu; pembatalan pada bid menghapus dukungan dan membuat bid turun; limit order baru pada ask menambah resistansi. Hanya dua yang pertama merupakan perdagangan. Dua yang terakhir tidak terlihat oleh ukuran berbasis volume — VWAP, on-balance volume, arus perdagangan bertanda — dan di sebagian besar venue rasio order terhadap perdagangan melebihi 10:1, sehingga bagian yang tidak terlihat adalah bagian yang besar. Seluruh klaim kegunaan OFI adalah bahwa ia memberi harga pada keempat mekanisme dengan skala yang sama. (Untuk order book sebagai struktur data dan vektor fitur snapshot standar , lihat DeepLOB.)
Model OFI Cont-Kukanov-Stoikov

Model dasar ini berasal dari paper Cont, Kukanov, dan Stoikov tahun 2014, "The Price Impact of Order Book Events" (Journal of Financial Econometrics).
Mendefinisikan Ketidakseimbangan Arus Order
Pertimbangkan harga best bid , harga best ask , serta ukurannya dan . Di antara observasi berurutan pada dan :
dengan kontribusi peristiwa sisi beli dan sisi jual sebagai berikut:
Dalam bahasa sederhana: jika harga best bid naik, minat beli baru muncul — hitung seluruh ukurannya sebagai positif. Jika turun, minat beli menghilang — kurangi ukuran lama. Jika harga tidak berubah, hitung hanya perubahan ukuran. Sisi ask adalah bayangannya.
Keunggulannya adalah tiga cabang indikator ini mencakup setiap transisi yang mungkin pada puncak order book, sehingga setiap pembaruan dipetakan tepat ke satu angka bertanda. Tidak perlu klasifikasi perdagangan, label sisi, atau feed tingkat pesan — dua snapshot berurutan sudah cukup.
Agregasi Antarinterval
Untuk interval yang memuat pembaruan order book:
Model Dampak Harga Linear
dengan sebagai perubahan mid-price, sebagai koefisien dampak harga, dan sebagai noise residual. Pada saham AS dalam interval 10 detik hingga 1 menit, CKS melaporkan kontemporer sebesar 50-65% per saham. Sekali lagi: interval yang sama, bukan prediksi ke depan.
Penskalaan Lintas Seksi
CKS juga menunjukkan bahwa koefisien dampak berskala berbanding terbalik dengan kedalaman:
dengan sebagai volume resting rata-rata pada best bid dan ask. Arus yang sama mendorong harga lebih jauh pada order book yang tipis. Ini adalah satu bagian model yang berpindah antarvenue tanpa perlu memfit ulang levelnya, karena memprediksi hubungan, bukan angka — dan dapat langsung diuji pada pasangan kripto dengan kedalaman berbeda.
Ketidakseimbangan Arus Order Multi-Level (MLOFI)

Model asli hanya menggunakan puncak order book. Xu, Gould, dan Howison (2019) memperluasnya hingga level.
Definisi
dengan menerapkan formula tiga cabang yang sama pada pasangan bid/ask level ke-.
Dampak Harga Multi-Level
Temuan yang dipublikasikan pada saham Nasdaq adalah bahwa setiap level tambahan menambah out-of-sample — kira-kira 10-15 poin persentase dari satu level ke lima, dengan kenaikan marginal masih ada pada level sepuluh. Koefisien menurun secara monoton, : puncak order book mendominasi, tetapi level yang lebih dalam membawa sinyal inkremental yang tidak sepele.
Apakah ini bertahan pada order book kripto adalah satu-satunya pertanyaan terbuka paling menarik dalam artikel ini. Order book kripto lebih tipis dan jauh lebih sering berubah di kedalaman, sehingga sangat mungkin level 2-5 tidak menambah apa pun setelah Anda meninggalkan order book Nasdaq.
Reduksi Komponen Utama
OFI pada level yang berdekatan sangat berkorelasi (di atas 0.8 dalam hasil saham yang dipublikasikan), sehingga dekomposisi komponen utama merupakan pilihan alami. Komponen pertama yang dilaporkan menangkap lebih dari 89% total varians dan berfungsi sebagai satu sinyal agregat:
dengan sebagai eigenvector utama matriks kovarians OFI. Daya tarik praktisnya adalah ia mereduksi regresi kolinear menjadi satu skalar yang terkondisi baik — layak dilakukan bahkan jika porsi varians pada data Anda ternyata lebih rendah.
Mengklasifikasikan Perdagangan: Dimulai Beli vs Jual

OFI sendiri tidak memerlukan klasifikasi perdagangan. Namun jika Anda ingin membandingkannya dengan ukuran berbasis perdagangan, atau hanya memiliki bar agregat, Anda perlu menginferensikan arah.
Aturan Kuotasi
Bandingkan harga perdagangan dengan midpoint yang berlaku :
Perdagangan di atas midpoint kemungkinan dilakukan pembeli yang mengangkat offer; di bawahnya, penjual yang menekan bid.
Algoritme Lee-Ready (1991) adalah aturan kuotasi dengan fallback aturan tick untuk perdagangan tepat di midpoint, ketika aturan kuotasi tidak menentukan. Aturan tick — tanda perubahan harga terakhir, dengan sisi sebelumnya diteruskan pada tick nol — sudah diturunkan dan diimplementasikan dalam Beyond time bars, yang menyediakan _tick_sign() yang siap digunakan. Akurasi klasifikasi Lee-Ready yang dilaporkan adalah 72-85%, bergantung pada pasar dan periode.
Klasifikasi Volume Agregat (BVC)
Ketika perdagangan individual tidak dapat diberi klasifikasi — bar agregat, sebagian besar API candle publik — Bulk Volume Classification milik Easley, Lopez de Prado, dan O'Hara memperkirakan fraksi beli dari volume sebuah bar berdasarkan perubahan harganya yang dinormalisasi:
dengan sebagai CDF normal standar dan diestimasi dari perubahan harga terbaru. Kurang akurat dibanding klasifikasi tingkat tick, tetapi bekerja pada OHLCV.
Apa yang Bukan OFI

Tiga besaran yang berdekatan sering disamakan dengan OFI. Masing-masing dibahas dengan benar di tempat lain dalam blog ini; pembedaan inilah yang penting di sini.
Static order book imbalance (OBI) adalah versi snapshot — volume bid yang menunggu dibanding volume ask yang menunggu, tanpa pelacakan peristiwa. Lihat fitur LOB tradisional DeepLOB untuk formulanya dan bentuk multi-levelnya. Kontras inilah inti OFI: OBI memberi tahu keadaan order book, OFI memberi tahu bagaimana keadaan itu terbentuk.
Trade imbalance (TI) dan variannya yang berbobot volume adalah arus perdagangan bertanda, yang didefinisikan dan diimplementasikan sebagai fitur bergulir dalam pemodelan spread dengan machine learning. Satu hasil terpublikasi tentang hubungan ini sangat penting: ketika OFI dan TI dimasukkan bersama sebagai regresor pada perubahan mid-price, TI menjadi tidak signifikan secara statistik. Isinya terserap. Inilah kasus empiris untuk melacak peristiwa order book alih-alih perdagangan — peristiwa yang hampir menjadi perdagangan membawa informasi yang sama dengan peristiwa yang benar-benar terjadi.
Mid berbobot volume adalah estimator nilai wajar, bukan ukuran ketidakseimbangan, dan dibahas dalam DeepLOB — termasuk catatan penamaan bahwa ia bukan micro-price Stoikov, yang merupakan estimator yang disesuaikan dengan martingale dan dibangun tepat karena mid berbobot naif bersifat bias.
Implementasi Python

Implementasi langsung dekomposisi CKS, yang digeneralisasi hingga level.
Perhitungan OFI Inti
import numpy as np
import pandas as pd
from dataclasses import dataclass, field
from typing import Optional
@dataclass
class OrderBookSnapshot:
timestamp: float
bid_prices: np.ndarray # best bid at index 0, descending
ask_prices: np.ndarray # best ask at index 0, ascending
bid_sizes: np.ndarray
ask_sizes: np.ndarray
@dataclass
class OFICalculator:
"""
Computes Order Flow Imbalance from consecutive order book snapshots.
Supports multi-level OFI (MLOFI) up to `n_levels` deep.
"""
n_levels: int = 5
prev_snapshot: Optional[OrderBookSnapshot] = field(default=None, init=False)
def compute_level_ofi(
self,
prev_price: float, curr_price: float,
prev_size: float, curr_size: float,
side: str
) -> float:
"""Compute single-level OFI contribution for bid or ask side."""
if side == "bid":
if curr_price > prev_price:
return curr_size # new level appeared above
elif curr_price < prev_price:
return -prev_size # old level disappeared
else:
return curr_size - prev_size # same level, size changed
else: # ask side
if curr_price < prev_price:
return curr_size # new level appeared below
elif curr_price > prev_price:
return -prev_size # old level disappeared
else:
return curr_size - prev_size # same level, size changed
def update(self, snapshot: OrderBookSnapshot) -> Optional[np.ndarray]:
"""
Process new snapshot, return MLOFI vector of shape (n_levels,).
Returns None on first call (no previous snapshot to compare).
"""
if self.prev_snapshot is None:
self.prev_snapshot = snapshot
return None
prev = self.prev_snapshot
n = min(self.n_levels, len(snapshot.bid_prices), len(prev.bid_prices))
ofi = np.zeros(n)
for level in range(n):
e_buy = self.compute_level_ofi(
prev.bid_prices[level], snapshot.bid_prices[level],
prev.bid_sizes[level], snapshot.bid_sizes[level],
side="bid"
)
e_sell = self.compute_level_ofi(
prev.ask_prices[level], snapshot.ask_prices[level],
prev.ask_sizes[level], snapshot.ask_sizes[level],
side="ask"
)
ofi[level] = e_buy - e_sell
self.prev_snapshot = snapshot
return ofi
Agregasi Ke Dalam Jendela
@dataclass
class OFIAggregator:
"""
Aggregates raw OFI updates into fixed time windows.
Emits the regression inputs (aggregated MLOFI) and target (delta mid).
"""
window_seconds: float = 10.0
n_levels: int = 5
calculator: OFICalculator = field(init=False)
buffer: list = field(default_factory=list, init=False)
window_start: float = 0.0
def __post_init__(self):
self.calculator = OFICalculator(n_levels=self.n_levels)
def on_snapshot(self, snapshot: OrderBookSnapshot) -> Optional[dict]:
"""
Feed a new order book snapshot.
Returns aggregated window dict when a window completes, else None.
"""
ofi_vec = self.calculator.update(snapshot)
if ofi_vec is None:
self.window_start = snapshot.timestamp
return None
if not self.buffer:
self.window_start = snapshot.timestamp
self.buffer.append({
"timestamp": snapshot.timestamp,
"ofi": ofi_vec.copy(),
"mid": (snapshot.bid_prices[0] + snapshot.ask_prices[0]) / 2,
})
elapsed = snapshot.timestamp - self.window_start
if elapsed >= self.window_seconds:
return self._flush()
return None
def _flush(self) -> dict:
"""Aggregate buffered OFI updates into a single window record."""
ofi_matrix = np.array([b["ofi"] for b in self.buffer])
agg_ofi = ofi_matrix.sum(axis=0) # shape: (n_levels,)
result = {
"window_start": self.window_start,
"window_end": self.buffer[-1]["timestamp"],
"n_updates": len(self.buffer),
"mid_open": self.buffer[0]["mid"],
"mid_close": self.buffer[-1]["mid"],
"delta_mid": self.buffer[-1]["mid"] - self.buffer[0]["mid"],
"ofi_level1": agg_ofi[0],
"ofi_total": agg_ofi.sum(),
"mlofi": agg_ofi,
}
self.buffer.clear()
return result
Perhatikan keluaran agregator: mlofi dan delta_mid berada pada jendela yang sama. Itulah regresi kontemporer. Untuk memperoleh versi prediktif, pasangkan mlofi milik jendela dengan delta_mid milik jendela dan perkirakan fit yang jauh lebih buruk.
Klasifikasi Perdagangan (Lee-Ready)
def classify_trades_lee_ready(
trades: pd.DataFrame,
quotes: pd.DataFrame
) -> pd.DataFrame:
"""
Classify trades as buy (+1) or sell (-1) using Lee-Ready:
quote rule first, tick rule as fallback at the midpoint.
Parameters
----------
trades : DataFrame with columns ['timestamp', 'price', 'size']
quotes : DataFrame with columns ['timestamp', 'bid', 'ask']
Returns
-------
trades with added 'side' column
"""
trades = trades.sort_values("timestamp").copy()
quotes = quotes.sort_values("timestamp")
trades = pd.merge_asof(
trades, quotes,
on="timestamp",
direction="backward"
)
trades["mid"] = (trades["bid"] + trades["ask"]) / 2
trades["side"] = np.where(
trades["price"] > trades["mid"], 1,
np.where(trades["price"] < trades["mid"], -1, 0)
)
trades["price_diff"] = trades["price"].diff()
tick_sign = np.sign(trades["price_diff"])
tick_sign = tick_sign.replace(0, np.nan).ffill().fillna(1)
midpoint_mask = trades["side"] == 0
trades.loc[midpoint_mask, "side"] = tick_sign[midpoint_mask].astype(int)
return trades
Normalisasi Sinyal
class OFISignal:
"""
Rolling z-score normalization of aggregated OFI.
Deliberately does NOT convert OFI into a predicted return: that
requires a fitted beta, and beta is venue-, pair- and regime-specific.
Fit it on your own data before wiring this into anything.
"""
def __init__(self, window_seconds: float = 10.0, n_levels: int = 5,
lookback: int = 100):
self.aggregator = OFIAggregator(
window_seconds=window_seconds, n_levels=n_levels,
)
self.lookback = lookback
self.ofi_history: list[float] = []
def process(self, snapshot: OrderBookSnapshot) -> Optional[dict]:
agg = self.aggregator.on_snapshot(snapshot)
if agg is None:
return None
ofi = agg["ofi_level1"]
self.ofi_history.append(ofi)
if len(self.ofi_history) > self.lookback:
self.ofi_history.pop(0)
if len(self.ofi_history) >= 20:
arr = np.array(self.ofi_history)
mu, sigma = arr.mean(), arr.std()
zscore = (ofi - mu) / max(sigma, 1e-10)
else:
zscore = 0.0
return {**agg, "ofi_zscore": zscore}
Di Mana OFI Dipasang

Market making. OFI masuk sebagai komponen skew prediktif pada fair value, di atas inventory skew yang telah diturunkan dan dikodekan dalam market maker Avellaneda-Stoikov: . Kedua komponen menjawab pertanyaan yang berbeda — komponen flow menunjukkan ke mana harga bergerak, komponen inventory menunjukkan apa yang mampu Anda tahan — dan artikel yang dipublikasikan membahas komponen kedua, termasuk alasan inventory positif mendorong kedua kuotasi turun. Nilai yang besar juga merupakan pemicu adverse selection yang wajar untuk respons defensif (memperlebar, mengecilkan, menarik satu sisi) yang dikatalogkan dalam sidik jari digital identifikasi trader dan deteksi anomali.
Eksekusi. OFI adalah input bagi estimasi probabilitas fill pada lapisan taktik, bukan pengendali urgensi terpisah. Keputusan post-versus-cross adalah aritmetika break-even eksplisit — dengan — dan berada dalam taktik eksekusi child order, yang juga menegaskan bahwa lapisan taktik tidak boleh menurunkan ulang urgensi dari pandangannya sendiri atas pasar, karena itu menciptakan dua pengendali yang saling bertentangan.
Pertimbangan Praktis

Paruh waktu sinyal dan kalibrasi ulang bergulir. Inilah bagian khusus OFI. Kandungan prediktif OFI meluruh pada skala waktu milidetik hingga detik dalam instrumen likuid, sehingga jendela agregasi bukan parameter bebas — melainkan taruhan pada horizon. Dan bukan konstanta: nilainya bergerak sepanjang hari, bersama kedalaman, dan di sekitar peristiwa terjadwal, sehingga setiap fit produksi mengestimasi ulangnya pada jendela bergulir alih-alih mematok nilai dari backtest.
Hal lain di sini dibahas di tempat lain. Anggaran latensi dan tangga co-location / FPGA / kernel-bypass: bagian produksi DeepLOB. Pola likuiditas intraday berbentuk U dan statistik normalisasi yang bergeser: pemodelan spread. Kalibrasi ulang per venue dan alasan model yang difit pada Nasdaq tidak akan berpindah ke pasangan kripto tanpa perubahan: DeepLOB lagi, dengan sisi fragmentasinya dalam smart order routing.
Manipulasi. Satu konsekuensi yang spesifik pada model ini dan layak dinyatakan terus terang: dekomposisi CKS membobot setiap peristiwa hanya berdasarkan ukuran, tanpa konsep niat atau persistensi. Karena itu spoofer yang memasang dan membatalkan ukuran langsung menyuntikkannya ke dalam sinyal dengan bobot penuh, sesuai konstruksinya. Heuristik deteksi — tingkat pembatalan, umur order, perilaku wall saat harga mendekat — ada dalam analisis posisi antrean dan wall order book; likuiditas hantu lintas venue ada dalam smart order routing.
Inti Kesimpulan

-
OFI adalah dekomposisi peristiwa, bukan snapshot. Formula indikator tiga cabang memetakan setiap transisi puncak order book — harga naik, harga turun, perubahan ukuran — menjadi satu angka bertanda, hanya dari dua snapshot berurutan.
-
R-squared utama bersifat kontemporer. Angka CKS 50-65% menguraikan pergerakan harga pada interval yang sama; itu bukan prakiraan dan tidak boleh dibandingkan dengan model return yang melihat ke depan.
-
OFI multi-level menambah level dan PCA mereduksinya. Hasil incremental- dan varians 89% yang dipublikasikan berasal dari saham Nasdaq. Apakah kedalaman tetap membantu pada order book kripto belum diuji di sini.
-
OFI menyerap trade imbalance. Ketika dimasukkan bersama, TI menjadi tidak signifikan — pembatalan yang dilihat OFI tetapi tidak dapat dilihat TI adalah sumber perbedaannya.
-
Model ini buta terhadap niat. Pembobotan yang sama berdasarkan ukuran adalah tepat hal yang membuatnya dapat dipalsukan melalui spoofing.
-
Tidak ada yang diukur dalam artikel ini. Setiap angka yang dikutip berasal dari literatur saham. Sebelum sinyal ini menyentuh modal, diperlukan fit pada data order book Anda sendiri, spesifikasi lag yang dilaporkan terpisah, serta pemeriksaan apakah keunggulannya bertahan setelah biaya dan spread.
Bacaan Lanjutan

- Cont, R., Kukanov, A., & Stoikov, S. (2014). "Dampak Harga Peristiwa Order Book." Journal of Financial Econometrics, 12(1), 47-88.
- Xu, K., Gould, M., & Howison, S. (2019). "Ketidakseimbangan Arus Order Multi-Level dalam Limit Order Book." arXiv:1907.06230.
- Kolm, P., Turiel, J., & Westray, N. (2023). "Ketidakseimbangan Arus Order Mendalam: Mengekstrak Alpha pada Berbagai Horizon dari Limit Order Book." Mathematical Finance, 33(4).
- Lee, C., & Ready, M. (1991). "Menyimpulkan Arah Perdagangan dari Data Intraday." Journal of Finance, 46(2), 733-746.
- Easley, D., Lopez de Prado, M., & O'Hara, M. (2012). "Toksisitas Arus dan Likuiditas dalam Dunia Frekuensi Tinggi." Review of Financial Studies, 25(5), 1457-1493.
Penulis
Trading-systems engineer
Trading-systems engineer building bots since 2017: cross-exchange arbitrage (connected up to 30 venues), cointegration-based pairs arbitrage across spot and futures, scalping, news and sentiment-driven strategies, trend algorithms, and portfolio management and balancing algorithms. Also builds sub-millisecond order execution, big-data warehouses, backtesting engines, AI agents, and trading interfaces (incl. open-source profitmaker.cc). Stack: JS/TS, Python, Rust/Zig/Go, DevOps, backend, frontend, architecture.