Pull to refresh

Как я написал платформу для высокочастотного трейдинга на D

Reading time5 min
Views13K
Original author: Georges Toutoungis

Я использовал язык программирования D для реализации платформы высокочастотного трейдинга (HFT). Я был вполне удовлетворен полученным опытом и решил поделиться тем, как я пришел к этому. Этот путь был тернист.


В 2008 году на Amazon я наткнулся на книгу под названием "Learn to Tango with D". Это вызвало у меня любопытство, и я решил изучить D подробнее. Это привело меня к Digital Mars и Уолтеру Брайту. Впервые я услышал об Уолтере, когда узнал о Zortech C++, первом нативном компиляторе C++. Его работа оказала огромное влияние на мой путь изучения C++. Поэтому я сразу же заинтересовался языком только потому, что он его автор, и был рад узнать, что он вместе с Андреем Александреску работает над второй версией. Тем не менее, я решил подождать, пока они продвинутся дальше в работе над новой версией, прежде чем окунуться в проект.

В 2010 году я купил книгу Андрея "The D Programming Language", как только она была опубликована, и начал читать. В то время я работал в BNP Paribas, используя C++ для оптимизации своей HFT-платформы, поэтому высокая производительность доминировала в моих мыслях. Когда я увидел, что классы в D являются ссылочными типами, а их функции по умолчанию виртуальные, я был разочарован. Я не понимал, как это может быть полезно для программирования с низкими задержками (латентностью). В то время я был слишком занят работой, чтобы углубляться в изучение, поэтому я отложил книгу и язык в сторону.

В 2014 году я начал готовиться к новому начинанию. В рамках этого я начал работать над новым фреймворком обработчика входных данных (Feed-Handler) на C++, используя свою собственную давно поддерживаемую библиотеку C++ низкоуровневых компонентов, полезных в высокопроизводительных приложениях с низкими задержками. Книга Андрея снова попалась мне на глаза, и я решил взглянуть на нее еще раз.

На этот раз я дочитал книгу до конца и понял, что мое первоначальное впечатление было ошибочным. Я обнаружил, что мне нравятся возможности метапрограммирования в D и его поддержка программирования в функциональном стиле. К концу книги я был готов дать шанс D.

Я начал с переноса своей библиотеки C++ и обработчика входных данных на D. Это было несложно. В своем коде на C++ я использую очень мало наследования, предпочитая композицию и конкретные классы (Concrete class). Я обнаружил, что довольно продуктивно работаю со структурами, шаблонами и миксинами (mixin) D. При этом я внимательно следил за показателями производительности. Когда оказалось, что D дает такую же производительность, как и мой код на C++, я был куплен с потрохами. Я обнаружил, что D намного элегантнее, чище, читабельнее и проще в поддержке. Я перешел на D и больше не оглядывался назад.

Моей целью было разработать законченную систему HFT с использованием D. Система должна была состоять из различных подсистем:

  1. Feed-Handler Framework: получает рыночные данные от бирж; создает журналы для всех ценных бумаг; публикует обновления для других подсистем.

  2. Strategies Framework: получает обновления рыночных данных от обработчика входных данных п.1; облегчает связь с системой управления заказами п.3; позволяет подключать к ней стратегии, принимающие решения о торговле акциями.

  3. Order Management System: взаимодействует с биржей и системой стратегий п.2; поддерживает базу данных ордеров.

  4. Signal Generator: получает обновления рыночных данных от от обработчиков входных данных п.1; генерирует различные сигналы в виде значений индикаторов, прогнозов цен на акции и т.д.; посылает различные сигналы стратегиям п.2.

В конце концов, я нашел новую структуру данных и наилучший дизайн для моего обработчика входных данных. Я разработал новую версию полностью на D. Эта реализация в существенной степени использует шаблоны. Мне нравится синтаксис шаблонов в D, и в целом я нахожу сообщения об ошибках более понятными, чем сложные сообщения об ошибках, к которым я привык в C++. Мне нужно было опуститься до ассемблера для некоторых специфических инструкций x86, и в D это было легко сделать.

Позже мне понадобилось работать с конфигурационными файлами. Я предпочитаю писать свои файлы конфигурации на Lua, легковесном скриптовом языке, который легко интегрировать в программу в качестве расширения через его C API. Для этого я нашел привязку D Lua под названием DerelictLua. Используя, опять же, средства метапрограммирования D, я разработал очень простой и практичный способ взаимодействия с Lua через DerelictLua. Примечание редактора: с тех пор DerelictLua устарел; новые проекты должны использовать его преемника, bindbc-lua.

Обработчик входных данных на бирже Bats работает с 31 параллельным каналом, поэтому эффективнее использовать многопоточность. Для этого я решил не использовать средства многопоточности, предоставляемые Phobos. Я чувствовал, что мне нужно больше контроля в такой среде с низкой задержкой, особенно возможность привязать каждый поток к определенному ядру. Я предпочел использовать библиотеку pthreads и ее работу с affinity. Благодаря совместимости с C ABI в D это было очень прямолинейно.

Я работаю в FreeBSD. Для своих коммуникационных потребностей я использую функции ядра для очередей и сокетов. Та же функциональность доступна на macOS, моей предпочтительной платформе для разработки. D не помешал мне использовать эти API ни на macOS, ни на FreeBSD. Это было так же просто, как использование функций ядра для очередей из C.

Несколько замечаний о проблемах и ограничениях:

  • Я раз столкнулся с ошибкой компилятора. Я нашел обходной путь, так что это не стало блокирующим фактором. Я смог воспроизвести ее с помощью нескольких строк кода и связался с сообществом D. Они решили проблему и внесли исправление в более позднюю версию компилятора.

  • Я не использовал сборщик мусора (GC) в D. Однако это не является выпадом против D или его GC. В такой системе с низкой задержкой, как эта, даже использование malloc и free может стать дорогостоящим, поэтому я не собираюсь рисковать использовать недетерминированную систему с непредсказуемой задержкой. Вместо этого я использовал свою библиотеку для обработки выделения/деаллокации памяти через списки свободных блоков, с предварительным выделением памяти. Как следствие, я также отказался от использования стандартной библиотеки D.

  • Мне нужно было работать со строками ASCII фиксированного размера, которые не имеют NUL-терминатора, а вместо этого дополнены пробелами в конце. Без стандартной библиотеки мне было проще работать с ними в С-стиле с помощью указателей.

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

Немного пояснений автора из комментариев (прим.ред):

Не использовались ни IDE, ни отладчик.
Я использовал Sublime Text, который имел плагин для D для отступов и подсветки синтаксиса.
Использовал терминал и систему сборки DUB и dmd и ldc2 в качестве компиляторов.
Для такого рода приложений с огромным количеством данных и многопоточностью отладчик может быть полезен, но чаще всего проблемы удается найти с помощью логов.
В D генерировать логи очень просто, достаточно использовать writeln и структуру, и все работает. В C++ вам нужно написать функцию типа dump() вручную.
Время от времени я пробовал использовать lldb в качестве отладчика, но использовал его нечасто, лишь изредка.

Никакой базы данных, так как никакие базы данных не подходят для такого типа приложений с низкой задержкой.

Все необходимые базы данных создаются на месте и находятся в памяти, в основном это хэш-таблицы.

Имеется только асинхронное архивирование сообщений между OMS и биржей, просто на случай, если что-то пойдет не так, мы можем создать требуемое состояние системы и продолжить работу.

Tags:
Hubs:
Total votes 16: ↑12 and ↓4+8
Comments12

Articles