Как стать автором
Поиск
Написать публикацию
Обновить

Построение стакана котировок (FullOrderBook) по историческим данным

Время на прочтение4 мин
Количество просмотров32K


Совсем недавно решал задачу построения стакана котировок на основе исторических данных Московской Биржи. В открытых источниках ничего подобного не нашел, пришлось начинать с нуля и копать самому. Есть некоторые нюансы, о которых нужно знать. Про них буду упоминать по ходу.

Про биржевую торговлю, инфраструктуру и тестирование алгоритмов на исторических данных много писал и пишет IT Invest, спасибо ему. От себя добавлю, что на данных OrderLogs мы анализируем глубину рынка, ликвидность, спреды и еще много чего. Результаты используем в наших торговых алгоритмах.

Специально выбрал Фондовый рынок, так как тут больше всего вопросов. Валютный и Срочный рынок имеют свои особенности, но там проще. Реализация алгоритма на Java, код на GitHub.

Цель: Получить стакан котировок на любой момент времени.

Что на входе?


Файл со всеми заявками/сделками (Full Order Log), полученный от Биржи за 1 день, простой CSV формат, объем ~ 1 Гб. Описание формата и примеры данных есть на сайте Биржи. Вот фрагмент файла:



  • Код бумаги — торговый код инструмента
  • Buy/Sell — напраление заявки купить или продать
  • Время — в формате HHMMSSZZZ (101738829 = 10 ч 17 мин 38 сек 829 мс)
  • ID заявки — по нему отслеживаем жизнь заявки
  • Тип события — {1 — пришла заявка, 0 — удалена заявка, 2 — сделка}
  • Цена — цена в руб. за 1 бумагу
  • Объем — объем заявки/сделки в количестве бумаг
  • ID сделки — заполняется если тип события=2
  • Цена сделки — заполняется если тип события=2

Так как данные получены прямо из торговой системы, то поле «Время» — это время фиксации событий в торговой системе. Это надо принять к сведению. Кто получает маркетдату через FAST, тем данные приходят с задержкой (latency ~ 0.1 мс в зоне колокации). Это я к тому, что, если вы тестируете алгоритмы на данных Биржи, то там во времени не учитываются задержки, которые есть в наших реалиях. Так что если такие времена не критичны, можно «забить» на latency.

Фондовый рынок стартует в 9:50 и закрывается в 18:50, проходя 3 фазы:

09:50 – 10:00 — Аукцион открытия (Формируется цена открытия)
10:00 – 18:40 — Основные торги
18:40 – 18:50 — Аукцион закрытия (формируется цена закрытия)

Файл содержит только «Основные торги» + неисполенные заявки с аукциона открытия.

Алгоритм сборки


Понадобится 2 типа объекта «Orders» и «OrderBook». Orders — это дискретные заявки (строка в файле). А объект OrderBook — это агрегированные по цене заявки имеющий 2 поля: цена и объем, т.е. складываем все объемы с одинаковой ценой.

Давайте соберем стакан для инструмента «XXXX» на момент времени AABBCCDDD. С первой строки начинаем собирать заявки (объекты Orders), касающиеся бумаги «XXXX» в коллекции. Заявки Buy в одну, Sell в другую. И будем перебирать все заявки пока time<=AABBCCDDD.

Если тип события = 1 (поставить заявку), добавляем заявку в коллекцию Buy или Sell в зависимости от направления заявки.
Если тип события = 0 (удалить заявку), то по номеру заявки находим ее в коллекции и удаляем. Она там непременно должна быть, ибо по логике, нельзя удалить то, чего нет. Если не нашли нужную заявку, надо бить тревогу (либо ошибка в самих данных, либо ошиблись мы сами).
Если тип события = 2 (сделка), то по номеру заявки находим ее в коллекции и смотрим на ее объем:

  • Если V1=V2 (V1 — объем заявки в коллекции, V2 — объем сделки), то заявку удаляем из коллекции. Это значит, что заявка исполнилась полностью;
  • Если V1>V2, то в коллекции изменяем объем V1 на V1-V2. Это значит, что заявка исполнилась частично. А часть осталась в стакане;
  • Если V1<V2 (да-да и такое может быть, т.е. объем заявки 10, а сделка произошла на 20) это признак «айсберг» заявки. В таком случае, заявку удаляем из коллекции.

Типы событий = 2 всегда идут попарно — две стороны сделки. Как только нарушается условие time<=AABBCCDDD, выходим из цикла. На этот момент у нас в коллекциях содержатся все активные заявки на момент AABBCCDDD. Сортируем элементы коллекций по цене. Теперь настало время создания объектов типа OrderBook, напомню, это ценовые уровни (агрегированные показатели цена — объем), т.е. то, что привыкли видеть в стакане котировок. Циклом проходим по всем заявкам и складываем объемы заявок с одинаковой ценой. Вот и весь алгоритм.

Заявки типа «По рынку»


У рыночныех заявок в поле цена указывается «0». Такие заявки, так же обрабатываем как обычные. Они исполняются в моменте.

Заявки типа «Айсберг»


Айсберг заявки также встречаются в ордерлогах. Как показала практика, их невозможно идетифицировать наверняка. При формировании данных Биржа применяет свой алгоритм, который скрывает «айсберги». Но все равно, в некоторых случаях они мелькают, например висит заявка с объемом 10, а когда превращается в сделку — объем уже 100.

Знание этой информации достаточно, чтобы собирать стаканы, анализировать спреды и глубину рынка.

А теперь самое вкусное: давайте проверим наш алгоритм на практике. 2 февраля 2016 специально сделал скриншоты с терминала Bloomberg со стаканом, зафиксировав время. Инструменты брал не самые ликвидные: Яндекс (YNDX), Камаз (KMAZ)… дабы избежать сложности с синхронизацией времени. Паралельно собрал стакан на Биржевых данных описанным выше алгоритмом. Вот результат на 16:56:21:



Данные идентичны.

Пару слов о скорости


В потоке около 15 млн записей, где содержится около 300 инструментов. Самый ликвидный инструмент SBER за целый торговый день прогоняет за 20 сек. Для SBERа глубина стакана в ту или другую сторону — 500-600 ценовых уровней. Если через каждый «час» сохранять состояние стакана, время обработки сокращается до секунды, что меня вполне устраивает. А если еще записать нужный инструмет в отдельный поток, время сократится до десятых секунд.

Таким образом, стакан по любому инструменту на любой момент времени получаем менее чем за 1 секунду. Уверен, кто-то сможет предложить более эффективный алгоритм, буду рад.

P.S.: Кусок исторических данных можно взять на сайте Биржи бесплатно. Если нужны данные имено за 2 февраля, выгружу на Я.Диск (~1Gb). Дайте знать.
Теги:
Хабы:
Всего голосов 13: ↑11 и ↓2+9
Комментарии5

Публикации

Ближайшие события