Перейти к содержимому

Глава 275: Прогнозирование LOB с помощью LSTM

1. Введение

Данные книги лимитных заявок (Limit Order Book, LOB) предоставляют детальное представление микроструктуры рынка в реальном времени: очереди заявок на покупку и продажу на различных ценовых уровнях, которые в совокупности определяют мгновенный ландшафт спроса и предложения. Прогнозирование эволюции характеристик LOB — направления средней цены, динамики спреда или дисбаланса потока заявок — является одной из наиболее сложных задач в количественных финансах, поскольку данные высокоразмерны, зашумлены и демонстрируют сложные временные зависимости на множестве временных масштабов.

Сети долгой краткосрочной памяти (Long Short-Term Memory, LSTM) — это класс рекуррентных нейронных сетей (RNN), специально разработанных для захвата дальних зависимостей в последовательных данных. В отличие от обычных RNN, которые страдают от затухания и взрыва градиентов при обратном распространении во времени, LSTM используют механизм вентилей (gates), который избирательно сохраняет, обновляет или отбрасывает информацию по выделенной магистрали состояния ячейки. Эта архитектурная инновация делает LSTM особенно подходящими для прогнозирования LOB, где модель должна одновременно отслеживать:

  • Быструю динамику: субсекундные изменения спреда на вершине книги и поступления заявок.
  • Медленную динамику: многоминутные тренды взвешенного по объёму дисбаланса и дрейфа средней цены.
  • Память о событиях: длительное влияние крупных рыночных заявок или вывода ликвидности, произошедших много шагов назад.

В этой главе мы разработаем полный конвейер прогнозирования LOB на основе LSTM на языке Rust — от сырых данных книги заявок и свечных данных с биржи Bybit через инженерию признаков, обучение модели и многошаговое прогнозирование направления средней цены.


2. Математические основы

2.1 Проблема обычных RNN

Обычная RNN вычисляет скрытое состояние на шаге $t$ как:

$$h_t = \tanh(W_{hh} h_{t-1} + W_{xh} x_t + b_h)$$

При обратном распространении во времени (BPTT) градиент функции потерь по $h_t$ включает произведения якобиана $\frac{\partial h_t}{\partial h_{t-1}}$ на протяжении многих шагов. Когда спектральный радиус этого якобиана меньше единицы, градиенты экспоненциально затухают; когда больше единицы — взрываются. Это ограничивает обычные RNN обучением зависимостей на протяжении примерно 10-20 шагов.

2.2 Архитектура ячейки LSTM

Ячейка LSTM заменяет единственное нелинейное преобразование четырьмя взаимодействующими вентилями. Для входного вектора $x_t \in \mathbb{R}^d$ и предыдущего скрытого состояния $h_{t-1} \in \mathbb{R}^h$ LSTM вычисляет:

Вентиль забывания — решает, какую долю старого состояния ячейки сохранить:

$$f_t = \sigma(W_f [h_{t-1}, x_t] + b_f)$$

Входной вентиль — решает, какую новую информацию сохранить:

$$i_t = \sigma(W_i [h_{t-1}, x_t] + b_i)$$

Кандидат состояния ячейки — предлагает новые значения для добавления:

$$\tilde{C}t = \tanh(W_C [h{t-1}, x_t] + b_C)$$

Обновление состояния ячейки — ядро LSTM, объединяющее старую и новую информацию:

$$C_t = f_t \odot C_{t-1} + i_t \odot \tilde{C}_t$$

Выходной вентиль — определяет открытое скрытое состояние:

$$o_t = \sigma(W_o [h_{t-1}, x_t] + b_o)$$

Скрытое состояние:

$$h_t = o_t \odot \tanh(C_t)$$

где $\sigma$ — сигмоидная функция, $\odot$ обозначает поэлементное (адамарово) произведение, а $[\cdot, \cdot]$ обозначает конкатенацию.

