Блог им. AgentSmith

Немного о сервере данных для торговли

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

На данном этапе увлекло меня создание транзитного сервера для данных. Что подразумевается под транзитным сервером?
Допустим, есть сторонний датафид. И мы хотим логически (а при необходимости и физически) разнести инфраструктуру для торговли.
Наш сервер будет получать Live-данные от датафида, кэшировать, сохранять на диск и в то же время ретранслировать видоизмененный поток данных клиенту, где бы тот ни находился — на той же машине или на удаленной.

Что это нам дает?
Будем исходить из того, что, даже если датафид позволяет запрашивать исторические данные, их содержимое может существенно уступать по детализации Live-данным, поставляемым тем же датафидом.
К примеру, IQFeed в виде тиков дает историю трейдов с лучшими Ask и Bid только на момент сделки, в то время как Live-данные транслируют весь поток L1. Если торговая система L1 не использует, то разница для нас значения не имеет.
В противном случае (а также если мы позже захотим использовать эти данные для тестирования ТС на инструментах, где за день проходит малое количество сделок — малоликвидные акции или опционы), отсутствие данных послужит досадной помехой.
И вот тут критическую роль сыграют обрывы связи (или перебои электропитания), если вся торговля ведется на нашем локальном компьютере. Решение очевидное — перенести программную инфраструктуру на удаленный сервер.
Пойдем немного в сторону — создадим программную прокладку, упомянутую выше. Таким образом, мы обезопасим себя (или, во всяком случае, минимизируем риски) от пробелов данных, связанных с потерей соединения или питания, и в то же время можем разместить торговую логику на другом компьютере.
К примеру, на домашнем. Зачем так делать? Допустим, торговая логика использует очень «тяжелые» вычисления или нуждается в огромном количестве памяти, а оплачивать машину в облаке с такими параметрами выльется в немалую «копеечку». А дома уже стоит системник с подходящими характеристиками и стоимостью как аренда в облаке за полгода аналогичного. Да и если торговый алгоритм из-за ошибки при разработке «сожрет» всю доступную оперативу, это не приведет к падению сервера данных, так как они на разных машинах.
Понятно, что такой подход всего лишь решает вопрос целостности данных, но в данном случае задача состоит именно в этом.

Таким образом, убедив самого себя, что изобретать велосипеды — это совсем ни разу не потеря времени, приступил к основам.
Как я уже писал, выбор пал на Windows Registered I/O.
Учитывая, что знаний в области сетевых коммуникаций у меня было не так и много, кроме самых общих, то процесс вливания в разработку транзитного сервера сопровождался созданием некоторого количества тестовых программ для уверенности, что все будет работать так, как я ожидаю.
Что привело меня к «открытию» таких чудес, как алгоритм Нагеля и delayed ACK… В связи с чем появилась надобность новых тестов.
И вот здесь мы, наконец, подходим к теме данного топика. Все далее описанное предполагает использование протокола TCP/IP, ОС Windows Server 2019.


RIO позволяет работать с множеством буферов для отправки и получения данных. И меня заинтересовало, какими рассуждениями следует руководствоваться при выборе количества буферов и их размера.
Если вы думаете, что это не имеет значения, попробуйте отослать несколько мегабайт с сервера, имеющего один буфер размером 64 байта. Я попробовал.
Итак, покопавшись и интернете в попытках разобраться в причинах такого результата, я приобщился к таинствам вуду протокола TCP/IP. С учетом приобретенных знаний, логически рассуждая, ответ на вопрос о количестве и размере буферов становится достаточно очевидным.
Но убедиться все равно надо. Тем более, что нам нужно остановиться на разумном количестве, обеспечивающем желаемую пропускную способность сервера.

Что используем: два сервера, физически разнесенных как можно дальше друг от друга для обеспечения максимальной латенси — один в США, другой в Европе. Пинг между серверами показал 157мс, хотелось бы побольше, но и так сойдет.
На одном сервере клиент для считывания данных (со статичными значениями размера и количества буферов чтения), на другом сервер. Батником в консольном режиме запускается сервер, в командной строке параметрами передаются значения размера буфера отправки и их количество.
В течении одной минуты сервер отсылает подготовленные данные клиенту, завершает работу, затем батник запускает сервер со следующим набором параметров. В отдельном потоке логгер каждые 160 мс считывает значение счетчика отправленных байт за этот промежуток времени, при завершении работы сервера сохраняет последовательность в файл на диске.
Синхронизация не используется, просто запись-чтение (данные выровнены по 8-байтной границе). Почему 160мс? Выбирал значение, кратное 16мс, чтобы получить несколько отсчетов за 1 секунду.
Логика теста пропускной способности: сервер сначала отправляет данные из всех буферов, дожидается подтверждения первого отправленного пакета, затем активирует логгер. Как только какой-либо буфер становится свободным — сервер отправляет из него данные величиной в размер всего буфера.
Клиент после закрытия соединения ждет 3 секунды, прежде чем приконнектиться к серверу — как уже говорил, конструировалась максимально простая связка сервер-клиент для теста в пакетном режиме пропускной способности при заданных параметрах и латенси.
На мой взгляд, одной минуты достаточно, чтобы получить представление — получается около 400 отсчетов.


