FinTechSep 8, 20268 мин чтения

Предторговые риск-проверки внутри пути заявки

Предторговый рискУправление рискамиТорговая инфраструктураСистема управления заявками
Ошибка загрузки изображения

Лимиты позиций, маржа, fat-finger границы и kill switch обязаны ответить на каждой заявке до того, как она уйдёт с гейтвея. Вот как эти проверки живут внутри пути заявки, а не рядом с ним: какое состояние лежит в памяти, что пересчитывается инкрементально и что происходит после перезапуска. Сначала — ограничения.

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

Это ограничение стоит назвать первым. Риск-проверка, поставленная в путь заявки, — налог на ввод заявок. Инженерный вопрос не в том, как сделать проверку умной, а в том, как сделать её достаточно маленькой, чтобы трейдеры её не чувствовали, и достаточно честной, чтобы она всё же отклоняла то, что обязана отклонить.

Что на самом деле принадлежит пути заявки

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

  • Лимиты позиции и экспозиции — итоговая позиция по инструменту, группе и счёту сравнивается с заданными границами
  • Маржа или покупательная способность — остаётся ли у счёта запас под заявку в текущей маржинальной модели
  • Fat-finger границы — размер заявки, номинал и отклонение цены от опорной, чтобы поймать опечатку раньше площадки
  • Состояние инструмента и счёта — торги остановлены, счёт ограничен, только закрытие, продукт для этого счёта не включён
  • Состояние kill switch — один флаг, который перекрывает всё выше
  • Защита от дублей и самосделок там, где площадка её не даёт

Всё остальное работает рядом с путём, на том же состоянии, не удерживая заявку. Оно определяет лимиты, которые применяет горячий путь, но не стоит между трейдером и площадкой.

  • Портфельная риск-аналитика — прогоны сценариев, стресс-тесты, коррелированная экспозиция по счетам
  • Пересчёт маржинальной модели при смене параметров и любой пересчёт, задевающий всю книгу позиций
  • Надзор и выявление паттернов — им нужна история, которую горячий путь намеренно не держит
  • Отчётность, сверка и всё, что ходит в базу или во внешний сервис
  • Кредитный анализ и оценка контрагента — они по своей природе живут на более медленных часах

Разделяет не категория, а вопрос. В пути: можно ли отправить эту заявку. Рядом с путём: какими должны быть лимиты. Всё, что отвечает на второй вопрос и при этом задерживает заявку, — ошибка проектирования, какой бы важной проверка ни была.

Где живёт состояние позиций и почему база не стоит на пути

Состояние, нужное предторговой проверке, — текущие позиции, рабочие заявки, использованная и доступная маржа, конфигурация лимитов — лежит в памяти того процесса, который принимает решение. Не в кеше перед базой, не за сетевым вызовом. В процессе.

Дело не только в скорости, хотя запрос на порядки дороже поиска в локальном массиве. Дело в корректности. База хранит позицию такой, какой её записали. Риск-проверке нужна позиция с учётом заявок, отправленных мгновение назад и ещё не исполненных, не подтверждённых и не сохранённых. Читая из хранилища, вы проверяете себя против прошлого, которое уже обогнал ваш собственный поток.

На практике это формирует процесс так же, как формируется любой low latency компонент:

  • Один писатель на счёт. Счета шардируются по риск-инстансам, чтобы за состояние счёта никогда не было конкуренции, и на пути заявки не берётся ни одного лока
  • Плоские, заранее выделенные структуры — массивы фиксированного размера с индексацией по id счёта и инструмента, разрешёнными на старте сессии, а не поиск по хешу строк, собираемых на каждую заявку
  • Никаких аллокаций, никакого I/O и никакого блокирующего логирования на пути решения; запись для аудита передаётся в другой поток через очередь
  • Конфигурация, меняющаяся без перезапуска, подменяется целиком, неизменяемым снимком, поэтому проверка никогда не читает наполовину обновлённый лимит

База — это место, где позиция записана. Это не место, где позиция известна.

Инкрементальный пересчёт, а не полный проход

Полный пересчёт экспозиции и маржи счёта обходит каждую позицию и каждую рабочую заявку. Эта стоимость растёт вместе с размером стакана, то есть риск-проверка замедлялась бы ровно для тех клиентов, кто торгует больше всех. Поэтому горячий путь ничего не пересчитывает. Он применяет дельту.

Счёт несёт текущие агрегаты — чистая и валовая экспозиция по инструменту и по группе, использованная маржа, номинал в полёте. Входящая заявка даёт небольшое изменение этих агрегатов, изменённые значения сравниваются с лимитами, и заявка принимается или отклоняется. Работа пропорциональна заявке, а не портфелю.

  • При отправке худший возможный эффект заявки резервируется в агрегатах, поэтому две заявки в полёте не могут обе поместиться в один и тот же остаток запаса
  • При отказе, отмене или истечении резервирование снимается; при исполнении оно заменяется реальным изменением позиции
  • Частичные исполнения меняют обе стороны этого за один шаг — именно там на деле живёт большинство багов такого движка
  • Правила неттинга и группировки разрешаются при загрузке инструмента, а не на каждой заявке, поэтому дельта — это несколько арифметических операций

