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

Я использовал язык программирования 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 и его продуктивности, читабельности и простоте модификаций.

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

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

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

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

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

@Siemargl
18.12.2021 14:54 UTC
Первоисточник

Комментарии

@MAXH0
18.12.2021 12:01 UTC
+14

Статья очень сильно напоминает многие введения к переведенным книгам "Как я добился успеха используя X (икс)". Самое бесячье в таких статьях то, описывается конкретный кейс, где это решение зашло, но не демонстрируется код и не сравниваются альтернативы. Т.е. статью явно бы украсили сровнение кодов C++ vs. D и их эффективности с выразительностью.

@Siemargl
18.12.2021 20:04 UTC
+1

Ну я не стал переводить все комменты, в т.ч тот, где написано, что код закрыт в рамках стартапа (который сдох ибо не наняли проф.трейдера=)

Но в целом для меня это очевидно, ибо языки с llvm бекендом при адекватной реализации фронта - плюс минус близки по итоговой скорости.

@
18.12.2021 12:45 UTC
0
НЛО прилетело и опубликовало эту надпись здесь
@bfDeveloper
18.12.2021 15:53 UTC
+1

И да, и нет. Для хороших трейсов на C++ backtrace_symbols  совершенно недостаточен. То есть что-то вполне читаемое он выведет, но если сравните это с стеком из gdb, то удивитесь, насколько лучше бывает. backtrace_symbols  содержит только символы, поэтому все неэкспортируемые функции, внезапно, лямбды оказываются совершенно неинформативными. Опять же нет номеров строк.

Поэтому для хорошего стека приходится тащить libdwarf и по дебажной информации восстанваливать качественнее. Но да, начинается всё с банального backtrace.

19.12.2021 09:39 UTC
0
НЛО прилетело и опубликовало эту надпись здесь
@Siemargl
18.12.2021 20:14 UTC
0

Смысл в неявной декодировке структуры компилятором.

import std.stdio;

struct StrX {
    int x;
    char [10] text;
    double z;
}

int main() 
{
    StrX sx = {7, " fx", 3.6};
    writeln(sx);
    return 0;
}

Вывод StrX(7, " fx\0\0\0\0\0\0\0", 3.6)

По-моему, это мелкая но удачная ф-циональность, сглаживающая границы между интерпретируемыми и нативными языками.

Но смысл немного глубже, это не магия компилятора, а доступно и для юзера.

@mrbald
19.12.2021 08:28 UTC
+1

Понятно теперь, почему чел работу в марте поменял :-D

@vgogolin
19.12.2021 23:51 UTC
+2
  1. HFT при том, что данные только от BATS...

  2. Кастомное решение, которое должно было помочь "профи", заработать деньги, но он не нашелся?..

  3. Учитывая стоимость данных BATS, наличие только одного разработчика на проекте...

    Больше вопросов, чем ответов.

@Siemargl
20.12.2021 05:52 UTC
0

the system ran in production in 2019 till Mars 2020, when I was working with a startup. unfortunately they didn’t have winning strategy, even the system was running perfectly, with a very low latency.
they didn’t hire a professional trader to get the best of the system, so I left that startup, as they didn’t fulfill a lot of promises.

Стартап, хотели профи заменить программой, но не осилили разработать выигрышную стратегию.

20.12.2021 06:06 UTC
0

Не заменить - нет. В HFT системах трейдер и система нужны дпуг другу. Трейдер должен реагировать на макро сигналы и выставлять параметры от которых "пляшет" система высокочастотной торговли.

@v_sapronov
20.12.2021 06:04 UTC
0

Работал над AMM системой и системоц алгоритмической торговли в двух инвест банках.

Попробую ответить:

  1. Далеко не обязательно подключать сразу все источники данных. Многие стратегии можно и нужно делать на одной бирже. В HFT на колоцированных серверах получать данные других бирж не имеет смысла в масштабах микросекунд - просто они будут всегда "опоздавшие" относительно биржи, где стоит сервер.

  2. "Профи" - это тот кто умеет правильно управлять сигналами и писать их анализ для HFT. Такой трейдер умеющий делать стратегии внутри миллисекунды. Это редкий скилл, если не удача...

  3. Часто данные покупают в любом случае для всей организации. Проектов у организации может быть много. Цена коллокации (необходимой для HFT) обычно дороже, чем сами данные.

@kantocoder
22.12.2021 00:40 UTC
+1

Судя по пунктам 1-4, это не HFT, а просто система для алготорговли. Такая усложненная архитектура приведет к непозволительным задержкам. Кстати, п. 4. избыточен, Signal Generator можно выкинуть -- по-сути, автор сморозил хрень, видимо чтобы ввести нас в заблуждение.

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