Проводилось три типа тестов:
1) Размер буфера фиксирован — 8192 байта; количество меняется от 1 до 8192, являясь степенью двойки (общий размер до 64 Мб)
2) Суммарный размер (<размер буфера> * количество) фиксирован 64 Мб, размер и количество меняются, являясь степенями двойки
3) Размер буфера фиксирован — 65536 байт; количество меняется от 1 до 1024, являясь степенью двойки (общий размер до 64 Мб)

Тесты проводились дважды, клиент для считывания использовал 16 буферов размером 4096 байт в первый проход, 256 буферов размером 8192 во второй. Картина наблюдалась аналогичная при соответствующих параметрах сервера.
Тестирование не предполагало получение исчерпывающих, точных результатов, поэтому не исключено влияние внешних факторов, таких как: работа планировщика потоков ОС, нагрузка на сеть сторонних приложений или клиентов, балансировка максимальной пропускной способности софтом облака (если таковой существует) и т.п.




И шо вы таки себе думаете? Этот хитрый делец Билли Гейтс ворует нашу пропускную способность!

Немного о сервере данных для торговли



Пояснения к графикам:
по оси Х — количество отсчетов от запуска сервера (каждый отсчет — 160 мс)
по оси Y — количество байт, переданных ОС «на отправку» за время отсчета
имя графика Srv_aaa_bbb — aaa — размер буфера в байтах, bbb — количество буферов

Соответственно, чтобы получить пропускную способность сервера в байтах/секунду нужно значение по Y разделить на 0.16, в битах/секунду — еще домножить полученное значение на 8
Как легко догадаться, координата 18 000 000 дает 900МБит/секунду — близко к потолку гигабитной сети


Итак, что же мы видим?

Тест1. Фиксированный размер буфера 8192, количество меняется.
Результат предсказуем:

Немного о сервере данных для торговли
Немного о сервере данных для торговли
Немного о сервере данных для торговли
Немного о сервере данных для торговли


повторный проход (приводится только часть графиков — остальные не имеют заметных отличий):


Немного о сервере данных для торговли

Немного о сервере данных для торговли


Тест3. Фиксированный размер буфера 65536, количество меняется.


Немного о сервере данных для торговли
Немного о сервере данных для торговли
Немного о сервере данных для торговли


повторный проход (приводится только часть графиков)


Немного о сервере данных для торговли



Тест2. Суммарный размер фиксирован — 64 Мб


Немного о сервере данных для торговли
Немного о сервере данных для торговли
Немного о сервере данных для торговли


повторный проход


Немного о сервере данных для торговли
Немного о сервере данных для торговли
Немного о сервере данных для торговли



Какие предварительные выводы можно сделать?
— пока нагрузка на канал связи не достигает близкой к максимально возможной,  расход топлива скорость отправки стабильна
— при некоторых условиях пропускная способность сервера может быть нестабильной — в одном из тестов, достигнув потолка гигабитной сети, значение упало в 100 раз и держалось на таком уровне полминуты.
 Хорошая новость — на практике мы вряд ли будем иметь такой поток данных, для которого понадобится гигабитная сеть.

Исходя из результатов тестов, можно предположить, что причиной нестабильных результатов является одна из трех возможностей:
а) когда канал забивается до допустимого потолка
б) если суммарный размер одновременно используемых буферов превышает максимальный размер внутреннего буфера ОС (точное значение размера не сообщается, судя по информации с сайта Майкрософта, и может варьироваться в зависимости от ОС).
  Если присмотреться к графикам, можно предположить, что проблемы начинаются, когда суммарный размер превышает 8 Мб.
в) мне просто не повезло, и именно во время тестирования конкретных параметров сеть приходилось делить с кем-то еще (может, ОС решила что-то подгрузить?). Во время обоих проходов.

Вопрос к залу: что, по вашему, послужило причиной «расколбаса» пропускной способности сервера? «Индусский код» в качестве причины пока вынесем за рамки обсуждения.

