Исходный код
В современном алгоритмическом трейдинге разделение труда критично: Python идеально подходит для анализа рынка, машинного обучения и генерации сигналов, тогда как C++ незаменим для сверхбыстрого исполнения ордеров и контроля рисков. Чтобы связать эти две среды с минимальной задержкой, стандартные REST API или тяжелые брокеры сообщений (RabbitMQ, Kafka) не подходят из-за высокого оверхеда. Оптимальный выбор — библиотека ZeroMQ (ZMQ).
Для генерации качественных сигналов аналитики часто используют исторические данные, которые можно получить, изучив руководство Как извлечь исторические данные стакана L2 с Tardis.dev в Python pandas, или обрабатывают события в реальном времени, например, настраивая отслеживание ликвидаций на Binance Futures через WebSocket на Python.
Ниже представлен рабочий пример реализации связки: Python-скрипт отправляет торговый сигнал (PUB), а C++ приложение мгновенно принимает его (SUB) для последующего исполнения.
# python_publisher.py
import zmq
import time
import json
def main():
# Инициализация контекста ZMQ
context = zmq.Context()
# Создаем сокет типа PUB (Publisher)
publisher = context.socket(zmq.PUB)
# Привязываем сокет к TCP-порту
publisher.bind('tcp://127.0.0.1:5555')
print('Python Publisher запущен на порту 5555...')
while True:
# Имитируем генерацию торгового сигнала
signal = {
'symbol': 'BTCUSDT',
'side': 'BUY',
'price': 65200.5,
'qty': 0.1,
'timestamp_ns': time.time_ns()
}
# Формируем сообщение с топиком для фильтрации на стороне подписчика
message = 'TRADE_SIGNAL ' + json.dumps(signal)
publisher.send_string(message)
print(f'Отправлен сигнал: {message}')
time.sleep(1)
if __name__ == '__main__':
main() А вот код высокопроизводительного подписчика на C++, использующего официальный заголовочный файл cppzmq:
// cpp_subscriber.cpp
#include
#include
#include
#include
int main() {
// Инициализация контекста ZMQ (1 рабочий поток)
zmq::context_t context(1);
// Создаем сокет типа SUB (Subscriber)
zmq::socket_t subscriber(context, zmq::socket_type::sub);
// Подключаемся к адресу публикации
subscriber.connect("tcp://127.0.0.1:5555");
// Подписываемся только на сообщения с префиксом "TRADE_SIGNAL"
subscriber.set(zmq::sockopt::subscribe, "TRADE_SIGNAL");
std::cout << "C++ Subscriber запущен и ожидает сигналы..." << std::endl;
while (true) {
zmq::message_t message;
// Блокирующее ожидание сообщения
auto result = subscriber.recv(message, zmq::recv_flags::none);
if (result) {
std::string raw_msg(static_cast(message.data()), message.size());
// Извлекаем топик и JSON-тело
size_t space_pos = raw_msg.find(' ');
if (space_pos != std::string::npos) {
std::string topic = raw_msg.substr(0, space_pos);
std::string payload = raw_msg.substr(space_pos + 1);
auto now = std::chrono::high_resolution_clock::now();
auto epoch = now.time_since_epoch();
uint64_t receive_time = std::chrono::duration_cast(epoch).count();
std::cout << "[" << topic << "] Получено тело: " << payload << std::endl;
std::cout << "Время получения (наносекунды): " << receive_time << std::endl;
}
}
}
return 0;
} Разбор параметров
zmq.PUB/zmq::socket_type::sub: Паттерн Издатель-Подписчик (PUB/SUB). Позволяет транслировать сигналы неограниченному числу исполнителей без блокировки отправителя.tcp://127.0.0.1:5555: Протокол TCP обеспечивает гарантированную доставку пакетов. Для межпроцессного взаимодействия (IPC) на одной машине можно использоватьipc:///tmp/feeds/0, что снизит задержки еще сильнее.zmq::sockopt::subscribe: Опция фильтрации сообщений на стороне подписчика. C++ исполнитель будет игнорировать любые сообщения, не начинающиеся с префиксаTRADE_SIGNAL, экономя ресурсы CPU.time.time_ns(): Использование наносекундных таймстампов позволяет точно измерять задержку (latency) передачи данных между Python и C++.
Как запустить
Для запуска решения вам понадобятся установленные библиотеки ZeroMQ для обоих языков.
1. Установите Python-зависимости:
pip install pyzmq 2. Установите C++ библиотеку libzmq и заголовочные файлы cppzmq. На Ubuntu/Debian это делается командой:
sudo apt-get install libzmq3-dev cppzmq-headers 3. Скомпилируйте C++ код:
g++ -O3 cpp_subscriber.cpp -o cpp_subscriber -lzmq 4. Запустите C++ исполнитель в одном терминале:
./cpp_subscriber 5. Запустите Python-анализатор во втором терминале:
python python_publisher.py После запуска вы увидите мгновенную передачу сигналов. При интеграции в реальный продакшн не забудьте настроить систему риск-менеджмента на стороне C++ исполнителя, например, внедрив защитные механизмы, аналогичные описанным в статье Circuit Breaker на Python: Защита Торгового Бота от Flash Crash.




