Торговая система QUIK для большинства серьёзных игроков рынка является очень популярной системой предоставления своим клиентам интерфейса для торговли ценными бумагами. Но в большинстве своём внутренности этой системы, как и любого коммерческого продукта являются закрытыми, в связи с чем могут возникать проблемы интеграции во внутреннюю инфраструктуру предприятия. В этой статье будут рассмотрены возможные механизмы интеграции QUIK в системы предприятия являющегося клиентом брокера или самостоятельным брокером.

Введение

DISCLAIMER: Все рассуждения и решения описанные в этой статье являются личной точкой зрения автора и могут не совпадать с точкой зрения разработчика продукта

С продуктами QUIK я познакомился более 15 лет назад, поэтому многие особенности продукта для меня являются привычными, но для большинства нюансы работы системы QUIK не всегда очевидны. Для того, чтобы понимать суть торговой системы и принцип её построения, можно обратиться к документации на сайте компании. Если коротко, то система построена по следующей схеме:

структура сервера QUIK.png
структура сервера QUIK.png
  • Вычислительное ядро + backend хранения настроек и данных(локальные файлы, MSSQL, экспериментально PostgreSQL)

  • Сервисы административного управления

  • Интерфейсы для подключения внешних модулей приёма/экспорта данных

  • Клиентские интерфейсы

Большинство модулей системы являются лицензируемыми, поэтому без наличия специализированных лицензий описываемый в статье функционал может быть недоступен.

Некоторые особенности системы

Не будем глубоко вдаваться во внутренности системы, но стоит отдельно упомянуть несколько очень важных моментов перед проработкой механизмов интеграции:

  • Продукт существует только под ОС семейства Windows

  • Сервер QUIK в процессе своего развития претерпевал множество изменений, которые очень сильно отразились на конечном продукте. Первая версия сервера QUIK с которой я столкнулся много лет назад, использовала для хранения данных Firebird/Interbase + BDE. В своё время это приводило к куче проблем с кодировками данных(KOI8R, CP866, CP1251, CP1252) при работе системы. И к сожалению даже спустя десятки лет системе требуются настройки BDE в системе и до сих пор есть проблемы с кодировками, что может стать неожиданностью для администраторов

  • Неявной проблемой является наследование программным кодом QUIK библиотек Microsoft Visual C++ 2005 и выше. При этом для разных продуктов системы требуются разные версии библиотек, что при эксплуатации нескольких продуктов на одном сервере усложняет унификацию конфигурации развёртывания

  • Множество продуктов линейки QUIK используют БД MS SQL для хранения данных и драйверы подключения к БД варьируются от нативных SQL Client до последних ODBC драйверов с поддержкой механизмов отказоустойчивости. При этом продукты могут работать в рамках одного сервера, но с разными версиями драйверов, что может вносить путаницу в настройки

  • У системы QUIK отсутствуют встроенные механизмы кластеризации (внешние механизмы репликаци имеются)

Рассмотрим подробнее части системы, так или иначе участвующие в интеграции

Транспортная часть

Транспортная часть представляет собой проприетарный протокол, защищённый шифрованием. Ключи шифрования трафика формируются при помощи различных алгоритмов в виде подключаемых библиотек. На моей памяти использовалось несколько алгоритмов/библиотек формирования ключей:

  • qcrypto32(основной)

  • signal-com

  • Multi Purpose SSPI

  • RSA

  • Placebo

Полученные при создании оригинального пакета KeyGen ключи имеют внутреннее имя и пароль для расшифровки. При использовании нескольких ключей в клиенте и сервисах, возможен масочный поиск по имени ключа. В случаях, когда защита соединения или подключения является лишней, используется можно использовать библиотеку Placebo_pr.dll, отключающую защиту.

Клиентское место

Система имеет определённый набор клиентских приложений, представленных на странице https://arqatech.com/ru/products/quik/terminals/user-applications/. Но полноценная клиентская часть реализована в виде персонального рабочего места, устанавливаемого на рабочую станцию участника торгов(клиента брокера). Дистрибутив персонального рабочего места(терминала) распространяется брокерами по запросу клиента и содержит в себе преднастроенный дистрибутив, в который перед началом работы необходимо импортировать ключи доступа. Интеграционное взаимодействие стационарного клиента с внешними системами доступно через подключаемые механизмы LUA и DDE. Через LUA можно полноценно работать с Client QuikAPI, через DDE выгружать информацию во внешние приёмники. Учитывая INTRADAY парадигму работы QUIK сервера, связанную в ежедневными перезагрузками для обнуления состояния системы, а также возможные разрывы соединения, оба механизма взаимодействия требуют присутствия сотрудника на рабочем месте для контроля работы при переподключении клиента.

