← Kembali ke artikel
May 26, 2026
5 menit baca

DeepLOB: Deep Learning pada Limit Order Book

DeepLOB: Deep Learning pada Limit Order Book
#deep-learning
#order-book
#LOB
#microstructure
#HFT
#market-making
📖
Part 5 of 6 · Collection
Order Book & Market Microstructure

Limit order book adalah struktur data sentral dari pasar elektronik modern. Setiap bid, setiap ask, setiap pembatalan — semuanya tersimpan di dalam LOB. Selama puluhan tahun, peneliti kuantitatif telah merancang fitur secara manual dari data ini: rasio order imbalance, weighted mid-price, sinyal posisi antrean. DeepLOB menempuh jalur yang berbeda — ia mempelajari fitur-fitur ini secara langsung dari snapshot order book mentah menggunakan arsitektur hibrida CNN-LSTM.

Diterbitkan oleh Zhang, Zohren, dan Roberts di Oxford-Man Institute pada tahun 2019, DeepLOB menunjukkan bahwa sebuah jaringan deep tunggal, yang dilatih secara end-to-end pada data book mentah, mampu bersaing dengan atau bahkan lebih baik daripada baseline klasik yang kuat dalam memprediksi pergerakan mid-price. Namun kita perlu cermat soal buktinya. Dataset benchmark FI-2010 adalah yang paling sering dikutip oleh banyak paper, tetapi para penulisnya sendiri menyebutnya tidak memadai — "terlalu pendek, di-downsample, dan diambil dari pasar yang kurang likuid" — dan menyajikan evaluasi kedua yang jauh lebih besar pada data London Stock Exchange (LSE) sebagai hasil mereka yang lebih kuat. Studi LSE itu mencakup kira-kira satu tahun dari lima saham pelatihan dan lima saham pengujian, dengan jumlah sampel sekitar 100 juta lebih, dan menunjukkan transfer learning: sebuah model yang dilatih pada satu set saham tetap dapat memprediksi pada saham yang belum pernah dilihat. Hasil transfer itu, bukan papan peringkat FI-2010, yang merupakan headline sesungguhnya dari paper tersebut. Tulisan ini membedah arsitekturnya, matematikanya, angka-angka yang sebenarnya, dan sebuah reimplementasi PyTorch yang berfungsi.

Limit Order Book sebagai Struktur Data

Tampilan isometrik dari limit order book: level volume bid dan ask yang bertumpuk membentuk tensor kedalaman di sekitar mid-price

Sebuah limit order book mengelola dua daftar terurut — bid (order beli) dan ask (order jual) — masing-masing diatur berdasarkan level harga. Pada setiap level, book mencatat harga dan volume agregat dari order yang menunggu.

Untuk sebuah order book dengan LL level, sebuah snapshot tunggal pada waktu tt adalah vektor berisi 4L4L nilai:

xt=[p1a,v1a,p1b,v1b,p2a,v2a,p2b,v2b,,pLa,vLa,pLb,vLb]\mathbf{x}_t = [p_1^{a}, v_1^{a}, p_1^{b}, v_1^{b}, p_2^{a}, v_2^{a}, p_2^{b}, v_2^{b}, \ldots, p_L^{a}, v_L^{a}, p_L^{b}, v_L^{b}]

di mana piap_i^{a} dan viav_i^{a} adalah harga dan volume ask pada level ii, dan pibp_i^{b}, vibv_i^{b} adalah nilai-nilai yang bersesuaian pada sisi bid. Level 1 menyimpan best bid dan best ask (BBO); selisihnya adalah bid-ask spread.

Dalam dataset benchmark FI-2010, L=10L = 10, sehingga menghasilkan 40 fitur per snapshot. FI-2010 dibangun dari kira-kira 4 juta pesan limit-order mentah dari lima ekuitas Finlandia di NASDAQ Nordic (Kesko, Outokumpu, Sampo, Rautaruukki, Wartsila) selama sepuluh hari perdagangan berturut-turut, 1-14 Juni 2010. Yang penting, DeepLOB tidak dilatih pada 4 juta snapshot: benchmark men-downsample pesan-pesan tersebut (setiap 10 event) menjadi sebuah representasi ternormalisasi berisi 394.337 sampel. Bentuk yang sudah di-downsample dan dinormalisasi itulah yang sebenarnya dilihat oleh model — salah satu alasan mengapa para penulis memperingatkan agar tidak memperlakukan FI-2010 sebagai kata akhir.

Mid-Price dan Pergerakannya

Mid-price pada waktu tt adalah rata-rata dari best bid dan ask:

ptmid=p1a(t)+p1b(t)2p_t^{mid} = \frac{p_1^{a}(t) + p_1^{b}(t)}{2}

DeepLOB memprediksi arah pergerakan mid-price pada horizon masa depan sebanyak kk event. Label-nya adalah return yang dihaluskan, tetapi perlu disadari bahwa ada dua konvensi penghalusan dalam literatur, dan keduanya tidak dapat dipertukarkan:

  • Rata-rata masa depan vs harga saat ini (Tsantekidis et al.): bandingkan rata-rata mid-price selama kk event berikutnya dengan mid-price mentah saat ini.
  • Rata-rata masa depan vs rata-rata sebelumnya (Ntakaris et al., label FI-2010 kanonik, yang juga digunakan DeepLOB untuk data LSE-nya): baik referensi maupun targetnya dihaluskan.