Полный пересчёт никуда не девается — он идёт по расписанию, при смене параметров маржи и как периодическая самопроверка против инкрементального результата. Он выполняется вне пути, на копии, и его результат либо подменяет текущий, либо поднимается как расхождение. Инкрементальное состояние, тихо уезжающее от истинного, хуже, чем отсутствие проверки, поэтому сравнение не опционально.

На риск-пути, который мы строим, сама предторговая проверка укладывается в <1 ms. Эта цифра описывает решение на состоянии в памяти, а не весь путь заявки от клиента до площадки и обратно.

Kill switch — отдельный путь

Kill switch используется ровно тогда, когда уже что-то не так. Значит, строить его поверх механики, которая сама может быть источником проблемы, нельзя. Это отдельный путь со своими правилами.

  • Это один атомарный флаг, читаемый в начале проверки, до обращения к состоянию позиций, марже и данным инструмента — поэтому он работает, даже когда они устарели, отсутствуют или сломаны
  • Он взводится несколькими независимыми триггерами: действием оператора, автоматическим условием, потерей фида рыночных данных или исполнений, от которого зависит риск-состояние
  • Он отказывает в закрытую. Если риск-процесс не может убедиться, что его состояние валидно, гейтвей ведёт себя так, будто kill switch включён
  • У него есть области действия — вся фирма, один деск, один счёт, одна стратегия — потому что рубильник, умеющий останавливать только всё сразу, применяют слишком поздно
  • Включение — одно действие и одно подтверждение, а не выкатка конфигурации; выключение — осознанное и всегда записывается

Остановить новые заявки — лёгкая половина. Трудная — что kill switch делает с заявками, уже стоящими на площадке: снятие котировок и отмена рабочих заявок должны быть возможны при отключённом пути отправки. Этот путь отмены заслуживает отдельного тестирования, потому что его используют в худший день, а не в обычный.

Перезапуск и как возвращается состояние

Состояние в памяти — производный вид от долговечной записи. Именно это делает перезапуск переживаемым. Каждое событие, меняющее риск-состояние — принятая заявка, снятое резервирование, применённое исполнение, изменённый лимит, включённый kill switch — дописывается в журнал на локальной машине до того, как по нему что-то сделают дальше по цепочке.

  • На старте процесс проигрывает журнал, восстанавливая агрегаты, затем сверяет позиции и рабочие заявки с площадкой и клиринговой drop copy
  • Пока сверка не завершена, счёт к торгам не открыт. Риск-движок, принимающий заявки, пока он ещё разбирается с позицией, — не риск-движок
  • Расхождение между воспроизведённым состоянием и картиной площадки останавливает этот счёт и поднимает алерт; оно никогда не решается тихим предпочтением одной из сторон
  • Горячий резерв читает тот же журнал, поэтому переключение поднимает прогретое состояние вместо холодного реплея, а сам резерв проверяется регулярным переводом в основной режим, а не в теории

Время восстановления тогда зависит от длины журнала и доступности drop copy, а не от размера книги позиций, и режим отказа при любой неизвестности один: не давать счёту торговать.

Чего эта архитектура не даёт

Честные ограничения стоит назвать прямо: именно они решают, подходит ли такая архитектура вообще:

  • Проверка настолько же корректна, насколько корректен фид исполнений. Если drop copy или отчёты об исполнении отстают, экспозиция занижена, и правильная реакция — деградировать до консервативных лимитов или включить kill switch, а не продолжать торговать на устаревшем состоянии
  • По-настоящему неаддитивные портфельные маржинальные модели сопротивляются инкрементальному расчёту. Работает консервативная инкрементальная оценка сверху на пути плюс полная модель вне пути; цена — часть заявок отклоняется, хотя полная модель их бы пропустила
  • Kill switch защищает от вашего собственного потока, а не от рынка. Он не предотвратит гэп или проскальзывание по позициям, которые у вас уже есть
  • Состояние внутри процесса означает, что риск-движок и гейтвей заявок делят общую судьбу. Это покупает задержку и стоит вам возможности масштабировать их по отдельности
  • Шардирование по счетам с единственным писателем усложняет межсчётные лимиты, а проверкам уровня фирмы нужен более медленный слой агрегации со своим отставанием данных
  • Это больше эксплуатационной работы, чем проверка через базу: журналы, сверка, учения по переводу резерва в основной режим. Если ввод заявок не чувствителен к задержке, такая сложность не окупается

amBrain строит такие предторговые риск-пути для брокеров и проп-фирм, с горячими путями на Rust. Команда работает над торговой инфраструктурой из Еревана, Армения, с 2019 года.

Нужна помощь с реализацией?

Наша инженерная команда специализируется на решениях FinTech. Давайте обсудим, как воплотить ваш проект в жизнь.

Похожие статьи

Ошибка загрузки изображения
FinTech
Sep 8, 20269 мин чтения

Проектирование матчинг-движка на Rust: приоритет цены и времени без пауз GC

Читать
Ошибка загрузки изображения
FinTech
Apr 27, 202618 мин чтения

Отчёт о трейдинговой инфраструктуре 2026: Казахстан, Узбекистан, Армения, Грузия

Читать
Ошибка загрузки изображения
FinTech
Mar 14, 202612 мин чтения

Почему важны миллисекунды: простое руководство по задержкам в торговых платформах

Читать