Небольшая ремарка про старт клиентского места.
При старте клиента первым делом получается текущий(на момент старта) срез данных с сервера, согласно установленных администратором системы пользовательских настроек в административном модуле. Передача данных происходит блоками. До окончания полного приёма блока данных, клиент не сможет показывать вам какую-либо информацию в реальном режиме времени. По мере загрузки блоков данных, автоматически заполняются интерфейсные таблицы клиента и активируется передача во внешние программные интерфейсы. Чем больший объём данных(бумаги, счета) вам доступен, тем медленнее будет происходить старт клиента. При переподключении клиента к серверу часть получаемой информации может пропускаться в зависимости от наличия в кеше.

Скорость получения данных для клиентов сервера по умолчанию ограничена настройками сервера. Скорость получения измеряется в элементах в секунду. Элементом является любая передаваемая запись (заявка, сделка, котировка, изменение портфеля, прочее). Данный параметр можно изменять в настройках сервера только при уверенности, что клиенты выдержат бОльший поток данных, т.к. настройка является глобальной.

Quik Exporter

Модуль QuikExporter является headless readonly клиентом системы QUIK и обладает всеми возможностями клиентского места в части получения информации от сервера. Внутренние механизмы QuikExporter позволяют настроить экспорт по ODBC в базу данных(mssql,mysql, pgsql). Так же есть возможность написания своей библиотеки, которая позволит выгружать данные во внешний источник. Выгрузка в БД сопряжена с рядом особенностей, таких как:

  • отсутствие bulk insert. На каждый полученный элемент данных вызывается функция БД, хранимая процедура, либо INSERT в таблицу. Это очень сильно повышает транзакционную нагрузку на БД

  • Кодировка данных по умолчанию "WIN-1251", что вызывает проблемы с Unicode символами при обработке данных

  • Настройки ODBC влияют на работу с case-sensitive названиями объектов

Также одной из особенностей является то, что QUIK Exporter не всегда получает RealTime данные, вместо этого он получает порционные агрегированные данные предобработанные сервером.

Основные получаемые через QUIK Exporter данные можно разделить на несколько частей (полный список):
1. Данные связанные с инструментами (список классов, список бумаг, данные котировок)
2. Данные связанные с портфелем клиента (торговые лимиты и остатки на счетах, текущая оценка портфеля)
3. Данные связанные со сделками (заявки, сделки, обезличенные сделки)
Каждая организация в зависимости от построения системы торговли самостоятельно выбирает нужный набор данных и атрибутивный состав для получения.

Fix интерфейс

Fix интерфейс это отдельный модуль системы QUIK, обеспечивающий интеграционное взаимодействие и автоматизацию торговли через внешние системы. У модуля есть некоторые особенности о которых нужно знать:

  • При подключении можно использовать 2 интерфейса: торговый(канал заявок) + маркетдата

  • Интерфейс маркетдаты поддерживает realtime потоки заявок(order book) и котировок(quotes/rates)

  • Атрибутивный состав трансляции котировок немного отличается от глобального стандарта и не содержит объем бумаг

  • Данные об обработке заявки сервером или биржей могут вернуться в систему через канал экспортёра и канал Fix адаптера в разное время. Об этом нужно помнить при построении механизмов учёта сделок

  • При большом объёме данных возможны задержки в передаче информации. Плюс к этому стоит расчитывать каналы связи в соответствии с возможными объёмами данных.

QUIKAPI