lt(k)=m+(t)m(t)m(t),m(t)=1ki=0k1ptimid,m+(t)=1ki=1kpt+imidl_t(k) = \frac{m_+(t) - m_-(t)}{m_-(t)}, \qquad m_-(t) = \frac{1}{k}\sum_{i=0}^{k-1} p_{t-i}^{mid}, \quad m_+(t) = \frac{1}{k}\sum_{i=1}^{k} p_{t+i}^{mid}

Menghaluskan referensi (bukan hanya masa depan) secara material mengurangi noise label dari fluktuasi single-tick, itulah sebabnya bentuk rata-rata sebelumnya/berikutnya lebih dipilih. Apa pun yang Anda gunakan, return kontinu didiskretisasi menjadi tiga kelas — naik, turun, stasioner — menggunakan ambang batas tetap ±α\pm\alpha:

yt={1jika lt(k)>α0jika lt(k)α1jika lt(k)<αy_t = \begin{cases} 1 & \text{jika } l_t(k) > \alpha \\ 0 & \text{jika } |l_t(k)| \leq \alpha \\ -1 & \text{jika } l_t(k) < -\alpha \end{cases}

Dataset FI-2010 menyediakan label untuk lima horizon prediksi: k{10,20,30,50,100}k \in \{10, 20, 30, 50, 100\} event.

Fitur LOB Tradisional

Sebelum deep learning, para peneliti mengandalkan fitur yang dirancang secara manual. Memahami fitur-fitur ini penting, karena DeepLOB secara sengaja disusun agar menyerupai banyak di antaranya — arsitekturnya dimotivasi oleh kuantitas-kuantitas ini bahkan ketika ia tidak mereproduksinya secara persis.

Order Book Imbalance (OBI)

Sinyal mikrostruktur yang paling banyak digunakan. Pada puncak book:

OBI1=v1bv1av1b+v1a\text{OBI}_1 = \frac{v_1^{b} - v_1^{a}}{v_1^{b} + v_1^{a}}

Volume bid yang lebih besar relatif terhadap volume ask mengindikasikan tekanan naik. Imbalance multi-level mengagregasi lintas LL level:

OBIL=i=1Lvibi=1Lviai=1Lvib+i=1Lvia\text{OBI}_L = \frac{\sum_{i=1}^{L} v_i^{b} - \sum_{i=1}^{L} v_i^{a}}{\sum_{i=1}^{L} v_i^{b} + \sum_{i=1}^{L} v_i^{a}}

Volume-Weighted Mid-Price

Mid-price standar memberi bobot yang sama pada kedua sisi. Volume-weighted mid-price (disebut juga weighted mid, atau VAMP) condong ke sisi book yang lebih berat. Dengan menuliskan imbalance pada puncak book sebagai I=v1b/(v1b+v1a)I = v_1^{b}/(v_1^{b}+v_1^{a}), ia merupakan rata-rata kedua harga yang diberi bobot imbalance:

pwmid=Ip1a+(1I)p1b=v1bp1a+v1ap1bv1b+v1ap^{wmid} = I\, p_1^{a} + (1 - I)\, p_1^{b} = \frac{v_1^{b}\, p_1^{a} + v_1^{a}\, p_1^{b}}{v_1^{b} + v_1^{a}}

Perhatikan pembobotan silang: harga ask diberi bobot oleh volume bid dan sebaliknya. Ketika volume bid mendominasi (I1I \to 1), weighted mid bergeser ke arah ask — mencerminkan ekspektasi bahwa book yang tidak seimbang akan terselesaikan dengan bergerak ke sisi yang lebih berat.

Sepatah peringatan soal penamaan. Weighted mid statis berbasis volume ini bukanlah microprice dari Stoikov. Micro-price dari Stoikov (2018) adalah sebuah estimator yang disesuaikan secara martingale Mt+g(I,S)M_t + g(I, S) yang diperoleh dari koreksi rekursif atas bagaimana spread dan imbalance berevolusi — inti argumennya adalah bahwa weighted mid naif itu bias dan bukan sebuah martingale. Keduanya adalah dua objek yang berbeda; kita menggunakan weighted mid di sini karena kesederhanaannya, bukan sebagai pengganti microprice.

Depth Imbalance

Mengukur bentuk book di luar BBO:

DIi=vibviavib+via,i=1,,L\text{DI}_i = \frac{v_i^{b} - v_i^{a}}{v_i^{b} + v_i^{a}}, \quad i = 1, \ldots, L

Spread dan Relative Spread

st=p1a(t)p1b(t),strel=stptmids_t = p_1^{a}(t) - p_1^{b}(t), \qquad s_t^{rel} = \frac{s_t}{p_t^{mid}}

Fitur-fitur ini kuat namun terbatas. Mereka membutuhkan keahlian domain untuk dirancang, tidak menangkap interaksi nonlinier yang kompleks, dan mengabaikan dinamika temporal lintas snapshot yang berurutan. DeepLOB mengatasi ketiga keterbatasan ini.

Arsitektur DeepLOB

Arsitektur DeepLOB: tensor order-book mentah mengalir melalui lapisan konvolusional, modul inception, dan LSTM

Arsitekturnya memiliki tiga blok, masing-masing dengan peran yang berbeda:

  1. Blok konvolusional — mengekstraksi fitur spasial dari snapshot order book
  2. Modul inception — menangkap pola temporal multi-skala
  3. Blok LSTM — memodelkan dependensi sekuensial sepanjang waktu

Input ke jaringan adalah tensor berbentuk (T,L×4)(T, L \times 4), di mana TT adalah jendela lookback (100 timestep dalam paper) dan L×4=40L \times 4 = 40 untuk 10 level harga dan volume pada kedua sisi.

Blok 1: Ekstraksi Fitur Konvolusional

Lapisan konvolusional pertama beroperasi sepanjang dimensi fitur untuk mempelajari interaksi antara harga dan volume pada setiap level.

Lapisan 1: Sebuah konvolusi dengan ukuran filter 1×21 \times 2 dan stride (1,2)(1, 2) yang diterapkan pada setiap pasangan harga-volume. Ini merangkum setiap pasangan (pi,vi)(p_i, v_i) menjadi sebuah fitur tunggal — analog dengan menghitung sebuah "interaksi harga-volume" pada setiap level. Lebarnya menyusut dari 40 menjadi 20.

Lapisan 2: Sebuah konvolusi 1×21 \times 2, stride (1,2)(1, 2) yang beroperasi lintas pasangan bid-ask yang cocok pada level yang sama. Ini menangkap informasi spread dan imbalance per level. Lebarnya menyusut dari 20 menjadi 10.

Lapisan 3: Sebuah konvolusi 1×101 \times 10 yang mengintegrasikan lintas seluruh 10 level, menciutkan dimensi kedalaman menjadi lebar 1. Ini menghasilkan sebuah fitur agregat tunggal per timestep yang mengenkode seluruh profil kedalaman.

Setiap langkah 1×21 \times 2 / 1×101 \times 10 diikuti oleh dua konvolusi (4,1)(4, 1) sepanjang sumbu waktu, masing-masing dengan aktivasi LeakyReLU dan batch normalization. Perhatikan bahwa konvolusi (4,1)(4, 1) ini dengan padding=(1, 0) tidak mempertahankan dimensi waktu: masing-masing memperpendeknya sebanyak satu langkah (Tout=Tin1T_{\text{out}} = T_{\text{in}} - 1). Lintas enam lapisan semacam itu di blok 1-3, sumbu waktu menyusut dari 100 menjadi 94 sebelum modul inception — sesuatu yang dibuat eksplisit oleh komentar bentuk (shape) dalam kode di bawah ini.

Desain ini secara sengaja menghindari filter spasial yang besar. Filter 1×21 \times 2 menghormati struktur berpasangan alami dari data LOB — harga dengan volume, bid dengan ask. Bias induktif ini sangat penting: filter 3×33 \times 3 akan mencampur level dan sisi yang berdekatan dengan cara yang tidak memiliki makna finansial.

Blok 2: Modul Inception

Setelah blok konvolusional mereduksi 40 fitur menjadi representasi spasial yang ringkas (lebar 1), modul inception beroperasi sepanjang dimensi waktu untuk menangkap pola pada berbagai skala temporal secara simultan.

Modul inception DeepLOB memiliki empat jalur paralel, masing-masing menghasilkan 32 channel, semuanya digabungkan (concatenated):

  • bottleneck 1×11 \times 1 \to konvolusi temporal 3×13 \times 1: pola temporal jangka pendek (3 timestep)
  • bottleneck 1×11 \times 1 \to konvolusi temporal 5×15 \times 1: pola temporal jangka menengah (5 timestep)
  • max-pool 3×13 \times 1 \to konvolusi 1×11 \times 1: sebuah jalur pooling yang mempertahankan tampilan yang dihaluskan dan di-downsample
  • (reduksi 1×11 \times 1 berfungsi sebagai bottleneck point-in-time sebelum konvolusi temporal)

Setiap jalur temporal menggunakan padding simetris sehingga dimensi waktu dipertahankan di dalam blok inception (berbeda dengan blok konvolusi di atas). Output-nya digabungkan sepanjang dimensi channel, memberikan jaringan akses ke fitur temporal multi-skala sekaligus.

Ini terinspirasi oleh arsitektur inception GoogLeNet, tetapi diadaptasi untuk data temporal 1D alih-alih citra 2D. Wawasan kuncinya adalah bahwa dinamika LOB beroperasi pada berbagai skala waktu: noise tick-demi-tick, momentum jangka pendek, dan mean reversion horizon yang lebih panjang semuanya berkoeksistensi.

Reimplementasi PyTorch di bawah ini menyajikan varian tiga jalur yang disederhanakan (dua konvolusi temporal ditambah satu jalur 1×11\times1) agar kodenya tetap mudah dibaca; ia mengabaikan jalur max-pool. Kami menyampaikan ini secara eksplisit karena ini merupakan penyimpangan dari paper, bukan modul aslinya.

Blok 3: Pemodelan Sekuens LSTM

Output dari modul inception diumpankan ke sebuah lapisan LSTM yang memproses seluruh sekuens sepanjang TT. LSTM menangkap dependensi temporal jangka panjang yang akan terlewat jika hanya mengandalkan konvolusi — perubahan rezim, efek waktu-hari, dan kondisi pasar yang berkembang.

Hidden state akhir dari LSTM diteruskan melalui sebuah lapisan fully connected dengan aktivasi softmax untuk menghasilkan distribusi probabilitas atas tiga kelas (naik, turun, stasioner).

Fungsi Loss

Model dilatih dengan categorical cross-entropy:

L=1Ni=1Nc=13yi,clog(y^i,c)\mathcal{L} = -\frac{1}{N} \sum_{i=1}^{N} \sum_{c=1}^{3} y_{i,c} \log(\hat{y}_{i,c})

di mana yi,cy_{i,c} adalah label sebenarnya yang dienkode one-hot dan y^i,c\hat{y}_{i,c} adalah probabilitas prediksi untuk kelas cc.

Reimplementasi PyTorch

DeepLOB asli dibangun di Keras pada backend TensorFlow; repositori para penulis (zcakhaa) kemudian menambahkan port PyTorch. Kode di bawah ini adalah reimplementasi PyTorch ilustratif buatan kami sendiri, bukan yang resmi. Ia menyimpang dari paper dalam dua hal yang kami tandai secara inline: ia mengabaikan jalur max-pool inception (tiga jalur alih-alih empat), dan ia menskalakan jumlah channel ke atas. Paper menggunakan 16 filter di seluruh blok konvolusi dan 32 filter per jalur inception (input LSTM 3×32=963 \times 32 = 96), menghasilkan model ringkas dengan kira-kira 60 ribu parameter. Cuplikan di bawah ini menggunakan 32 filter konvolusi / 64 filter inception (input LSTM 192) — konsisten secara internal dan dapat dijalankan, tetapi lebih berat daripada yang asli. Untuk menyamai paper, atur channel konvolusi menjadi 16, channel inception menjadi 32, dan input_size=96.

import torch
import torch.nn as nn


class DeepLOB(nn.Module):
    """
    DeepLOB-style CNN-Inception-LSTM for limit order books.
    Reimplementation inspired by Zhang, Zohren, Roberts (2019),
    IEEE Transactions on Signal Processing, arXiv:1808.03668.

    NOTE: this is an illustrative reimplementation, NOT the official model.
    Differences from the paper:
      - inception has 3 paths here vs 4 in the paper (max-pool path omitted);
      - channel counts are scaled up (paper: 16 conv / 32 inception, input 96).

    Input shape: (batch_size, 1, T, 40)
        T = lookback window (e.g. 100)
        40 = 10 levels x 4 features (ask_price, ask_vol, bid_price, bid_vol)
    """

    def __init__(self, num_classes: int = 3, T: int = 100):
        super().__init__()
        self.num_classes = num_classes

        self.conv1 = nn.Sequential(
            nn.Conv2d(1, 32, kernel_size=(1, 2), stride=(1, 2)),
            nn.LeakyReLU(negative_slope=0.01),
            nn.BatchNorm2d(32),
            nn.Conv2d(32, 32, kernel_size=(4, 1), padding=(1, 0)),  # time -1
            nn.LeakyReLU(negative_slope=0.01),
            nn.BatchNorm2d(32),
            nn.Conv2d(32, 32, kernel_size=(4, 1), padding=(1, 0)),  # time -1
            nn.LeakyReLU(negative_slope=0.01),
            nn.BatchNorm2d(32),
        )

        self.conv2 = nn.Sequential(
            nn.Conv2d(32, 32, kernel_size=(1, 2), stride=(1, 2)),
            nn.LeakyReLU(negative_slope=0.01),
            nn.BatchNorm2d(32),
            nn.Conv2d(32, 32, kernel_size=(4, 1), padding=(1, 0)),  # time -1
            nn.LeakyReLU(negative_slope=0.01),
            nn.BatchNorm2d(32),
            nn.Conv2d(32, 32, kernel_size=(4, 1), padding=(1, 0)),  # time -1
            nn.LeakyReLU(negative_slope=0.01),
            nn.BatchNorm2d(32),
        )

        self.conv3 = nn.Sequential(
            nn.Conv2d(32, 32, kernel_size=(1, 10)),
            nn.LeakyReLU(negative_slope=0.01),
            nn.BatchNorm2d(32),
            nn.Conv2d(32, 32, kernel_size=(4, 1), padding=(1, 0)),  # time -1
            nn.LeakyReLU(negative_slope=0.01),
            nn.BatchNorm2d(32),
            nn.Conv2d(32, 32, kernel_size=(4, 1), padding=(1, 0)),  # time -1
            nn.LeakyReLU(negative_slope=0.01),
            nn.BatchNorm2d(32),
        )

        self.inp1 = nn.Sequential(
            nn.Conv2d(32, 64, kernel_size=(1, 1), padding=(0, 0)),
            nn.LeakyReLU(negative_slope=0.01),
            nn.BatchNorm2d(64),
        )
        self.inp2 = nn.Sequential(
            nn.Conv2d(32, 64, kernel_size=(1, 1), padding=(0, 0)),
            nn.LeakyReLU(negative_slope=0.01),
            nn.BatchNorm2d(64),
            nn.Conv2d(64, 64, kernel_size=(3, 1), padding=(1, 0)),
            nn.LeakyReLU(negative_slope=0.01),
            nn.BatchNorm2d(64),
        )
        self.inp3 = nn.Sequential(
            nn.Conv2d(32, 64, kernel_size=(1, 1), padding=(0, 0)),
            nn.LeakyReLU(negative_slope=0.01),
            nn.BatchNorm2d(64),
            nn.Conv2d(64, 64, kernel_size=(5, 1), padding=(2, 0)),
            nn.LeakyReLU(negative_slope=0.01),
            nn.BatchNorm2d(64),
        )

        self.lstm = nn.LSTM(
            input_size=192,  # 64 * 3 paths from the simplified inception
            hidden_size=64,
            num_layers=1,
            batch_first=True,
        )

        self.fc = nn.Linear(64, num_classes)

    def forward(self, x: torch.Tensor) -> torch.Tensor:
        """
        Args:
            x: Tensor of shape (batch, 1, T, 40)
        Returns:
            Tensor of shape (batch, num_classes)
        """
        h = self.conv1(x)   # (batch, 32, T-2, 20)
        h = self.conv2(h)   # (batch, 32, T-4, 10)
        h = self.conv3(h)   # (batch, 32, T-6, 1)   e.g. T=100 -> 94

        h_inp1 = self.inp1(h)  # (batch, 64, T-6, 1)
        h_inp2 = self.inp2(h)  # (batch, 64, T-6, 1)
        h_inp3 = self.inp3(h)  # (batch, 64, T-6, 1)
        h = torch.cat([h_inp1, h_inp2, h_inp3], dim=1)  # (batch, 192, T-6, 1)

        h = h.squeeze(-1)          # (batch, 192, T-6)
        h = h.permute(0, 2, 1)     # (batch, T-6, 192)

        h, _ = self.lstm(h)
        h = h[:, -1, :]  # take last hidden state

        out = self.fc(h)
        return out

Pra-pemrosesan Data

Dataset FI-2010 dikirimkan dalam keadaan ternormalisasi z-score. Untuk data order book langsung, Anda perlu melakukan normalisasi serupa:

import numpy as np
from torch.utils.data import Dataset


class LOBDataset(Dataset):
    """Dataset for limit order book snapshots."""

    def __init__(
        self,
        data: np.ndarray,
        labels: np.ndarray,
        T: int = 100,
    ):
        """
        Args:
            data: shape (num_snapshots, 40), raw LOB features
            labels: shape (num_snapshots,), class labels {0, 1, 2}
            T: lookback window length
        """
        self.data = data
        self.labels = labels
        self.T = T

        self.mean = data[:len(data) // 2].mean(axis=0)
        self.std = data[:len(data) // 2].std(axis=0)
        self.std[self.std == 0] = 1.0
        self.data = (self.data - self.mean) / self.std

    def __len__(self) -> int:
        return len(self.data) - self.T

    def __getitem__(self, idx: int):
        x = self.data[idx : idx + self.T].reshape(1, self.T, 40)
        y = self.labels[idx + self.T - 1]
        return torch.tensor(x, dtype=torch.float32), torch.tensor(
            y, dtype=torch.long
        )

Training Loop

def train_deeplob(
    model: DeepLOB,
    train_loader,
    val_loader,
    epochs: int = 50,
    lr: float = 0.01,
    device: str = "cuda",
):
    model = model.to(device)
    criterion = nn.CrossEntropyLoss()
    optimizer = torch.optim.Adam(model.parameters(), lr=lr, eps=1)

    best_val_f1 = 0.0
    for epoch in range(epochs):
        model.train()
        train_loss = 0.0
        for x_batch, y_batch in train_loader:
            x_batch = x_batch.to(device)
            y_batch = y_batch.to(device)

            optimizer.zero_grad()
            logits = model(x_batch)
            loss = criterion(logits, y_batch)
            loss.backward()
            optimizer.step()
            train_loss += loss.item()

        model.eval()
        all_preds, all_labels = [], []
        with torch.no_grad():
            for x_val, y_val in val_loader:
                x_val = x_val.to(device)
                preds = model(x_val).argmax(dim=1).cpu()
                all_preds.extend(preds.numpy())
                all_labels.extend(y_val.numpy())

        from sklearn.metrics import f1_score
        val_f1 = f1_score(all_labels, all_preds, average="weighted")

        print(
            f"Epoch {epoch+1}/{epochs} | "
            f"Train Loss: {train_loss/len(train_loader):.4f} | "
            f"Val F1: {val_f1:.4f}"
        )

        if val_f1 > best_val_f1:
            best_val_f1 = val_f1
            torch.save(model.state_dict(), "deeplob_best.pt")

Hiperparameter pelatihan utama dari paper asli:

  • Optimizer: Adam dengan ϵ=1\epsilon = 1 (luar biasa besar — membantu menstabilkan pembaruan pada data finansial yang penuh noise)
  • Learning rate: 0.01
  • Batch size: 32
  • Jendela lookback: T=100T = 100 timestep

Kami melacak weighted F1 alih-alih akurasi pada validasi, karena ketiga kelas tidak seimbang — dan, seperti yang ditunjukkan bagian berikutnya, F1 adalah metrik yang ditekankan oleh paper asli justru karena alasan itu.

Apa yang Dirancang untuk Ditangkap oleh DeepLOB

Sinyal mikrostruktur yang dipelajari DeepLOB: order-flow imbalance, dinamika antrean, dan tekanan volume-weighted mid-price

Salah satu aspek menarik dari DeepLOB adalah betapa eratnya blok-bloknya dimotivasi oleh fitur-fitur yang dirancang manual di atas. Kita perlu berhati-hati di sini: paper menyajikan ini sebagai intuisi desain, bukan sebagai properti yang terbukti dari jaringan yang telah dilatih. Ia tidak menerbitkan visualisasi filter, korelasi activation-imbalance, atau analisis tentang apa yang diperhatikan LSTM. Jadi bacalah hal berikut sebagai niat arsitektural, bukan temuan terukur.

Blok konvolusional pertama. Filter 1×21 \times 2 memasangkan harga dengan volume pada setiap level. Secara struktural, ini adalah operasi yang sama yang membentuk volume-weighted price — paper memotivasi lapisan pertama dengan mencatat bahwa feature map-nya membentuk sebuah kuantitas serupa micro-price. Jaringan dirancang untuk memulihkan sesuatu dalam keluarga itu; kami tidak mengklaim bahwa ia secara terbukti menemukan kembali estimator spesifik apa pun.

Blok konvolusional kedua. Dengan beroperasi lintas pasangan bid-ask, filter-filter ini diposisikan untuk mempelajari fitur serupa imbalance pada berbagai level — sekali lagi, secara konstruksi alih-alih melalui korelasi yang ditunjukkan.

Modul inception. Konvolusi temporal multi-skala dimaksudkan untuk menangkap momentum pada frekuensi yang berbeda: jalur 1×11\times1 merespons struktur point-in-time, jalur 3×13\times1 tren jangka pendek, jalur 5×15\times1 tren yang sedikit lebih panjang, dan (dalam modul penuh) jalur max-pool sebuah tampilan yang dihaluskan.

Lapisan LSTM. Komponen rekuren menambahkan memori atas dependensi jangka panjang yang tidak dapat direpresentasikan oleh konvolusi — pergeseran rezim dan efek waktu-hari. Kami menghindari klaim yang lebih kuat (seperti bahwa LSTM mengimplementasikan sebuah "adaptive attention" yang membobot ulang data terbaru pada rezim yang volatil); paper tidak menunjukkan hal ini.

Kinerja pada FI-2010

Paper asli mengevaluasi dua protokol. Setup 1 menggunakan pembagian normalisasi dataset yang lebih awal; Setup 2 adalah setup deep-learning yang paling sering dibandingkan oleh karya-karya selanjutnya. Karena FI-2010 tidak seimbang antar kelas, paper menekankan F1, bukan akurasi, dan melaporkan angka berbasis precision/recall untuk baseline non-neural (SVM, MLP). Berikut adalah angka Setup 2 yang sebenarnya (F1, %):

Horizon (k) SVM MLP CNN-I LSTM DeepLOB
10 35.88 48.27 55.21 66.33 83.40
20 72.82
50 80.35

Pada k=10k = 10, DeepLOB juga melaporkan akurasi 84.47% di samping F1-nya yang sebesar 83.40. Setup 2 hanya melaporkan k{10,20,50}k \in \{10, 20, 50\} — tidak ada baris k=100k = 100 di sini. (Setup 1 memang melaporkan k{10,50,100}k \in \{10, 50, 100\}, dengan F1 DeepLOB masing-masing sebesar 77.66 / 74.96 / 76.58.) Tanda hubung di atas menandai sel baseline yang tidak ditabulasikan paper pada horizon tersebut dalam protokol ini.

Beberapa pengamatan menonjol:

  1. DeepLOB mengungguli baseline dengan margin yang lebar pada horizon pendek. Pada k=10k = 10 F1-nya (83.40) jauh di atas LSTM (66.33), CNN-I (55.21), MLP (48.27), dan SVM (35.88). Pengurutan kualitatif — model rekuren-konvolusional deep di atas CNN biasa, MLP, dan SVM — adalah kesimpulan yang kokoh.
  2. Tren horizon bersifat non-monoton, bukan "lebih panjang lebih mudah." Lintas Setup 2, F1 DeepLOB bergerak 83.4072.8280.3583.40 \to 72.82 \to 80.35 saat kk bergerak 10205010 \to 20 \to 50 — sebuah pola berbentuk U, dengan k=20k=20 yang paling sulit, bukan kenaikan yang rapi. Apakah sebuah horizon "lebih mudah" sangat bergantung pada setup, ambang batas α\alpha, dan skema label-smoothing; kita tidak boleh membaca hukum universal ke dalam angka-angka ini.
  3. DeepLOB tidak mendominasi setiap metode klasik pada setiap sel. Terhadap baseline kuat seperti C(TABL), marginnya menyempit pada beberapa horizon, sehingga "mengungguli semua pendekatan klasik di mana saja" terlalu melebih-lebihkan keadaan. Klaim yang dapat dipertahankan adalah bahwa ia kompetitif-hingga-terbaik, dan jelas terbaik pada horizon pendek.

Dan sekali lagi: pandangan paper itu sendiri adalah bahwa FI-2010 terlalu kecil dan terlalu di-downsample untuk menyelesaikan persoalan ini. Bukti yang lebih kuatnya adalah studi LSE, di mana DeepLOB dilatih pada satu set saham dan tetap dapat memprediksi pada saham yang ditahan (held-out) — sebuah hasil transfer-learning yang tidak dapat ditunjukkan oleh FI-2010.

LOBFrame dan Krisis Replikasi

Kurva in-sample dan out-of-sample yang menyimpang menggambarkan krisis replikasi deep-learning order-book

Kerangka kerja benchmark LOBFrame (Briola, Bartolucci, Aste, 2024) memberikan pelengkap yang menyadarkan terhadap hasil-hasil ini. Meskipun arsitektur DeepLOB solid, kerangka kerja ini menyoroti beberapa peringatan penting:

Ketergantungan pada mikrostruktur. Kinerja model bervariasi secara signifikan lintas saham dengan karakteristik mikrostruktural yang berbeda. Saham yang likuid dan ber-tick besar lebih mudah diprediksi daripada instrumen yang tidak likuid dan ber-tick kecil. Sebuah model yang tampak kuat pada satu saham dapat menurun secara substansial pada saham lain.

Prediksi vs. profit. Akurasi klasifikasi yang tinggi tidak otomatis berubah menjadi profit perdagangan. LOBFrame menekankan metrik yang terkait dengan apakah pergerakan yang diprediksi cukup besar untuk menutup bid-ask spread. Sebuah model perlu benar cukup sering, dan pada pergerakan yang cukup besar, untuk mengatasi spread — dan untuk saham ber-spread ketat, batas itu tinggi.

Sensitivitas label. Pilihan ambang batas α\alpha dan horizon kk secara dramatis memengaruhi baik akurasi yang dilaporkan maupun nilai praktis dari prediksi. Label yang terlalu ketat menghasilkan target yang penuh noise; label yang terlalu lebar menghasilkan prediksi yang secara trivial "akurat" tetapi tidak berguna.

Melampaui DeepLOB: Lanskap Saat Ini

Konstelasi pendekatan peramalan order-book modern yang mengorbit model DeepLOB asli

Sejak publikasi DeepLOB, beberapa ekstensi telah bermunculan:

Transformer untuk limit order book (Wallbridge, 2020). Sering disebut secara longgar sebagai "TransLOB" dalam literatur selanjutnya, model itu sendiri adalah sebuah ekstraktor fitur konvolusional kausal/dilated yang diikuti oleh masked multi-head self-attention — bukan sekadar DeepLOB dengan LSTM yang ditukar menjadi Transformer; ia tidak menggunakan kembali tumpukan inception+konvolusi. Ia melaporkan state of the art FI-2010 yang baru untuk masanya.

Varian domain kripto. Beberapa kelompok menerapkan arsitektur bergaya DeepLOB pada pasar mata uang kripto, di mana dinamika order book berbeda secara substansial dari ekuitas — spread yang lebih lebar, perdagangan 24/7, dan campuran partisipan yang berbeda yang semuanya menuntut pelatihan ulang.

Varian yang diperkuat attention. Sebuah lini karya menyisipkan multi-head attention di antara blok inception dan LSTM, membiarkan jaringan berfokus pada level atau langkah waktu yang paling informatif untuk prediksi saat ini.

LOB-Bench (Nagy, Frey, Li, Sarkar, Vyetrenko, Zohren, Calinescu, Foerster, 2025). Benchmark ini mengalihkan perhatian dari prediksi ke generasi, menilai seberapa realistis model generatif dari data order book — relevan untuk backtesting dan pelatihan agen alih-alih peramalan arah.

Pertimbangan Praktis untuk Produksi

Jika Anda mempertimbangkan untuk men-deploy model bergaya DeepLOB dalam sistem perdagangan langsung, beberapa persoalan rekayasa muncul:

Latensi

Model harus menghasilkan prediksi dalam anggaran latensi sistem perdagangan Anda. Untuk sistem HFT yang beroperasi pada latensi sub-milidetik, bahkan inferensi PyTorch yang teroptimasi pun bisa terlalu lambat. Opsinya meliputi:

  • Ekspor ONNX dengan optimasi TensorRT
  • Kuantisasi ke INT8
  • Deployment FPGA untuk aplikasi yang paling sensitif terhadap latensi

Pipeline Data

Model mengharapkan snapshot order book yang ternormalisasi dan tersejajarkan pada frekuensi tetap. Dalam praktiknya, pembaruan LOB tiba secara asinkron. Anda membutuhkan:

  • Sebuah mesin rekonstruksi snapshot yang mempertahankan state book saat ini
  • Sebuah sampler frekuensi-tetap yang menghasilkan tensor input (T,40)(T, 40)
  • Normalisasi online menggunakan statistik bergulir (rolling)

Stabilitas Fitur

Parameter normalisasi z-score yang dihitung pada data pelatihan menyimpang seiring waktu. Harga berubah, rezim volatilitas bergeser, struktur pasar berevolusi. Sebuah sistem produksi membutuhkan:

  • Jendela normalisasi bergulir (mis., menghitung ulang statistik setiap hari)
  • Deteksi rezim untuk memicu pelatihan ulang model
  • Pemantauan terhadap pergeseran distribusi input

Overfitting terhadap Mikrostruktur

Pola LOB bersifat spesifik-venue dan spesifik-instrumen. Sebuah model yang dilatih pada ekuitas NASDAQ tidak akan berfungsi pada Binance BTC/USDT tanpa pelatihan ulang. Bahkan dalam venue yang sama, model dapat overfit terhadap:

  • Rezim ukuran tick (saham ber-tick besar vs. ber-tick kecil)
  • Pola waktu-hari (lelang pembukaan, jeda makan siang, closing cross)
  • Perilaku market maker yang berubah seiring waktu

Kesimpulan

DeepLOB merepresentasikan penerapan deep learning yang rapi dan dimotivasi dengan baik pada mikrostruktur pasar. Arsitektur tiga-bloknya — CNN untuk fitur spasial, inception untuk pola temporal multi-skala, LSTM untuk dependensi sekuensial — memetakan secara alami pada struktur data limit order book.

Wawasan kuncinya bukan hanya bahwa sebuah model deep dapat menyamai atau mengungguli fitur yang dirancang manual, melainkan bahwa bias induktif dari arsitekturnya — filter 1×21 \times 2, paralelisme inception, memori rekuren — mengenkode pengetahuan domain yang sesungguhnya tentang bagaimana order book bekerja. Ini bukan jaringan deep generik yang dilemparkan begitu saja ke data finansial; ini adalah arsitektur yang dirancang di sekitar geometri spesifik dari limit order book. Dan bukti yang paling meyakinkan darinya bukanlah papan peringkat FI-2010 yang bahkan tidak dipercaya para penulisnya sendiri, melainkan hasil transfer-learning pada data LSE selama satu tahun.

Bagi praktisi, DeepLOB adalah baseline yang kuat dan sebuah blok bangunan yang berguna. Bagi peneliti, ia menunjukkan bahwa desain arsitektur yang cermat — bukan sekadar skala model — yang mendorong kinerja pada data finansial terstruktur. Cukup ingat untuk mengutip angka yang sebenarnya, perhatikan skema label, dan perlakukan akurasi klasifikasi sebagai sesuatu yang masih jauh dari profit perdagangan.


Referensi

  1. Zhang, Z., Zohren, S., & Roberts, S. (2019). DeepLOB: Deep Convolutional Neural Networks for Limit Order Books. IEEE Transactions on Signal Processing, 67(11), 3001-3012. arXiv:1808.03668

  2. Ntakaris, A., Magris, M., Kanniainen, J., Gabbouj, M., & Iosifidis, A. (2018). Benchmark Dataset for Mid-Price Forecasting of Limit Order Book Data with Machine Learning Methods. Journal of Forecasting, 37(8), 852-866. arXiv:1705.03233

  3. Briola, A., Bartolucci, S., & Aste, T. (2024). Deep Limit Order Book Forecasting (LOBFrame). arXiv:2403.09267

  4. Wallbridge, J. (2020). Transformers for Limit Order Books. arXiv:2003.00130

  5. Cont, R., Kukanov, A., & Stoikov, S. (2014). The Price Impact of Order Book Events. Journal of Financial Econometrics, 12(1), 47-88.

  6. Stoikov, S. (2018). The Micro-Price: A High-Frequency Estimator of Future Prices. Quantitative Finance, 18(12), 1959-1966.

  7. Nagy, P., Frey, S., Li, K., Sarkar, B., Vyetrenko, S., Zohren, S., Calinescu, A., & Foerster, J. (2025). LOB-Bench: Benchmarking Generative AI for Finance — an Application to Limit Order Book Data. ICML 2025. arXiv:2502.09172

  8. Kode DeepLOB (asli dalam Keras/TensorFlow; repositori juga menyediakan port PyTorch): github.com/zcakhaa/DeepLOB-Deep-Convolutional-Neural-Networks-for-Limit-Order-Books

Penafian: Informasi yang disediakan dalam artikel ini hanya untuk tujuan edukasi dan informasi serta tidak merupakan nasihat keuangan, investasi, atau trading. Trading mata uang kripto mengandung risiko kerugian yang signifikan.

Penulis

Eugen Soloviov
Eugen Soloviov

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.

Newsletter

Selangkah Lebih Maju dari Pasar

Berlangganan newsletter kami untuk wawasan AI trading eksklusif, analisis pasar, dan pembaruan platform.

Kami menghormati privasi Anda. Berhenti berlangganan kapan saja.