Глава 267: Предсказание обновлений котировок
Введение
В современных электронных рынках цены не изменяются плавно — они двигаются дискретными скачками, называемыми обновлениями котировок (quote updates). Каждый раз, когда участник рынка выставляет, отменяет или изменяет лимитный ордер на лучшем бид или аск, котировка верхнего уровня стакана меняется, и новое сообщение распространяется через матчинг-движок биржи. Предсказание направления и величины следующего обновления котировки — даже на несколько миллисекунд вперёд — является одной из самых ценных задач в количественных финансах.
В этой главе разрабатывается полная платформа для предсказания обновлений котировок (Quote Update Prediction, QUP). Мы начинаем с необработанных данных стакана Level-2, конструируем информативные признаки, строим быструю линейную модель оценки и разворачиваем её против API криптобиржи Bybit. Акцент сделан на проектирование с учётом задержки: каждый компонент реализован на Rust, чтобы инференс выполнялся за субмикросекундное время, укладываясь в бюджет системы высокочастотной торговли (HFT).
1. Что такое обновление котировки?
Котировка — это текущая лучшая цена и объём покупки (bid) и продажи (ask), публикуемые биржей. Обновление котировки происходит при следующих событиях:
| Событие | Эффект на котировку |
|---|---|
| Новый лимитный ордер на лучшем bid/ask | Объём увеличивается |
| Отмена на лучшем bid/ask | Объём уменьшается; цена может сдвинуться |
| Рыночный ордер исполняется по лучшей цене | Объём уменьшается; цена может сдвинуться |
| Новый ордер улучшает лучшую цену | Цена и объём меняются |
Формально, пусть $Q_t = (b_t, a_t, s_t^b, s_t^a)$ обозначает котировку в момент $t$, где $b_t$ — лучшая цена покупки, $a_t$ — лучшая цена продажи, $s_t^b$ — объём на бид, $s_t^a$ — объём на аск. Обновление котировки — это любой переход $Q_t \to Q_{t+1}$, при котором хотя бы один компонент изменяется.
1.1 Средняя цена и микро-цена
Средняя цена (mid-price) — это среднее арифметическое лучшего бида и аска:
$$m_t = \frac{b_t + a_t}{2}$$
Микро-цена (также называемая взвешенной по объёму средней ценой) корректируется с учётом дисбаланса стакана:
$$\tilde{m}_t = \frac{s_t^b \cdot a_t + s_t^a \cdot b_t}{s_t^b + s_t^a}$$
Когда $s_t^b \gg s_t^a$, микро-цена смещается к аску, отражая более высокую вероятность того, что следующая сделка поднимет аск. Разность $\tilde{m}_t - m_t$ является одним из наиболее предиктивных признаков для следующего движения средней цены.
1.2 Дисбаланс стакана
Дисбаланс уровня 1 определяется как:
$$I_t = \frac{s_t^b - s_t^a}{s_t^b + s_t^a} \in [-1, 1]$$
Положительный дисбаланс означает больший объём на стороне покупки, что эмпирически коррелирует с восходящим ценовым давлением. Мы обобщаем до взвешенного по глубине дисбаланса по $L$ уровням:
$$I_t^{(L)} = \frac{\sum_{l=1}^{L} w_l \cdot s_{t,l}^b - \sum_{l=1}^{L} w_l \cdot s_{t,l}^a}{\sum_{l=1}^{L} w_l \cdot (s_{t,l}^b + s_{t,l}^a)}$$
где $w_l = 1/l$ придаёт больший вес уровням, ближайшим к лучшей котировке.
2. Конструирование признаков для предсказания котировок
Хорошие признаки для QUP должны удовлетворять двум ограничениям:
- Предсказательная сила — признаки должны нести информацию о направлении следующей средней цены.
- Низкая задержка — они должны вычисляться за O(1) на обновление, без аллокаций памяти на горячем пути.
2.1 Набор признаков
Мы используем восемь признаков, извлечённых из пар последовательных снапшотов $(Q_{t-1}, Q_t)$:
| # | Признак | Формула | Интуиция |
|---|---|---|---|
| 1 | imbalance | $I_t$ | Давление покупки/продажи уровня 1 |
| 2 | depth_imbalance | $I_t^{(5)}$ | Многоуровневое давление |
| 3 | normalised_spread_bps | $\frac{a_t - b_t}{m_t} \times 10^4$ | Стоимость ликвидности |
| 4 | mid_return_bps | $\frac{m_t - m_{t-1}}{m_{t-1}} \times 10^4$ | Недавний импульс |
| 5 | micro_mid_diff_bps | $\frac{\tilde{m}_t - m_t}{m_t} \times 10^4$ | Справедливая стоимость на основе дисбаланса |
| 6 | bid_size_change_pct | $\frac{s_t^b - s_{t-1}^b}{s_{t-1}^b} \times 100$ | Пополнение бида |
| 7 | ask_size_change_pct | $\frac{s_t^a - s_{t-1}^a}{s_{t-1}^a} \times 100$ | Пополнение аска |
| 8 | dt_ms | $t - (t-1)$ в мс | Скорость прихода обновлений |
2.2 Z-нормализация
Перед подачей признаков в модель мы применяем z-нормализацию по столбцам:
$$\hat{x}_j = \frac{x_j - \mu_j}{\sigma_j}$$
где $\mu_j$ и $\sigma_j$ оцениваются по обучающей выборке. В продакшене эти статистики вычисляются по скользящему окну (например, последние 10 000 обновлений).
3. Линейная модель оценки
Для HFT-приложений сложность модели — враг задержки. Линейная функция оценки обеспечивает отличный компромисс:
$$f(\mathbf{x}) = \mathbf{w}^\top \mathbf{x} + b$$
Предсказанное направление: $\hat{y} = \text{sign}(f(\mathbf{x}))$:
- $\hat{y} = +1$: ожидается движение средней цены вверх
- $\hat{y} = -1$: ожидается движение средней цены вниз
- $\hat{y} = 0$: стабильно (оценка ровно ноль, на практике редко)
3.1 Шарнирная функция потерь и SGD
Мы обучаем с помощью онлайн шарнирной функции потерь (hinge loss — та же функция потерь, что лежит в основе линейных SVM):
$$\mathcal{L}(y, f(\mathbf{x})) = \max(0,; 1 - y \cdot f(\mathbf{x}))$$
Обновление субградиента для одного примера:
$$\mathbf{w} \leftarrow \mathbf{w} + \eta \cdot y \cdot \mathbf{x} \quad \text{если } y \cdot f(\mathbf{x}) < 1$$
$$b \leftarrow b + \eta \cdot y \quad \text{если } y \cdot f(\mathbf{x}) < 1$$
где $\eta$ — скорость обучения. Это однопроходный (online SGD) алгоритм, подходящий для потоковых данных, где модель обновляется тик за тиком.
3.2 Почему не глубокое обучение?
Глубокие модели (LSTM, Трансформеры) могут улавливать долгосрочные зависимости, но они влекут:
- Задержку: умножение матриц больших скрытых состояний занимает микросекунды, а не наносекунды.
- Риск переобучения: на зашумлённых тиковых данных более простые модели часто лучше обобщаются на очень коротких горизонтах предсказания HFT.
- Сложность развёртывания: инференс на GPU добавляет джиттер; линейная модель работает целиком в L1-кэше.
Для горизонтов дольше нескольких секунд нелинейные модели становятся ценными, но для предсказания следующего тика линейная модель трудно превзойти по скорректированной на риск доходности.
4. Стратегия разметки
Мы присваиваем направленную метку каждой паре снапшотов, используя порог $\tau$ (в базисных пунктах):
$$y_t = \begin{cases} +1 & \text{если } \frac{m_{t+1} - m_t}{m_t} \times 10^4 > \tau \ -1 & \text{если } \frac{m_{t+1} - m_t}{m_t} \times 10^4 < -\tau \ 0 & \text{иначе (стабильно)} \end{cases}$$
Выбор $\tau$ — это решение моделирования:
- $\tau = 0$: каждый ненулевой тик получает метку, что приводит к зашумлённым меткам.
- $\tau = 0.5$ до $2.0$ бп: фильтрует микро-шум; типично для крипторынков.
- $\tau > 5$ бп: предсказываются только крупные движения; меньше примеров, но чище сигнал.
Стабильные метки ($y = 0$) пропускаются при обучении, чтобы модель фокусировалась на направленных движениях.
5. Реализация на Rust
5.1 Структуры данных
Структура OrderBookSnapshot хранит полный снапшот Level-2, включая несколько уровней глубины. Ключевые методы:
mid_price()— арифметическая средняя цена.micro_price()— взвешенная по объёму средняя цена.imbalance()— дисбаланс уровня 1.depth_imbalance(levels)— взвешенный многоуровневый дисбаланс.
5.2 Извлечение признаков
extract_features(prev, curr) вычисляет все восемь признаков из двух последовательных снапшотов. Функция не выполняет аллокаций на горячем пути (все значения — stack-allocated f64).
build_feature_matrix(snapshots) обрабатывает полную последовательность в матрицу ndarray::Array2<f64>, подходящую для пакетного обучения.
5.3 Обучение модели
LinearQuotePredictor реализует:
new(num_features, learning_rate)— случайная инициализация.score(features)— необработанная линейная оценка (одно скалярное произведение).predict(features)— направление по знаку оценки.train_epoch(x, labels)— один проход online SGD с hinge loss.accuracy(x, labels)— метрика качества (исключая стабильные метки).
5.4 Нормализация
z_normalise(x) возвращает нормализованную матрицу вместе с векторами средних и стандартных отклонений, необходимых во время инференса для преобразования живых признаков.
6. Интеграция с Bybit
6.1 Получение данных стакана
Библиотека предоставляет как асинхронные, так и блокирующие функции для запроса REST API Bybit v5:
// Асинхронная версия (внутри tokio runtime)let snap = fetch_bybit_orderbook("BTCUSDT", 10).await?;
// Блокирующая версия (для синхронных контекстов)let snap = fetch_bybit_orderbook_blocking("BTCUSDT", 10)?;Эндпоинт GET /v5/market/orderbook возвращает до 200 уровней глубины. Мы парсим биды и аски в нашу структуру OrderBookSnapshot, автоматически извлекая цены и объёмы верхнего уровня.
6.2 Пайплайн живого скоринга
Торговый пример (examples/trading_example.rs) демонстрирует полный пайплайн:
- Обучение на синтетических данных (или исторических снапшотах).
- Получение живых снапшотов с Bybit с интервалом ~500 мс.
- Извлечение признаков из последовательных снапшотов.
- Нормализация с использованием статистик обучающей выборки.
- Скоринг и предсказание следующего направления.
В продакшене цикл опроса следует заменить подпиской на WebSocket orderbook.1.BTCUSDT для истинных обновлений в реальном времени.
6.3 От предсказания к исполнению
Положительная оценка предполагает, что средняя цена сдвинется вверх; отрицательная — вниз. Простая стратегия исполнения:
| Оценка | Действие |
|---|---|
| $f(\mathbf{x}) > \theta$ | Выставить лимитный ордер на покупку по лучшему биду |
| $f(\mathbf{x}) < -\theta$ | Выставить лимитный ордер на продажу по лучшему аску |
| $ | f(\mathbf{x}) |
Порог $\theta$ контролирует агрессивность стратегии. Более высокий $\theta$ означает меньше сделок, но более высокую ожидаемую прибыль на сделку.
7. Соображения производительности
7.1 Бюджет задержки
| Операция | Типичное время |
|---|---|
| Извлечение признаков (8 признаков) | ~50 нс |
| Z-нормализация | ~20 нс |
| Линейная оценка (скалярное произведение) | ~10 нс |
| Полный инференс | ~80 нс |
Это оставляет значительный запас в рамках типичного обмена сообщениями с биржей (1-10 мс).
7.2 Обновление модели
Микроструктура рынка нестационарна. Модель следует переобучать (или инкрементально обновлять веса) через регулярные интервалы:
- Внутри дня: переобучение каждые 30-60 минут по последним N снапшотам.
- Скользящее окно: поддерживать FIFO-буфер последних 50 000 снапшотов и периодически переобучать.
- Онлайн-обучение: обновлять веса после каждого предсказания, используя реализованную метку (когда она доступна).
7.3 Контроль рисков
- Лимиты позиции: не накапливать позицию больше настроенного максимума.
- Лимиты убытков: прекратить торговлю, если кумулятивный PnL падает ниже порога.
- Фильтр спреда: не торговать при спреде выше максимума (неликвидные условия).
- Проверка устаревания: если последний снапшот старше T мс, предположить потерю связи и закрыть позиции.
8. Расширения и продвинутые темы
8.1 Нелинейные модели
Замена линейного скорера на небольшое дерево решений или модель градиентного бустинга для маргинального улучшения точности. Ключевое ограничение — инференс должен оставаться менее ~1 микросекунды.
8.2 Мультигоризонтное предсказание
Вместо предсказания только следующего тика — предсказывать доходности на нескольких горизонтах (1, 5, 25, 100 тиков вперёд). Каждый горизонт получает свою модель, а сигналы комбинируются в мета-модели.
8.3 Межинструментные признаки
В крипте BTC часто ведёт движения альткоинов. Включение дисбаланса стакана BTC в качестве признака при предсказании котировок ETH может значительно улучшить точность.
8.4 Моделирование позиции в очереди
Помимо направления, моделировать позицию в очереди ваших стоящих ордеров. Вероятность исполнения зависит от того, сколько объёма стоит перед вами в очереди, а это меняется с каждым обновлением котировки.
9. Ключевые выводы
-
Обновления котировок — атомарная единица ценообразования. Предсказание следующего изменения котировки — фундаментальная задача микроструктуры рынка.
-
Дисбаланс стакана — самый предиктивный признак. Соотношение объёмов bid/ask на лучших уровнях показано на акциях, фьючерсах и крипте как предсказатель краткосрочного направления цены.
-
Линейные модели доминируют при ультранизкой задержке. Скалярное произведение 8 признаков выполняется за ~80 наносекунд на Rust, укладываясь в бюджет задержки HFT.
-
Нормализация признаков необходима. Необработанные признаки живут на очень разных шкалах (дисбаланс в [-1,1] vs dt_ms в [50, 500]). Z-нормализация обеспечивает равное отношение модели ко всем признакам.
-
Микро-цена — лучший оценщик справедливой стоимости, чем средняя цена. Взвешивание по отображаемому объёму корректирует микро-цену на асимметричную ликвидность.
-
Онлайн SGD с hinge loss естественен для потоковых тиковых данных. Модель обновляется за константное время на наблюдение, соответствуя темпу входящих рыночных данных.
-
REST API Bybit обеспечивает лёгкий доступ к данным Level-2. Для продакшен-систем WebSocket-поток обеспечивает обновления с меньшей задержкой.
-
Управление рисками так же важно, как и предсказание. Лимиты позиций, убытков и проверки устаревания предотвращают накопление катастрофических потерь при смене режимов.
10. Ссылки
- Cont, R., Kukanov, A., & Stoikov, S. (2014). The Price Impact of Order Book Events. Journal of Financial Econometrics, 12(1), 47-88.
- Cartea, A., Jaimungal, S., & Penalva, J. (2015). Algorithmic and High-Frequency Trading. Cambridge University Press.
- Stoikov, S. (2018). The Micro-Price: A High-Frequency Estimator of Future Prices. Quantitative Finance, 18(12), 1959-1966.
- Документация Bybit API: https://bybit-exchange.github.io/docs/v5/market/orderbook