★1
41 комментарий
Как всё вышеописанное влияет на прибыльность торговли?
avatar
Fairman, Интересуюсь мнением технически подкованных коллег по поводу непонятного мне момента. Ситуация-то не теоретическая, задача лежит вполне себе в практической плоскости — создание программного транзитного сервера данных (торговая инфраструктура)
Спасибо! Приятно видеть такие статьи на смартлабе!
Вывел на главную
Тимофей Мартынов, благодарю, но ценность статьи для смартлаба преувеличена. В начале немного общих рассуждений, потом чисто технический вопрос.
Шишки, грабли, windows не меняется.
Не строят такие системы на винде. Если конечно хочется не получить очередными граблями под конец тяжких трудов.

Ну и главное — нет смысла в ретрансляции данных. Есть смысл в заливке их в быструю среду, наложение на них необходимых функций, предагрегация и упаковка в быструю БД с компрессией. Тогда можно работать с этими данными в реальном времени, обставляя 99% наколенной бытовухи на винсерверах.
Есть такая штука, называется брокер сообщений: RabbitMq, Kafka и т.д. зачем изобретать велосипед?
Иван Иванов, нужно следить за развитием технологий, пожелаем автору этого, потому что энергии у него уже есть (был) вагон
Брахман Пилорама, хехе, вы даже не представляете сколько энергии трачу. Описанное — это только часть, всего лишь повод отвлечься, переключить внимание. Основные усилия направлены в другом направлении, там рутины и монотонности столько, что отсутствие результата демотивирует, и спасает только периодическое переключение усилий на что-то созидательное, что приносит удовольствие, хоть и в практической плоскости покажется многим потерей времени
Дед Нечипор, знания — сила, потому что позволяют не заниматься велосипедингом.
От прочитанного картинка не сложилась. Вроде речь про TCP, но в то же время и про какие-то подтверждения. Отправка запуском бантиков порядка 10раз в секунду доставляет.
В сетевых коммуникациях я разбираюсь, можем голосом обсудить
avatar
Roman Ivanov, про подтверждения — это относится к RIO. Там можно указывать метод уведомления (например, с помощью Event) когда ОС обработает запрос на отправку из очереди и буфер снова будет доступен для повторного использования.
По поводу второго — там немного не так. Батник запускает программу-сервер раз минуту с новыми параметрами, а вот несколько раз в секунду считывается значение счетчика отправленных байт, т.е. мы получаем минуту измерений одного набора параметров с частотой замеров несколько раз в секунду.
По поводу голосового обсуждения — благодарю, но не вижу смысла кого-то беспокоить. Думал, может это типичная ситуация с сетью, и кто-то отпишется, к примеру: «да, такие чудеса бывают, когда используешь канал в облаке на полную»
Лонгрид осилил. Это конечно очень интересно, но по моему маркет-дату лучше покупать. Во первых не надо городить инфраструктуру, а во вторых, если вам завтра захочется новый инструмент исследовать, то вместо исследований вы будете ждать пока накопите данные. Ну а если вы вообще весь поток сохраняете, то вы сами становитесь копией какого-нибудь IQ-фида. Эдакое «Закешируйте мне весь интернет, я его на даче в офлайне читать буду» )
avatar
Sprite, вы точно уловили суть моего велосипеда:
Ну а если вы вообще весь поток сохраняете, то вы сами становитесь копией какого-нибудь IQ-фида

мне просто захотелось иметь возможность еще и сохранять L1 (полагаю, многие датафиды, как и IQFeed при обрыве связи позволяют подкачать только трейды).
Sprite, покупать весь L1 чисто для исследований для частника дорого (да я и не встречал предложений исторических данных всего потока L1, максимум — трейды с BBO на момент сделки). А есть желание покопаться в индексе волатильности для отдельных акций или их кастомного портфеля, при малом количестве сделок его на исторических данных особо не построишь

Дед Нечипор, всё продается, L1, L2, full order log
PS Но сам я коплю, а не покупаю )

avatar
Вам бы с таким на хабр. Тут всё такие «серьёзные трейдеры» собрались, которые знают как изменение ставки влияет на бизнес и потребителя, а Вы им про delayed Ack :)
avatar
Сиделец, так и я же только-только узнал про него! Пусть и другие узнают и порадуются! А если без шуток, то низковат мой технический уровень лезть на хабр. Проще спросить здесь — распределение аудитории по сферах компетенции очень широкое, кто-то да знает ответ
Дед Нечипор, это скорее на хабре в последнее время странности разные полезли левые — давно забросил читать.
Так то да, может тут тоже кто в теме откликнется. Мне просто казалось что «бытовые алгоритмисты» обычно более высокоуровнеными инструментами пользуются, тут же слишком приземлённо и многие вопросы ценны сами по себе, без привязки к торговле.

