За то, чем вы не пользуетесь, вы не платите. И более того: то, чем вы пользуетесь, вы не написали бы вручную лучше.
Два контура одной платформы
В современном алготрейдинге преимущество в 500 наносекунд повышает вероятность исполнить лимитный ордер первым до 75%. При таких скоростях выбор языка и архитектурных шаблонов определяет выживание фонда.
Главная ошибка начинающих — попытка написать торговую систему на «одном универсальном языке».
В реальных квантовых фондах стек строго разделён на два изолированных мира:
- Offline-контур (Исследования и ML): Здесь правит Python. Главная метрика — скорость проверки гипотез, гибкость и мощь математических библиотек.
- Online-контур (Горячий путь / Production Execution): Здесь правит современный C++ (C++20/23) или аппаратные чипы FPGA. Главная метрика — наносекундный детерминизм, предсказуемость задержки (zero jitter) и полный контроль над памятью.
1. Python, C++ и SQL
Python — стек исследователя
Сам по себе CPython медлителен из-за динамической типизации и Global Interpreter Lock (GIL). Однако в количественных финансах Python выступает в роли дирижера: тяжёлые вычисления делегируются скомпилированным C/C++ и Fortran ядрам.
- Эволюция от Pandas к Polars: Классический Pandas дублирует данные в оперативной памяти (размер датафрейма в RAM превышает CSV-файл в 3–5 раз) и вычисляет все в один поток.
Современные квант-команды переходят на Polars (написанный на Rust):- Apache Arrow: Плоская колоночная память без накладных расходов на сериализацию.
- Ленивые вычисления (Lazy Evaluation): Построение графа запроса (DAG) с автоматическим отсечением неиспользуемых колонок на этапе чтения с диска.
- Параллелизм: Автоматическое распараллеливание операций по всем ядрам CPU.
import polars as pl
# Ленивый расчёт дисбаланса стакана (Order Book Imbalance) на петабайтах тиков
imbalance_df = (
pl.scan_parquet("ticks_l2_*.parquet")
.filter(pl.col("symbol") == "Si-9.26")
.select([
pl.col("timestamp"),
(pl.col("bid_vol_0") - pl.col("ask_vol_0")) /
(pl.col("bid_vol_0") + pl.col("ask_vol_0")).alias("obi_level_0")
])
.collect() # Исполнение оптимизированного плана запроса
)
- Машинное обучение:
- Табличные данные: Доминируют бустинги LightGBM и CatBoost. Они устойчивы к мультиколлинеарности и обучаются за минуты.
- Сверхплотные тики L2/L3: PyTorch. Используются одномерные сверточные сети (1D-CNN) и трансформеры с причинным маскированием (Causal Attention) для исключения утечек из будущего.
- Бэктестинг: Vectorbt (векторизованный прогон сотен тысяч траекторий через Numba за секунды) и NautilusTrader (событийно-ориентированная симуляция очередей в стакане).
C++ — стек разработчика
В горячем пути исполнения ордеров (Tick-to-Trade Hot PathTick-to-Tradet_out − t_inВремя от прихода рыночного события до выхода встречной заявки на провод. Ключевая метрика горячего пути; в топовых системах измеряется сотнями наносекунд.Подробнее →) C++ незаменим благодаря детерминированному управлению ресурсами и отсутствию непредсказуемых пауз сборщика мусора.
- Принцип Zero-Allocation: Любой вызов
mallocилиnewв цикле обработки тика — это катастрофа. Системный аллокатор обращается к глобальной куче и блокирует поток (heap contention). Кванты используют статические Memory Pools и кольцевые буферы:
// ПАТТЕРН ZERO-ALLOCATION НА C++20
#include <array>
#include <cstdint>
struct MarketTick {
uint64_t timestamp_ns;
int64_t price_fixed; // Фиксированная точка
uint32_t volume;
};
class FastTickBuffer {
private:
static constexpr size_t CAPACITY = 65536;
alignas(64) std::array<MarketTick, CAPACITY> ring_buffer_; // Выравнивание по кэш-линии
size_t head_{0};
public:
void push(const MarketTick& tick) noexcept {
ring_buffer_[head_ & (CAPACITY - 1)] = tick; // Битовая маска вместо деления с остатком
++head_;
}
};
- Оптимизация под кэш процессора:
- Cache Lines (64 байта) и False Sharing: Если два ядра CPU одновременно меняют разные переменные, лежащие на одной 64-байтной кэш-линии, процессор постоянно сбрасывает кэши по протоколу MESI. Решение — директива выравнивания
alignas(64)в C++17. - Branch Prediction: Атрибуты
[[likely]]и[[unlikely]]в C++20 подсказывают компилятору порядок ассемблерных инструкций для предотвращения сброса конвейера CPU.
- Cache Lines (64 байта) и False Sharing: Если два ядра CPU одновременно меняют разные переменные, лежащие на одной 64-байтной кэш-линии, процессор постоянно сбрасывает кэши по протоколу MESI. Решение — директива выравнивания
- Kernel Bypass (Сетевой обход ядра): Стандартный сетевой стек Linux вносит микросекундные задержки из-за переключения контекста и копирования пакетов. Технологии Solarflare Onload и DPDK пробрасывают сетевую карту напрямую в память приложения в userspace, снижая задержку до сотен наносекунд.
- Библиотеки финансовой математики: QuantLib (оценка опционов и процентных кривых), Eigen (векторизованная линейная алгебра на шаблонах выражений).
SQL и базы временных рядов
Почему классический PostgreSQL падает на тиковых данных?
PostgreSQL хранит данные построчно. Чтобы посчитать средневзвешенную цену (VWAP) по миллиарду сделок за месяц, построчная база прочитает с диска гигабайты ненужных колонок (ID сделок, направления, типы ордеров), уперевшись в дисковый ввод-вывод.
- ClickHouse: Колоночный король исторических квантовых данных. Каждая колонка хранится отдельно и сжимается специализированными алгоритмами (DoubleDelta, Gorilla). Запросы исполняются на векторных SIMD-инструкциях CPU.
- kdb+/q (Kx Systems): Легендарный стандарт Уолл-стрит. Построен на векторном языке
qи держит всю тиковую историю в оперативной памяти (In-Memory RAM), выполняя выборки за микросекунды.
2. Альтернативные языки: OCaml, Java, Rust и FPGA
| Технология | Где применяется | Главное преимущество | В чем подвох |
|---|---|---|---|
| OCaml | Вся инфраструктура Jane Street | Строгая система типов, pattern matching, отсутствие runtime-крашей | Skill lock-in: за пределами Jane Street стек почти не востребован |
| Java (JVM) | Гриды данных в Two Sigma | Стабильный распределённый кластер в облаке (GCP, Spark) | Требуется ZGC-тюнинг и GC-free структуры во избежание пауз |
| Rust | Крипто-алготрейдинг, новые фонды | Безопасность памяти без GC (Borrow Checker) на скорости C++ | Огромное наследие C++ библиотек на биржах трудно заменить |
| FPGA (Verilog) | HFT-лидеры (Jump, HRT) | Наносекундная обработка на кремнии: сетевой пакет не доходит до CPU | Медленный цикл разработки и высокая стоимость плат |
3. Чем стек исследователя отличается от стека разработчика
| Критерий | Quantitative Researcher (QR) | Quantitative Developer (QD) |
|---|---|---|
| Главная цель | Поиск альфа-сигналов и математических закономерностей | Построение торгового ядра, минимальная задержка и аптайм |
| Основной язык | Python, R, SQL | C++ (17/20/23), Rust |
| Библиотеки | Polars, PyTorch, LightGBM, Vectorbt, SciPy | Boost, Eigen, QuantLib, DPDK, Solarflare Onload |
| Метрика качества кода | Скорость проверки гипотезы: за сколько часов идея превращается в бэктест | Latency & Jitter: 99-й перцентиль задержки исполнения в наносекундах |
| Среда разработки | Jupyter Notebooks, VS Code | CLion, Linux Terminal, Vim, GDB |
| Инструменты профилирования | cProfile, TensorBoard | Perf, Valgrind, AddressSanitizer, Google Benchmark |
4. Три смертных греха программирования в финансах
Грех 1. Выделение памяти на куче (new / malloc) в горячем пути
Попытка создать временный объект через std::make_shared или new во время прихода тика приводит к тому, что системный аллокатор блокирует память.
Результат: Задержка обработки ордера взлетает со 100 наносекунд до нескольких миллисекунд. Вы опаздываете в стакан и покупаете по худшей цене.
Грех 2. Использование типов float для денежных расчётов
Числа с плавающей точкой стандарта IEEE 754 не могут точно представить десятичные дроби (например, 0.01 рубля). На миллионах сделок накапливается ошибка округления, из-за которой балансы перестают сходиться, а риск-лимиты сбоят.
Правило: Всегда использовать Fixed-Point арифметику (целочисленные типы int64_t с масштабированием, где 100.25 ₽ хранится как 100250000).
Грех 3. Lookahead Bias (Утечка будущего) в Python
Случайное применение информации из будущего при расчёте скользящих средних (shift(-1) вместо shift(1)) или нормализация всего датасета по глобальному среднему.
Результат: Бэктест показывает нереалистичный коэффициент Шарпа 6.0, а в продакшене алгоритм мгновенно теряет депозит.
5. Золотая полка квант-разработчика
- Scott Meyers — «Effective Modern C++»: Глубинное понимание move-семантики, perfect forwarding и умных указателей.
- Anthony Williams — «C++ Concurrency in Action»: Библия многопоточного программирования: lock-free структуры, атомики и барьеры памяти.
- Fedor Pikus — «The Art of Writing Efficient C++»: Низкоуровневая оптимизация под архитектуру CPU: кэши L1/L2/L3, выравнивание памяти и устранение False Sharing.
- Marcos López de Prado — «Advances in Financial Machine Learning»: Построение информационных баров и очищенная валидация CPCV.
- Python исследует, C++ исполняет: Попытка написать быстрый торговый шлюз на Python или проверять ML-гипотезы на сыром C++ одинаково бесперспективна.
- Polars побеждает Pandas: Колоночная память Apache Arrow, многопоточность и оптимизатор ленивых запросов делают Polars новым стандартом для квантов.
- Zero-allocation — закон HFT: Никаких аллокаций памяти и вызовов операционной системы в горячем цикле обработки тиков.
- Fixed-Point вместо Float: Деньги и биржевые котировки в коде должны храниться строго в целочисленных типах с фиксированным масштабным коэффициентом.
Источники
- [1] Foundations of C++ Формулировка принципа нулевых накладных расходов из эпиграфа, в авторской редакции.
- [2] Advances in Financial Machine Learning Источник по утечке будущего (lookahead bias), переобучению бэктестов и правильной кросс-валидации временных рядов.
- [3] Quantitative Trading: How to Build Your Own Algorithmic Trading Business, 2-е издание Практика построения исследовательского контура и инфраструктуры бэктеста.
- [4] Документация срочного рынка: TWIME, FAST/UDP, Plaza-2 Протоколы, с которыми реально работает исполнительный контур на российском рынке.
Ссылки сверены 4 сентября 2026
Проверьте себя
10 вопросов по материалу статьи.
Для прохождения — 10 из 10.