Архитектура алгоритмической торговой системы
31.05.2026 · R. B. Atai
Алгоритмическая торговая система кажется набором отдельных модулей: загрузка данных, стратегия, бэктест, исполнение, риск-менеджмент, логи, мониторинг. Но в реальной эксплуатации важнее не список компонентов, а границы между ними. Именно на этих границах чаще всего ломается связь между красивым исследованием и реальным рынком.
Одна и та же идея проходит несколько сред: research, backtest, paper trading и production. Если в каждой среде используются разные данные, разные правила исполнения и разные проверки риска, то система тестирует одну стратегию, а торгует другую. Архитектура нужна не ради схемы, а ради воспроизводимости: чтобы сигнал, расчёт позиции, проверка лимитов и отправка ордера сохраняли один смысл на всём пути от гипотезы до живого капитала.
Хорошая торговая архитектура поэтому похожа не на "умную модель", а на инженерный контур с понятными контрактами. Данные должны приходить в проверяемом формате. Стратегия должна генерировать решение, а не сама общаться с биржей. Бэктест должен моделировать ограничения реального исполнения. Execution engine должен знать состояние ордеров, а не просто отправлять HTTP-запросы. Risk management должен стоять до сделки, после сделки и поверх всей системы.
Data ingestion: входной слой рынка
Data ingestion — это не "скачать свечи". Это слой, который превращает внешний рынок в внутренний поток событий: сделки, стакан, candles, funding, статусы инструментов, комиссии, торговые ограничения и, если нужно, новости или корпоративные события.
Главная задача этого слоя — не потерять смысл данных при нормализации. У разных бирж отличаются символы, точность цены и количества, временные метки, типы ордеров, лимиты запросов и правила агрегации. Даже простая свеча может иметь разные границы интервала, разную политику по пустым барам и разное отношение к поздним исправлениям. Если эти различия спрятать слишком рано, стратегия получит аккуратную таблицу, которая уже не соответствует конкретному venue.
Поэтому полезно разделять raw layer и normalized layer. Raw layer хранит исходные сообщения или максимально близкое к ним представление: что пришло, когда пришло, из какого источника, с каким sequence number или update id. Normalized layer приводит данные к внутренней модели: единые symbol ids, timestamps, типы событий, цены, объёмы и статус качества.
Для потоковых данных особенно важны gaps и порядок событий. Документация Coinbase прямо предупреждает, что sequence numbers могут указывать на пропущенные или пришедшие не по порядку сообщения, и потребитель должен уметь восстанавливать корректное состояние. 6 Binance для локального order book описывает отдельную процедуру: сначала WebSocket, затем REST-снапшот, затем применение buffered depth events по update id. 5 Это не техническая мелочь, а часть торговой модели: если стакан собран неправильно, execution и slippage считаются на вымышленной ликвидности.
База данных и хранение
В торговой системе обычно нет одной "базы данных для всего". Есть несколько разных классов хранения, и смешивать их опасно.
Первый класс — market data store. Он нужен для исторических котировок, сделок, стакана, funding, справочников инструментов и всех данных, на которых строится research и backtest. Здесь важны append-only логика, версионирование, контроль дыр, возможность пересобрать свечи из более низкого уровня и понять, на какой версии истории был получен конкретный результат.
Второй класс — operational state. Это ордера, исполнения, позиции, балансы, cash movements, комиссии, ошибки API, состояние риск-лимитов и внутренние события системы. Эти данные нужны не только для отчётов, но и для реконсиляции: совпадает ли представление системы с тем, что видит биржа или брокер.
Третий класс — research artifacts: параметры стратегий, результаты оптимизации, walk-forward окна, отчёты по метрикам, наборы экспериментов. Их нельзя хранить как безымянные CSV "final_v3". Если невозможно связать результат бэктеста с версией данных, кодом стратегии, параметрами и моделью издержек, то результат нельзя воспроизвести. А если результат нельзя воспроизвести, он не должен попадать в production.
Strategy engine
Strategy engine отвечает за превращение данных и состояния в торговое намерение. В хорошей архитектуре стратегия не отправляет ордер напрямую на биржу. Она говорит: при таком состоянии рынка, портфеля и риска я хочу такую экспозицию, такой target position или такой набор заявок.
Это разделение кажется формальным, но оно защищает систему от главной путаницы: сигнал и исполнение — разные задачи. Сигнал отвечает на вопрос "что я хочу сделать". Execution отвечает на вопрос "как это безопасно и реально сделать на конкретной площадке". Если стратегия сама знает API биржи, сама считает лимиты и сама обрабатывает partial fills, её почти невозможно честно перенести из бэктеста в live.
Strategy engine лучше проектировать как детерминированный слой. На одинаковом входе он должен давать одинаковое решение. Если в нём есть случайность, она должна быть явно зафиксирована seed, версией модели или состоянием. Если используются ML-модели, рядом нужны версия признаков, версия модели, время обучения и запрет на данные, которые в момент решения ещё не были доступны.
Практический контракт прост: стратегия получает только те данные, которые были бы доступны в тот момент времени, и не знает, будет ли её решение исполнено в backtest, paper trading или production. Тогда один и тот же strategy engine можно проверять в разных средах, не переписывая саму логику.
Backtesting engine
Backtesting engine нужен не для того, чтобы показать красивую equity curve, а чтобы проверить гипотезу в условиях, максимально близких к будущему исполнению. Чем больше допущений спрятано внутри бэктеста, тем выше риск, что система оптимизируется под симулятор, а не под рынок.
Первое требование — отсутствие look-ahead bias. Стратегия не должна видеть будущий close, поздние исправления данных, состав universe, который известен только сегодня, или corporate actions, применённые так, будто они были известны заранее. Второе требование — честная модель издержек: комиссия, spread, slippage, funding, borrow cost, market impact и ограничения ликвидности. Третье — правильная событийная последовательность: сигнал, проверка лимитов, размещение ордера, исполнение, обновление позиции, запись результата.
Vectorized backtest удобен для исследования, но часто плохо моделирует очередь событий. Event-driven backtest медленнее, зато ближе к production: он заставляет стратегию жить в том же порядке событий, в котором она будет торговать. Для среднесрочных стратегий vectorized подход может быть достаточным, но для intraday, order book и execution-sensitive систем без событийной модели легко получить результат, который не переживает первого запуска на реальной бирже.
Отдельная проблема — переоптимизация. Bailey, Borwein, López de Prado и Zhu описывают backtest overfitting как ситуацию, когда стратегия выбирается по исторической симуляции и затем деградирует вне выборки; они предлагают оценивать вероятность переобучения через специальные процедуры cross-validation для инвестиционных бэктестов. 7 Архитектурный вывод здесь простой: backtesting engine должен хранить не только "лучший результат", но и след экспериментов, чтобы было видно, сколько вариантов было перебрано до красивой кривой.
Execution engine
Execution engine — это слой, который превращает торговое намерение в реальные ордера. Он работает в гораздо более грязном мире, чем strategy engine: задержки, повторные запросы, частичные исполнения, отмены, reject-сообщения, rate limits, рассинхронизация позиции, разные типы ордеров и разные состояния одной и той же заявки на стороне биржи.
Минимальный execution engine должен уметь вести жизненный цикл ордера: created, submitted, acknowledged, partially filled, filled, cancelled, rejected, expired. Ему нужна идемпотентность: повтор запроса после таймаута не должен случайно открыть двойную позицию. Ему нужна реконсиляция: если система думает, что ордер отменён, а биржа показывает fill, приоритет должен быть у внешнего источника истины.
Для институционального рынка стандартной границей часто выступает FIX. FIX Trading Community описывает FIX Protocol как глобальный открытый стандарт для обмена торговой информацией: ордерами, исполнениями и market data, независимый от конкретного транспорта. 3 В криптоинфраструктуре чаще встречаются REST и WebSocket API конкретной площадки, но инженерная задача та же: отделить внутреннюю модель ордера от внешнего протокола.
Хорошая практика — строить execution через адаптеры. Внутри системы есть единый OrderIntent, OrderState, Fill, Position. Снаружи есть Binance, Coinbase, брокерский FIX gateway или sandbox. Тогда стратегия и риск-слой не переписываются под каждую площадку, а различия venue остаются в адаптере исполнения.
APIs бирж как внешняя граница
Биржевой API — это не просто транспорт. Это внешняя граница системы, где появляются authentication, rate limits, лимиты по числу WebSocket-подписок, правила heartbeat, задержки, maintenance windows, разные форматы ошибок и внезапные изменения поведения.
Документация Binance, например, разделяет REST market data endpoints и WebSocket streams, указывает лимиты входящих сообщений, ping/pong-логику и порядок восстановления локального стакана. 4 Coinbase отдельно описывает production и sandbox endpoints, каналы подписки, heartbeat, sequence numbers и необходимость обработки gaps. 6 Эти детали напрямую влияют на архитектуру: ingestion должен уметь восстанавливаться, execution должен различать reject и timeout, monitoring должен видеть потерю heartbeat раньше, чем стратегия начнёт принимать решения на устаревших данных.
Фрагментация особенно заметна в крипте. Одна и та же пара на разных venues имеет разные комиссии, глубину, tick size, min order size, скорость обновления и режимы остановки торгов. Поэтому слой API не должен протекать внутрь стратегии. Стратегия может знать, что она работает с инструментом и доступной ликвидностью; но конкретные правила LOT_SIZE, подпись запроса или формат cancel response должны жить ниже.
Risk management как сквозной контур
Risk management нельзя делать последним модулем в конце пайплайна. В торговой системе риск должен быть сквозным контуром: до сделки, во время исполнения, после сделки и на уровне всей системы.
Pre-trade risk checks отвечают на вопросы: не превышает ли ордер лимит размера, не нарушает ли он max position, хватает ли баланса или margin, не превышен ли дневной loss limit, не выключен ли инструмент, не устарели ли данные, не потеряна ли связь с биржей. Post-trade checks проверяют фактическую позицию, PnL, комиссии, exposure, концентрацию и отклонение от ожидаемого состояния.
Регуляторная логика давно формализует такие требования. ESMA в guidelines по automated trading требует от investment firms эффективных систем и контролей, включая pre-trade и post-trade controls, тестирование алгоритмов, управление доступом и процедуры на случай сбоев. 1 SEC Rule 15c3-5 требует от broker-dealers с market access поддерживать систему риск-контролей и supervisory procedures, чтобы ограничивать финансовые и регуляторные риски market access. 2
Для приложения вроде ai-trader практический вывод не в том, чтобы имитировать регуляторный документ, а в том, что риск-слой должен быть обязательной частью пути ордера: сигнал не становится заявкой, пока не прошёл лимиты, а превышение drawdown, рассинхронизация позиции или потеря market data должны уметь остановить торговлю без участия человека.
Logging
Logging в торговой системе — это не поток сообщений "что-то произошло". Это audit trail, по которому можно восстановить, почему система приняла решение, какой вход она видела, какой риск-чек прошла заявка, что было отправлено на биржу и какой ответ пришёл обратно.
Логи должны связывать события сквозными идентификаторами: signal id, decision id, order id, exchange order id, fill id, strategy version, data version. Без такой связи расследование превращается в ручной поиск по времени, а время в торговых системах часто неидеально: разные сервисы могут иметь разные clocks, а события могут приходить не в том порядке, в котором были созданы.
Важно логировать не только ошибки. Успешные решения тоже нужны: почему стратегия не вошла, почему риск-слой отклонил ордер, почему execution выбрал limit вместо market, почему позиция была уменьшена. Отсутствие сделки иногда важнее самой сделки, особенно при сравнении live-результата с backtest.
При этом logging не должен становиться новым источником риска. В логах не место секретам API, приватным ключам и полным authentication payloads. Для production нужны уровни логирования, маскирование чувствительных полей, отдельное хранение audit-событий и понятная политика retention.
Monitoring
Monitoring отвечает не на вопрос "что случилось в логах", а на вопрос "работает ли система сейчас в допустимом режиме". Это разница между историческим расследованием и оперативным управлением.
В SRE-практике мониторинг строится вокруг симптомов, которые видит пользователь или система, а не только вокруг внутренних причин; Google SRE Book отдельно подчёркивает важность метрик, алертов и сигналов, которые отражают фактическое состояние сервиса. 8 Для торговой системы такими симптомами становятся freshness market data, latency ingestion-to-signal, latency signal-to-order, доля reject, расхождение локальной и биржевой позиции, ошибки реконсиляции, stale orders, heartbeat, drawdown, exposure и live-vs-backtest drift.
Плохой мониторинг сообщает "API вернул ошибку". Хороший мониторинг сообщает "стратегия продолжает принимать решения, но market data по инструменту не обновлялись 40 секунд" или "локальная позиция отличается от биржевой после последнего fill". В первом случае это просто событие. Во втором — состояние, при котором система должна деградировать, остановиться или перейти в safe mode.
Особенно важны алерты на молчание. Если сервис упал громко, его легче заметить. Если WebSocket перестал присылать обновления, но процесс жив и стратегия продолжает читать старый state, ошибка выглядит как нормальная работа. Поэтому monitoring должен смотреть не только на exceptions, но и на свежесть данных, скорость событий и инварианты состояния.
Paper trading и production: один код, разные контуры
Paper trading полезен только тогда, когда он проверяет тот же путь, который пойдёт в production. Если paper environment — это отдельная упрощённая реализация, где ордера "исполняются" сразу по последней цене, он проверяет скорее интерфейс, чем торговую систему.
Правильнее держать один путь сигнала: data ingestion, strategy engine, risk checks, order intent, execution adapter, order state, fills, positions, logs, monitoring. Разница между paper и production должна быть в адаптере исполнения и источнике подтверждений. В paper adapter fill симулируется по заданной модели. В production adapter fill приходит от биржи или брокера. Остальная система должна видеть одинаковые типы событий.
Такой подход позволяет делать staged rollout. Сначала стратегия проходит historical backtest. Потом paper trading на live data проверяет свежесть данных, порядок событий, риск-лимиты и operational behavior. Затем можно включать минимальный размер позиции, ограниченный universe, более жёсткие лимиты, усиленный monitoring. Production trading — это не один большой переключатель, а постепенное снятие ограничений по мере того, как система доказывает, что её live-поведение похоже на ожидаемое.
Даже здесь paper trading не является доказательством прибыльности. Он не воспроизводит полную очередь заявок, market impact и стресс ликвидности. Его задача скромнее и полезнее: проверить, что торговый контур не расходится с реальностью ещё до того, как ошибка начинает стоить денег.
Итог
Архитектура алгоритмической торговой системы начинается не с выбора фреймворка и не с модели сигнала. Она начинается с вопроса: сможет ли одна и та же логика пройти путь от данных к ордеру без подмены смысла.
Data ingestion отвечает за то, чтобы рынок был представлен честно. Хранилище отвечает за воспроизводимость. Strategy engine отделяет идею от исполнения. Backtesting engine проверяет гипотезу с учётом реальных ограничений. Execution engine ведёт жизненный цикл ордеров. Exchange adapters изолируют хаос внешних API. Risk management ограничивает ущерб до того, как он стал необратимым. Logging даёт память, monitoring — оперативное зрение. Paper trading связывает исследование и production без прыжка вслепую.
Сильная система не обязана быть сложной. Но она должна иметь ясные границы, проверяемые инварианты и один путь принятия решений. Иначе стратегия может выглядеть работающей в исследовании, но в реальности торговать уже не рынок, а набор архитектурных допущений.