(имхо лезть в такое имеет смысл чтобы набить руку и зарабатывать прикладными навыками в другой области, или на дядю работать за зарплату. Ну может конечно еще и просто как развлечение если пассивный доход уже позволяет в игрушечки играться).
avatar
Так и не понял, что там тестировалось и зачем. Windows registered IO, и задержка в 160 мс, вы серьезно? Там ожидаемые улучшения от WRIO, будут в районе микросекунд или меньше. Речь конечно про latency, гигабит throughput прокачивается без проблем и на сокетах.
А по поводу ваших вопросов, данные не телепортируются. Они бьются на пакеты, и идут по проводам/оптике, через маршрутизаторы, чем длиннее этот путь, тем больше задержки и меньше пропускная способность.
avatar
vlad1024, задержку выбирал побольше, чтобы убедиться в правильности моего понимания сути проблемы, так сказать, в экстремальных условиях. Цель тестирования — проверить, есть ли разница в том, какой набор буферов использовать. Если утрировать — один, но большой, или маленькие, но ооочень много (повторять голосом Карцева). Я-то не знаю, вдруг, начиная с какого-то размера будет заметная деградация. Потому и решил убедиться
Дед Нечипор, да это я более менее понял. Проблема в том что в алготрейдинге вы вряд ли упретесь в пропускную способность канала(throughput), гораздо важнее задержка(latency). Никто не ставит сервера, чтобы торговать на другой стороне океана от источника данных и исполнения.
И вторая проблема, что Windows RIO это достаточно сложная технология тем более прибитая к винде(да есть io uring, но сути не меняет). Поэтому для начала хорошо бы было сравнить WRIO со стандартными сокетами. И посмотреть, есть ли у WRIO какие-то реальные преимущества на ваших задачах.
avatar
vlad1024, я в WRIO полез не просто от скуки. Пользовался самодельным качком исторических данных IQFeed (писал на Delphi, сетевые компоненты оттуда же), так там вылезали проблемы, причин которых я понять не мог.
В среднем раз в несколько десятков тысяч-сотен тысяч запросов вылезал Access violation чтение по адресу $00020. Путем долгих и мучительных отладок и вставок где только можно логирования удалось локализовать проблему до одной команды. Ею оказался вызов обертки Delphi вокруг команды WinSock на предмет готовности сокета (наличия данных). Не могу представить, что проблему вызывало что-то другое, где бы я набокопорил: идут три команды подряд — 1) запись в лог «вызов ххх» 2) сама функция Delphi ххх 3) запись в лог «завершено ххх». Так вот при ошибке AV в логе было «вызов ххх» и все. 
Или еще — примерно с той же частотой запросов получал неполные данные (начало отсутствовало).

Понимаю, что у любого опытного программиста естественной реакцией будет — ищи ошибку в своем коде. Но я реально перелопатил там все несколько раз. И в будущем разбираться, где проблема — то ли в сетевом компоненте Delphi, то ли в Windows, то ли в самом IQFeed не особо хочется. Поэтому и появилось желание закодить самому что-то низкоуровневое, чтобы отсечь хотя бы часть потенциальных проблем.
Дед Нечипор, так это лично у меня основной вопрос, есть ли существенные преимущества у WRIO перед обычными сокетами. Сокеты это и есть самый низкий уровень, они дальше уходят в ядро, сетевой стек и железо. Проблема очевидно не в винде и сокетах, а в кривой прикладной программке.
avatar
vlad1024, понимаю, что ошибка скорее всего у меня, но совершенно не могу представить как?! Локализовав ошибку записями в лог до одной команды (сейчас уже не вспомню какой), которая вызывает функцию ядра, с очень редкой воспроизводимостью. Тут уж поневоле, хочешь-не хочешь, а начнешь искать альтернативы, лишь бы не биться головой о стену и не гадать — у меня проблема, или это тот редчайший случай, когда все-таки это у разработчика «не баг, а фича!»

Дед Нечипор, так Delphi уже давно не поддерживается, и косяки там вполне могут быть. Вероятность найти ошибку в виндовых сокетах, просто нулевая. Если бы вы сами написали код с вызовом системных send/receive/select без делфи, тогда можно было бы посмотреть.
avatar
vlad1024, так и была такая мысль как решение, а потом подсмотрел у кого-то на смартлабе про WRIO, и решил «а не замахнуться ли нам на...», если уж все равно время тратить.
Если бы вы сами написали код с вызовом системных send/receive/select, тогда можно было бы посмотреть