Состояние ячейки $C_t$ действует как информационная магистраль: поскольку вентиль забывания может научиться поддерживать $f_t \approx 1$ для релевантной информации, градиенты могут течь назад через состояние ячейки с минимальным затуханием, решая проблему затухающих градиентов.

2.3 Многослойный (стековый) LSTM

Один слой LSTM может не захватить иерархические временные абстракции, присутствующие в данных LOB. Мы укладываем $L$ слоёв LSTM так, что выход скрытого состояния $h_t^{(l)}$ слоя $l$ служит входом для слоя $l+1$:

$$h_t^{(l)} = \text{LSTM}^{(l)}(h_t^{(l-1)}, h_{t-1}^{(l)}, C_{t-1}^{(l)})$$

где $h_t^{(0)} = x_t$. Нижние слои обычно обучаются коротким паттернам (уровень тиков), а верхние захватывают более долгосрочную структуру (тренд, режим).

2.4 Прогнозирование «последовательность-в-одно»

Для классификации направления средней цены мы используем финальное скрытое состояние $h_T^{(L)}$ верхнего слоя LSTM, пропущенное через плотный выходной слой:

$$\hat{y} = \text{softmax}(W_y h_T^{(L)} + b_y)$$

с классами: Рост, Падение, Стабильность. Обучение минимизирует кросс-энтропийную функцию потерь.


3. Инженерия признаков LOB

Сырые данные LOB представляют собой матрицу пар (цена, объём) на каждом уровне. Мы конструируем следующие признаки на каждом шаге $t$:

3.1 Средняя цена (Mid-Price)

$$p_{\text{mid},t} = \frac{p_{\text{ask},t}^{(1)} + p_{\text{bid},t}^{(1)}}{2}$$

3.2 Спред

$$s_t = p_{\text{ask},t}^{(1)} - p_{\text{bid},t}^{(1)}$$

Расширяющийся спред сигнализирует о снижении ликвидности и потенциальной волатильности.

3.3 Коэффициент дисбаланса

$$\text{IR}t = \frac{V{\text{bid},t} - V_{\text{ask},t}}{V_{\text{bid},t} + V_{\text{ask},t}}$$

где $V_{\text{bid},t} = \sum_{k=1}^{K} q_{\text{bid},t}^{(k)}$ — общий объём заявок на покупку по $K$ уровням. Коэффициент дисбаланса, близкий к +1, указывает на сильное давление покупателей; близкий к -1 — на давление продавцов. Это один из сильнейших краткосрочных предикторов направления средней цены.

3.4 Профиль объёма / Глубина

Мы отслеживаем кумулятивный объём на нескольких уровнях глубины:

$$D_t^{(k)} = \sum_{j=1}^{k} \left( q_{\text{bid},t}^{(j)} + q_{\text{ask},t}^{(j)} \right)$$

Это фиксирует «толщину» книги на различных расстояниях от средней цены.

3.5 Доходность средней цены

$$r_t = \frac{p_{\text{mid},t} - p_{\text{mid},t-1}}{p_{\text{mid},t-1}}$$

Доходности стационарны (в отличие от сырых цен), что делает их более подходящими в качестве входов нейронной сети.

3.6 Микроцена

Микроцена взвешивает лучшие цены покупки и продажи объёмом противоположной стороны:

$$p_{\text{micro},t} = \frac{q_{\text{ask},t}^{(1)} \cdot p_{\text{bid},t}^{(1)} + q_{\text{bid},t}^{(1)} \cdot p_{\text{ask},t}^{(1)}}{q_{\text{bid},t}^{(1)} + q_{\text{ask},t}^{(1)}}$$

Это даёт лучшую оценку «справедливой цены», чем простая средняя цена.

3.7 Нормализация признаков

Все признаки нормализуются по z-score на скользящем окне из $W$ шагов:

$$\hat{x}{t,j} = \frac{x{t,j} - \mu_j^{(W)}}{\sigma_j^{(W)} + \epsilon}$$