Полноценный интерфейс для работы с сервером QUIK через вызов функций из программного кода(c,с++,c#). Механизмы API разделены по продуктам и распространяются среди брокеров с подробным описанием интеграции. Использование QUIKAPI позволяет производить низкоуровневое взаимодействие с API сервера, но может иметь высокий overhead по сравнению с другими решениями

Файлы данных сервера и клиента

Клиентское место и сервер хранят промежуточные данные в локальных ".ik" файлах с закрытым форматом. Все конфигурационные файлы созданы в .ini формате. Параметры подключения к серверу QUIK для большинства сервисов по умолчанию хранятся в открытом виде. Опционально часть сервисов позволяет зашифровать чувствительные данные подключения к серверу в конфигурационных файлах.
В большинстве своём взаимодействие с файлами сервера или клиента не является необходимым, за исключением момента с получением исторических данных.
Хранение данных расчитанных биржевых свечей по инструментам реализовано в виде специализированной структуры данных(об этом будет информация ниже), имеет ограниченную глубину и отличается по формату хранения на сервере и на клиенте.

Попробуем рассмотреть различные механизмы интеграции с корпоративными системами имеющими QUIK в качестве торговой системы.
Взаимодействие и интеграция с продуктами QORT в статье не рассматривается. Интеграцию по DDE и LUA в рамках корпоративной интеграции мы также не рассматриваем, т.к. она больше расчитана на клиентское место и малоприменима в корп.среде.

Интеграция с внутренними расчётными системами

Множество брокеров имеют внутренние системы учёта, в рамках которых ведётся бумажный портфель клиента, расчитываются комиссии, обеспечивается оперативный контроль за финансовым состоянием счетов клиента.

Основными общепринятыми механизмами интеграции являются:

  • использование QuikExporter с промежуточной информационной базой, в которую выгружаются данные о портфеле, сделках, заявках, бумагах и другой торговой информации

  • ручной либо автоматический (через QUIK Limits API) механизм корректировки портфеля клиента в торговой системе

  • интеграция через QUIKFix для интерактивных интерфейсов торговли/визуализации выдаваемых конечному клиенту, получения маркетдаты, каналов оповещения о сделках/заявках.

Начнём пожалуй с данных о портфеле пользователя.

Портфель клиента состоит из имеющегося объёма денежных средств в валюте торгов, списка и количества имеющихся бумаг в разрезе нескольких торговых дней. У большинства брокеров QUIK является системой "одного торгового дня", в которой хранятся актуальные данные только за текущий торговый день. При старте торгового дня, серверу(в качестве параметра запуска) передаётся статичный файл с расчитанными клиентскими данными, содержащий список и объём бумаг, а также финансовое состояние портфеля в разных валютах. При падении/выключении сервера, его старт без параметров приведёт к нулевым лимитам у всех клиентов. Для загрузки лимитов клиентов в этом случае необходимо с администраторского места выбрать и загрузить вручную файл с лимитами, либо запустить сервер с новым файлом лимитов. Если загружаемый файл с лимитами не будет соответствовать последнему состоянию портфеля клиента на момент сбоя/останова, то возможны проблемы с превышением лимитов торговли.

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

Для корректировки остатков/позиции на сервере QUIK используется два доступных механизма. Первый механизм это использование административной консоли(клиента) с запущенным в ней механизмом периодического чтения файла на сетевом или локальном ресурсе. Данный метод может давать сбои, т.к. клиент QUIK опрашивая файл открывает его в эксклюзивном доступе, при котором запись в файл(добавление данных о корректировке) недоступна. Размер файла при этом может быть достаточно большим в зависимости от количества операций корректировки и его чтение может занимать долгое время. Вторым механизмом является использование QUIK Limits API по управлению лимитами. Модуль управления лимитами представляет собой подключаемую библиотеку, которую можно использовать в разрабатываемых внутренних продуктах. Механизм является более универсальным, за исключением того, что разрабатываемый сервис так же является клиентом QUIK и подвержен проблемам с предварительной загрузкой данных(см. ниже).

Второй проблемой механизма является отсутствие блочных операций и необходимость точной синхронизации с торговой системой при корректировке остатков, т.к. изменения происходят напрямую во внутренних таблицах данных QUIK. Если между фиксацией остатка и командой корректировки произойдёт транзакция, то возможна установка некорректных значений лимитов для клиента. Поэтому стоит вести offline портфель в соседней расчётной системе для дополнительного контроля.

Итак вернёмся к интеграции. При использовании QuikExporter в качестве промежуточного механизма получения данных о клиентском портфеле с сервера QUIK, вторым по важности после устойчивой работы сервера, является обеспечение постоянного соединения между QuikExporter и сервером QUIK. Как было описано ранее, QuikExporter является headless readonly клиентом сервера QUIK. Сервис является stateless и не сохраняет свои данные или состояние при останове/падении/пропадании соединения. Также необходимо помнить, что объём передаваемых данных в сторону клиентов, так и в QuikExporter ограничен для обеспечения стабильности работы.

Попробуем немного посчитать. У нас есть 10000 клиентов, у каждого из них 3 счёта в валюте (рубли, доллары, евро). Плюс к этому портфель на 30 бумаг. При этом лимиты у нас существуют в двух днях(Т0 и Т+). 10000*3*2+10000*30*2 = 60000+600000 = 660000 элементов. Пропускная способность не сильно производительного mssql сервера примерно 1500-2000 транзакций в секунду. Итого для загрузки информации о портфелях в промежуточную базу нужно 660000/2000 = 330 секунд, это 5 с половиной минут. Можно бесконечно увеличивать мощность, но максимум того, что мы достигли, это примерно 9-11к вставок в секунду(при разгоне сервера QUIK) в режиме процедурной или инкрементальной вставки в БД. Использование механизмов группировки и блочной вставки позволило поднять скорость до 25к вставок в секунду. Использование внешней библиотеки позволяет увеличить поток до 50к элементов в секунду. Необходимо также помнить, что большое влияние на работу с БД оказывает атрибутивный состав элемента. Например для описания параметров бумаги существует более 60 полей, но не все они нужны и не всегда нужны.

Кстати о полях.

В пакете QuikExporter находится пример исходного кода для создания собственной библиотеки расширения для экспорта данных на c++. Библиотека собирается с SDK 8.1 32х битной или 64битной версии в зависимости от разрядности пакета и подключается в QuikExporter. В рамках внутреннего движка QuikExporter существует жёсткая связка полей и их типизации описанная в сопровождающей пакет документации. Согласно перечисленным в конфигурационном файле атрибутам элемента, которые необходимо передать в приёмник информации, внутренний механизм на каждый атрибут вызывает свою функцию для каждого типа данных, формирующую часть пакета для передачи. В связи с этим, чем длиннее список атрибутов, тем больше происходит вызовов. Все вызовы являются stateless, поэтому для формирования конечного элемента необходимо постоянно добавлять части в буфер с данными, перед отправкой конечной системе. При разработке библиотеки необходимо придерживаться методологии потокобезопасной разработки, т.к. экспортёр умеет отдавать данные в несколько потоков и если работу потоков смешать, ничего хорошего не получится.

При экспорте большого объёма данных через QUIK Exporter и невозможности приёмника принять весь приходящий поток данных, выделение памяти для QUIK Exporter начинает "распухать", что приводит к падению производительности и чрезмерной нагрузке на сервер где запущен пакет. К сожалению QUIK Exporter не умеет отдавать память обратно, поэтому либо придётся ожидать конца дня для перезапуска, либо перезапустить его во время паузы в торгах.

Как же повысить производительность и стабильность?

  1. Изменить подход к получению данных из QUIK. Например подключить очереди Kafka к QuikExporter в виде внешней библиотеки(до 50к элементов в секунду). Можно использовать внешнюю предварительную буферизацию и вставлять данные в базу блоками(до 30к элементов в секунду). Можно отгружать данные по ODBC вместо MS SQL в PostgreSQL с дальнейшей передачей в fdw. Скорость в этом случае зависит от приёмника и метода трансформации данных(trigger, function, publish/subscribe).

  2. Изменить подход к хранению данных клиентов. Читать данные выдаваемые в интерфейсе пользователя не из SQL базы, а из In-Memory базы, убрав лишнюю транзакционную нагрузку на БД

  3. Вставку данных в случае БД перевести на процедурный Upsert/Merge, но при этом нужны эффективно построенные индексы, которые при большом объёме данных могут стать серьёзной проблемой

  4. Обеспечить резервирование инстансов QUIK Exporter, по возможности расположив один из них рядом с QUIK для аварийного получения дампа со значениями портфелей

  5. Для управления корректировкой лимитов перейти на QUIK Limits API + очереди, исключив файловые операции

  6. Разделить нагрузку и доставку данных между несколькими экземплярами QUIK Exporter

Интеграция со информационно/статистическими системами

Основным параметром влияющим на принятие решения о покупке/продажи бумаги является рыночная цена. За ценой нужно следить и по возможности следить за несколькими бумагами одновременно. В рамках клиентского места QUIK отслеживание изменения цен происходит в визуальном либо полуавтоматическом режиме просмотра "биржевого стакана". "Биржевой стакан" показывает объёмы и цены заявок на покупку и продажу. Совершаемые сделки покупки или продажи изменяют рыночную цену и содержимое стакана. Самописные или профессиональные статистические системы анализируют динамику изменения цены и стараются обеспечить сохранность денежных средств при падении бумаги или повышенный доход при её подъёме.

Для удобства учёта ценные бумаги имеют официально зарегистрированный внутрибиржевой торговый код(тикер), класс бумаги и международный идентификатор(ISIN). Классы бумаг помогают быстро определять принадлежность инструмента к определённому типу ценных бумаг(акция, облигация, долговая расписка, прочее). Система QUIK позволяет подключать внешние модули для формирования и работы с виртуальными классами бумаг. При подключении к бирже либо сторонней торговой системе, сервер QUIK запрашивает список доступных бумаг и классов, которые потом соединяются с внутренними классами и бумагами и транслируются клиентам, подключающимся к торговой системе. Административный интерфейс QUIK позволяет ограничить набор классов и бумаг транслируемых конкретному клиенту или группе клиентов.

При использовании QUIK Exporter или QUIK Fix в механизмах получения текущих котировок нужно понимать, что подход к использованию этих инструментов отличается. QUIK Exporter являясь клиентом торговой системы, по умолчанию получает все доступные ему классы и бумаги с сервера QUIK. Включение фильтра на классы или бумаги в самом QUIK Exporter не приводит к ускорению получения данных, т.к. фильтрация данных происходит в момент их получения на клиенте. При включении ограничения для логина QUIK Exporter на самом сервере через административный интерфейс, фильтрация данных будет обрабатываться на стороне сервера, что позволит исключить лишний трафик и ускорить доставку.
Fix подключение для поставки маркетдаты использует механизм подписки по нужному списку инструментов. При использовании данного подключения рекомендуется периодически перезапрашивать список инструментов с сервера для обновления. К сожалению канал маркетдаты в QUIK Fix не является самодостаточным источником данных котировок, т.к. атрибутивный состав Fix протокола сильно урезан и отличается от атрибутивного состава информации в QUIK Exporter. Как и любой канал подписки, работающий с сырым потоком данных по заявкам и котировкам, при большом объёме списка инструментов могут наблюдаться задержки в передаче данных. При активной торговле в течении торгового дня, особенно в моменты старта и закрытия торговой сессии, может наблюдаться переизбыток данных, который негативно сказывается на отображении информации на стороне клиента. Ни один внешний клиент находящийся в мобильном приложении или веб интерфейсе не сможет обработать поток данных в 50-100 изменений котировки в секунду для одной бумаги. Поэтому удобнее использовать котировки приходящие в предрасчитанном сжатом режиме по каналу QUIK Exporter. Если вы строите аналитическую realtime систему, то при небольшом списке бумаг использование маркетдаты через Fix протокол может быть вполне оправдано.

Если есть необходимость постройки своей статистической системы для отображения биржевых свечей конечным пользователям, то у этой задачи есть несколько путей решения. В большинстве своём для построения биржевых свечей используется механизм анализа совершённых обезличенных сделок. Список обезличенных сделок представляет собой информацию содержащую идентификатор, тикер бумаги, время, цену и объём совершённой на рынке сделки.

Принцип расчета данных очень прост. Значение цены первой сделки в срезе является ценой открытия(open), последней сделки в срезе - ценой закрытия(close), минимальные и максимальные значения соответственно min и max и последнее значение это сумма объёма торгов. Первичным и самым важным требованием для построения правильных биржевых свечей является сохранение последовательности информации полученной из торговой системы. Это требование возникает из-за минимального кванта времени используемого для временного отпечатка сделки в QUIK равного 1 секунде. За одну секунду может быть зарегистрировано несколько сделок и смена их порядка повлияет на расчёт.

В методе хранения, расчёта и предоставления доступа к данным, используемым для визуализации биржевых свечей, каждый выбирает свой путь.

Не очень опытные участники рынка используют обычный SQL в качестве хранилища данных, сталкиваясь позже с огромными издержками и задержками при хранении больших объёмов данных, поисковых индексов и групповых операций при сборке свечи.

Более опытные участники используют механизмы хранения данных основанные на базах временных рядов(influxdb, postgresql+timescaledb, tsdb и прочих). Базы временных рядов имеют специализированные возможности группировки по временному срезу, и различных операций(first(open),last(close),max(high),min(low),sum) по группированным блокам данных, для получения конечного массива значений. Основным недостатком является малая нагрузочная способность таких систем из-за математических операций и группировки.
Самые опытные участники используют комбинированные решения с расчётом свечей в реальном режиме времени, параллельной выгрузке в каналы доставки, базы временных рядов и в кеширующие системы. Нагрузочная способность таких систем может выдерживать десятки тысяч запросов в секунду.

Многие задаются вопросом: "А где взять начальную базу свечей для моей системы?"
Опять же обратимся к системе QUIK. Сервер QUIK умеет расчитывать свечи и сохранять их в реальном режиме времени в свои файлы, содержимое которых может потом передавать клиентам. Формат файла закрыт, но путём анализа файлов и редактора этих файлов был разобран его бинарный формат. Ниже скрипт для автоматического разбора группы файлов из бинарного формата в человекочитаемый.

quik_candlefile_dat_parser.py
#!/usr/bin/python
# -*- coding: utf-8 -*-

from hexdump import *
import pathlib, os
import struct
from collections import OrderedDict
import binhex

tpl = [(1, '1 min'),
       (2, '2 min'),
       (3, '3 min'),
       (4, '4 min'),
       (5, '5 min'),
       (6, '6 min'),
       (10, '10 min'),
       (20, '20 min'),
       (15, '15 min'),
       (30, '30 min'),
       (60, '1 hour'),
       (120, '2 hour'),
       (240, '4 hour'),
       (-1, '1 day'),
       (-2, '1 week'),
       (-3, '1 month')]

slices = OrderedDict()
for i in tpl:
    (id, name) = i
    slices.update({id: name})

def calcoffset(f, datablocks, candlerange=1, numofcandles=1):
    sliceslist = list(slices.keys())
    sliceindex = sliceslist.index(candlerange)
    return sum(datablocks[:sliceindex]), datablocks[sliceindex]

def parsefile(f, candlerange=-1):
    datablocks = list()

    for slice in slices.keys():
        data = f.read(48)
        candlerangenum, candlecount = struct.unpack('ii', data[-8:])
        datablocks.append(candlecount)

    offsetblock, numberofcandles = calcoffset(f, datablocks, candlerange)
    print('='*50)
    print('%s: Offset %d for %d candles in range %s' % (f.name, offsetblock, numberofcandles, entries[candlerange]))
    f.seek(768 + 48 * offsetblock)
    for candleid in range(numberofcandles):
        data = f.read(48)
        (v, o, h, l, c, date, time) = struct.unpack('dddddii', data)
        if time == 0:
            time = '%06d' % 0
        print('File: %s. Candle %d: %s %s. Open: %.2f  High: %.2f Low: %.2f Close: %.2f Volume: %.0f' % (
            f.name, candleid, date, time, o, h, l, c, v))


with os.scandir('TQBR') as d:
    for datfile in sorted(d, key=lambda d: d.name):
        if datfile.is_file() & datfile.name.endswith('.dat'):
            f = open(datfile.path, 'rb')
            parsefile(f, candlerange=-1)

Обратите внимание, что последовательность срезов в самом начале скрипта является сломанной. После 10 идёт 20, потом идёт 15. Но это не баг, а "фича". Историю "фичи" не знаю, но при выгрузке среза будьте внимательны, чтоб не ошибиться.
Архивы файлов с расчитанными свечами можно попросить у разработчиков системы QUIK - компании ARQA Technologies.

К сожалению файлы свечей QUIK имеют один существенный недостаток. Длина любого временного среза ограничена размером в 3000 элементов. Поэтому для получения более глубоких данных для определённого среза, следует обратиться к другим источникам.

Перед тем как формировать хранилище срезов оцените необходимую глубину данных по каждому срезу. Самые популярные срезы это 1м,5м,30м,1ч,1д. При расчёте суточного среза необходимо учитывать время работы биржи. Так например торговый день ММВБ начинается в 7 утра, заканчивается в 23:50, у СПБ Биржи начинается в 7 утра и заканчивается в 1:45 ночи. Поэтому если вы обрежете свечи бумаг торгуемых на СПБ Бирже бумаг в 00:00, то расчёты срезов больше 1 дня скорее всего будут неверными. Если вы распространяете свечи и котировки для внешних потребителей, не являющихся клиентами брокера, необходимо помнить о правиле задержки на 15 минут всех биржевых данных, которое прописано в регламенте подключения к биржам.

Вернёмся к котировкам. При совершении сделки по бумаге на бирже, меняется её котировка(рыночная цена). При большом количестве сделок происходит очень много событий изменения цены. При построении аналитических систем использующих ценовые потоки QUIK, следует учитывать следующие особенности:

  • Котировки идущие через QUIK Exporter имеют квантование по времени для снятия нагрузки на сервер и клиентов. Т.е. в квант времени из 20 котировок пришедших на сервер, клиенту будет отправлена последняя или агрегированная котировка

  • Realtime котировки идущие через QUIK Fix не содержат количества бумаг в сделке

Для уменьшения объёма трафика и увеличения скорости доставки, подписку на котировки через Fix рекомендуется лимитировать ограниченным списком наиболее популярных инструментов. Учитывайте также ширину и загруженность канала до сервера.

Что касается формирования и визуализации биржевого стакана в интерфейсе клиента из потока обезличенных заявок, определитесь сначала с тем, что вы хотите получить от этой визуализации и на чём вы это показываете. Если просто показать клиенту стакан как "фичу" в телефоне, то при большом объёме заявок ничего кроме моргающего нечто вы не получите. Плюс вы тупо будете гонять бесполезный трафик и тратить батарейку телефона. Если вы действительно хотите показать функциональный стакан в интерфейсе, то продумайте алгоритм доставки, требуется ли интерактив по выставлению заявок из стакана, анализируйте потоки обезличенных сделок и заявок. Правильный стакан очень помогает клиенту выставить заявку в нужный момент.

Основные разделы по доставке данных мы разобрали. Подведём итоги:

  1. Работа с получением данных в реальном режиме времени требует грамотного планирования информационной системы и понимания специфики источника данных

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

  3. Пользовательские интерфейсы должны прорабатываться заранее, на основании имеющихся или планируемых потоков данных. Не надо гнаться за "фичами", главное функциональность

Мониторинг потоков данных

Рано или поздно возникает вопрос мониторинга и замера RTT для контроля задержек работы торговой системы. Так как же это сделать наиболее доступными и очевидными способами ?

  1. Замер через выставление заявки. Используя Fix или LUA выставить фейковую заявку по внутренней/биржевой бумаге, которая никогда не исполнится. При помощи Fix, LUA или Quik Exporter поймать эту заявку по идентификатору клиента и посчитать время получения. После этого снять заявку и еще раз посчитать время. Данный метод покажет RTT между клиентом, сервером, биржей и клиентом

  2. Замер через корректировку баланса. Через любой интерфейс управления изменить баланс сервисного счёта(не имеющего прав торговли) на unixtime с милли или микросекундами, после чего поймать сообщение об изменении баланса на QUIK Exporter. Разница между установленным значением и текущим значением времени(с учётом синхронизации часов на корректировщике, сервере и приёмнике) покажет задержку доставки данных от сервера до потребителя

  3. Оценка скорости приёма данных на QUIK Exporter и производительности приёмника данных. Если у вас в системе большое количество клиентов и таблицы MoneyLimits и DepoLimits содержат большое количество записей, то есть простой способ замерить время доставки через лог QUIK Exporter. Дело в том, что в момент начала фазы передачи данных таблиц MoneyLimits и DepoLimits, QUIK Exporter полностью блокирует приём любых данных кроме этих, до окончания передачи.
    Фаза начала загрузки данных характерируется наличием строки
    "New AT_DATA_MARKER alert type N_MONEY_LIMIT state 0" или "New AT_DATA_MARKER alert type N_DEPO_LIMIT state 0".
    Фаза завершения загрузки данных характеризуется наличием строк
    "New AT_DATA_MARKER alert type N_MONEY_LIMIT state 1" или "New AT_DATA_MARKER alert type N_DEPO_LIMIT state 1".
    Строка MoneyLimits(count-xxxx queue-xxxxx) покажет вам готовность вашего сервера принимать входящий поток данных. Разделите количество элементов в поле count на время в секундах между двумя фазами и вы получите тот объём элементов, который готов принять ваш ODBC приёмник или библиотека в секунду. Чем больше поле queue, тем больше проблема с быстродействием

Вот в принципе и всё, что я хотел рассказать в данной статье. Как показывает опыт, не бывает идеальных систем, любая из имеющихся или строящихся систем имеет свои недостатки и преимущества. Если правильно подходить к архитектуре построения информационных систем предприятия, учитывая специфику смежных продуктов, можно достичь очень хороших результатов для себя и своих клиентов.

(C) Aborche 2022
(C) Aborche 2022

Комментарии (0)