Delphi, кстати, новые выпускают постоянно. Даже на бесплатную версию расщедрились. Хоть и не без косяков, я лично один в какой-то из предыдущих версий нашел.
Дед Нечипор, у дельфи менеджер памяти не очень работает под нагрузкой, или уменьшайте операции с памятью создание/удаление объектов, делайте фиксированные буфферы или высоконагруженые части лучше переписать на C#.
Иван Иванов, а это повод похвастаться еще одним велосипедом — уже давно сделал свой менеджер памяти. Правда, он делался исключительно под конкретную задачу для собственного тестера и для общих задач не подойдет.
И спасибо за совет по поводу операций с памятью, я так и стараюсь делать.
Дед Нечипор, 
 Цель тестирования — проверить, есть ли разница в том, какой набор буферов использовать. Если утрировать — один, но большой, или маленькие, но ооочень много (повторять голосом Карцева). Я-то не знаю, вдруг, начиная с какого-то размера будет заметная деградация
с большой долей уверенности могу сказать, что какой бы буфер не послали, ваша же система сразу нарежет его пакетами = MTU, то есть по 1514 байт и будет фигачить в кабель такими пакетами.

поэтому пропускная способность линка выходит на пиковое значение в диапазоне 1300-1500 байт на пакет. Если вы начинаете повышать сайз, то сразу попадает на фрагментацию (нарезка по 1500б), а это тоже время и задержки
avatar
Андрей К, вызовы сокетов не нарезают пакеты, лишь копируют во внутренний буфер сокета/ОС, дальше идет вниз по сетевому стеку и прерываниям железки, где уже поток байт сокета превращается в пакеты. Оптимально закидывать по свободному размеру буфера сокета, так как системный вызов — тоже действие затратное.
avatar
vlad1024, так это… когда идет вниз, там и нарезается ) либо в в ОС, либо если сетевуха нормальная не дешевая, то нарезает она на уровне TCP
avatar
vlad1024, понимаю, потому и решил протестировать при заметной сетевой задержке.
Они бьются на пакеты, и идут по проводам/оптике, через маршрутизаторы, чем длиннее этот путь, тем больше задержки и меньше пропускная способность

Тут, видимо, у нас разночтение что именно тестировалось (пропускная способность чего).  Я не сам канал тестировал, а сколько программный сервер может протолкнуть данных при заданной латенси и параметрах (размер/количество буферов). Условно говоря, толку от того, что у меня гигабитная сеть, если я сконфигурирую параметры неудачно и сервер будет пыхтеть с практическим потолком пару килобайт в секунду
Дед Нечипор, а вы уверены что WRIO дает какие либо значимые улучшения, по сравнению с обычными сокетами? )
avatar
vlad1024, смартлаб что-то чудит с порядком в дереве комментариев, ответ — в многословном комментарии
а вы уверены что WRIO дает какие либо значимые улучшения, по сравнению с обычными сокетами? )
Дед Нечипор, 

Т.е. Вы хотите сказать, что существующие решения (напр. небезизвестная Гидра stocksharp.ru/store/%D1%81%D0%BA%D0%B0%D1%87%D0%B8%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-%D0%BC%D0%B0%D1%80%D0%BA%D0%B5%D1%82-%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85/)
настолько плохи (лично я разное про это слышал), что нужно свое делать с нуля?
avatar
Synthetic, так мне же не нужно на все случаи жизни, только под свои задачи. Основное преимущество своего — ты полностью ориентируешься в во всем и в состоянии с минимальными затратами допилить/исправить.
Тогда надо было и Windows Server с нуля переписать. Под свои задачи.

avatar
в tcp еще много секретов ) временами они мне все снятся ) удачи в посвящении
avatar
Мне кажется, это тот случай, когда из алготрейдинга «убегают в серверостроителей/программистов». Такое часто бывает, вместо того, чтобы допиливать системы, погружаются в «рисование красивых кнопочек». Сам такое проходил. Хотя красивые и кликабельные кнопки конечно тоже важны :)Имхо стандартные слишком убогие. Но не влияют на результаты торговли.
avatar
Anest, Переключение на какое-то время на совершенно другие задачи здорово помогает. Потом с новыми силами и новыми надеждами снова начинаешь вгрызаться в породу в попытках откопать крупицу золота.
Еще часто бывает на серверах начального уровня сетевые карты. Нормальная карта будет стоить 30к и выше. Если брать intel или что-то из похожего, то задержки могут уйти. Не один раз с таким сталкивался
avatar

теги блога Дед Нечипор

....все тэги



UPDONW
Новый дизайн