Это критически важно для сходимости LSTM, поскольку вентили чувствительны к масштабу входных данных.


4. Многошаговое прогнозирование

4.1 Прямое многошаговое

Обучаем $H$ отдельных моделей, каждая предсказывает $\hat{y}_{t+h}$ для горизонта $h = 1, \ldots, H$. Избегает накопления ошибок, но требует больше параметров.

4.2 Рекурсивное (авторегрессионное) многошаговое

Обучаем одну одношаговую модель и подаём предсказания обратно как входы. Ошибка накапливается на горизонтах, но подход экономичен по параметрам.

4.3 Последовательность-в-последовательность (Seq2Seq)

Используем кодирующий LSTM для сжатия входной последовательности в вектор контекста, затем декодирующий LSTM для генерации полной последовательности прогнозов $(\hat{y}{t+1}, \ldots, \hat{y}{t+H})$ за один проход. Это наиболее выразительный подход, но требует больше данных.

4.4 Выбор горизонта для LOB

Для высокочастотного прогнозирования LOB типичные горизонты:

ГоризонтШагиПрименение
Ультракороткий1-5 тиковМаркет-мейкинг
Короткий10-50 тиковАгрессивный HFT
Средний100-500 тиковСтатистический арбитраж

Наша реализация использует настраиваемый горизонт со значением по умолчанию 10 шагов вперёд.


5. Реализация на Rust

5.1 Обзор архитектуры

Наша реализация на Rust организована в следующие модули в lib.rs:

  • LstmCell — одна ячейка LSTM с полным вычислением вентилей.
  • StackedLstm — несколько слоёв LSTM, уложенных вертикально.
  • LobFeatureExtractor — вычисляет инженерные признаки из сырых снимков книги заявок.
  • LstmForecaster — сквозная модель, объединяющая извлечение признаков, буферизацию последовательностей и предсказание.
  • Функции API Bybit — получение данных книги заявок и свечей в реальном времени.

5.2 Ключевые детали реализации

Инициализация весов: Мы используем равномерную инициализацию Ксавье/Глоро, масштабируя веса на $\sqrt{6 / (n_{\text{in}} + n_{\text{out}})}$. Это поддерживает стабильную дисперсию активаций между слоями и критически важно для обучения LSTM.

Функции активации: Сигмоида и tanh реализованы поэлементно над массивами ndarray. Сигмоида вычисляется как $\sigma(x) = 1 / (1 + e^{-x})$ с обрезкой для предотвращения числового переполнения.

Прямой проход: Каждая ячейка LSTM конкатенирует $[h_{t-1}, x_t]$, умножает на весовые матрицы для всех четырёх вентилей одновременно, затем разделяет и применяет соответствующие активации.

Обучение: Мы реализуем обратное распространение во времени (BPTT) с простым оптимизатором SGD. В продакшене следует использовать Adam или AdamW, но SGD наглядно демонстрирует основное вычисление градиентов.

5.3 Интеграция с Bybit

Мы получаем два типа данных из API Bybit v5:

  1. Снимки книги заявок (/v5/market/orderbook): предоставляют цены и объёмы покупки/продажи на до 200 уровнях.
  2. Свечные данные (/v5/market/kline): предоставляют бары OHLCV для контекста тренда.

Оба конечных точки публичны и не требуют аутентификации.


6. Интеграция данных Bybit

6.1 Данные книги заявок

Конечная точка REST API Bybit GET /v5/market/orderbook?category=linear&symbol=BTCUSDT&limit=50 возвращает JSON-ответ, содержащий массивы пар [цена, объём] для заявок на покупку и продажу.

Мы разбираем это в нашу структуру OrderbookSnapshot, которая хранит векторы кортежей (f64, f64), представляющих (цена, объём) на каждом уровне.

6.2 Свечные данные (Kline)

Конечная точка GET /v5/market/kline?category=linear&symbol=BTCUSDT&interval=1&limit=200 возвращает свечные данные. Мы извлекаем цены закрытия для вычисления серии доходностей средней цены как дополнительных признаков.

6.3 Конвейер данных

Bybit API --> OrderbookSnapshot --> LobFeatureExtractor --> Вектор признаков
|
v
Буфер последовательности (T шагов)
|
v
StackedLstm --> Предсказание

Конвейер работает следующим образом:

  1. Получаем пакет снимков книги заявок и свечных данных.
  2. Для каждого снимка вычисляем вектор признаков LOB (дисбаланс, спред, глубина, доходность средней цены, микроцена).
  3. Накапливаем признаки в скользящем окне длины $T$ (длина последовательности).
  4. Подаём последовательность через многослойный LSTM.
  5. Финальное скрытое состояние проецируется на 3-классовый выход (Рост / Падение / Стабильность).

6.4 Формирование меток

Для обучения с учителем мы размечаем каждый шаг на основе будущего изменения средней цены:

$$y_t = \begin{cases} \text{Рост} & \text{если } p_{\text{mid}, t+H} - p_{\text{mid}, t} > \theta \ \text{Падение} & \text{если } p_{\text{mid}, t} - p_{\text{mid}, t+H} > \theta \ \text{Стабильность} & \text{иначе} \end{cases}$$

где $\theta$ — порог (например, 0.5 * средний спред), который предотвращает разметку шума как направленного движения.


7. Ключевые выводы

  1. Вентили LSTM решают проблему затухающих градиентов: Способность вентиля забывания поддерживать $f_t \approx 1$ позволяет градиентам течь через состояние ячейки на протяжении сотен шагов, давая сети возможность обучаться как быстрым (тик-уровень), так и медленным (тренд-уровень) зависимостям в данных LOB.

  2. Инженерия признаков LOB критически важна: Сырые уровни книги заявок высокоразмерны и зашумлены. Инженерные признаки — коэффициент дисбаланса, спред, микроцена, профили глубины — сжимают релевантную информацию о микроструктуре в управляемое, информативное представление.

  3. Многослойность захватывает иерархические паттерны: Нижние слои LSTM обучаются локальным паттернам (отдельные поступления заявок, колебания спреда), а верхние — агрегированным (тренды, режимы ликвидности). Обычно достаточно двух-трёх слоёв.

  4. Нормализация и инициализация важны: Z-score нормализация признаков и инициализация весов по Ксавье не опциональны — без них вентили LSTM насыщаются и обучение не сходится.

  5. Многошаговое прогнозирование требует тщательного проектирования: Прямое многошаговое избегает накопления ошибок, но требует отдельных моделей на горизонт. Рекурсивные подходы экономичны по параметрам, но накапливают ошибки.

  6. Rust обеспечивает низкую задержку вывода: Для HFT-приложений, где предсказания должны генерироваться за микросекунды, абстракции нулевой стоимости и отсутствие сборщика мусора в Rust делают его идеальным выбором.

  7. Bybit предоставляет доступные данные LOB: Публичный API v5 предлагает снимки книги заявок на до 200 уровнях без аутентификации, что упрощает построение и тестирование моделей прогнозирования LOB на живых данных криптовалют.

  8. Пороговая разметка снижает шум: Использование порога $\theta$, относительного к спреду, при формировании обучающих меток предотвращает попытки модели предсказывать случайные колебания средней цены внутри спреда.

  9. Длина последовательности — ключевой гиперпараметр: Слишком короткая (< 20 шагов) — модель не сможет захватить многомасштабные зависимости; слишком длинная (> 200 шагов) — обучение замедляется и модель может переобучиться. Длина 50-100 шагов — хорошая отправная точка для данных LOB с разрешением 100мс.

  10. Оценка должна учитывать дисбаланс классов: В прогнозировании LOB класс «Стабильность» часто доминирует. Используйте сбалансированную точность, макро-F1 или взвешивание классов в функции потерь.