VIZANIXРазработка торгового ПО
Архитектура ботовАрхитектура9 мин чтения

Архитектура торгового бота: слои, которые нельзя смешивать

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

Инженеры Vizanix · об авторе

МАТЕРИАЛ
9 минвремя чтения
РАЗДЕЛ
Архитектура ботов
ОПУБЛИКОВАНО
2026-08-28
ГЛАВ
6
ЧИТАТЬ ДАЛЬШЕ
3
ЯЗЫК
написано на русском
Инженерный разбор, а не пересказ документации.
LAYERSSTRATEGYEXECUTIONRISKTRANSPORT

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

Пять слоёв

СлойОтвечает заНе должен знать про
ТранспортREST-клиент, WebSocket, подпись, лимиты, повторыСтратегии, позиции, P&L
Реестр инструментовСимволы, фильтры, категории, шаг цены и лотаВсё, что меняется во времени
Состояние рынкаСтаканы, свечи, фандинг, целостность последовательностиОрдера, намерения
СтратегияСигналы: хочу быть в лонге на 3 единицы XAPI биржи, ID ордеров, HTTP
Риск и исполнениеПревращение намерения в ордера при ограниченияхПочему стратегия этого захотела

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

Почему граница стратегии так важна

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

  • Бэктест. Нельзя прогнать стратегию, которая ждёт HTTP-клиент. Подменив биржу моком, вы получите тест мока.
  • Paper trading. Та же проблема, только вживую.
  • Общий риск. Когда три стратегии сами ставят ордера, никто не знает суммарной экспозиции до того, как она уже набрана.
  • Смена площадки. Новая биржа означает переписывание каждой стратегии вместо одного адаптера.
python
# Стратегия говорит намерением. Она не знает, что биржа существует.
@dataclass(frozen=True)
class Intent:
    symbol: str
    target_qty: Decimal        # со знаком: отрицательное — шорт
    stop: Decimal | None
    reason: str                # уходит в журнал аудита дословно

class ImpulseReversal:
    def on_bar(self, bar, state) -> Intent | None:
        ...
        return Intent(bar.symbol, -size, stop=level, reason="rsi_overbought_series_4")

# Риск и исполнение решают, что на самом деле произойдёт с этим намерением.
def handle(intent: Intent):
    approved = risk.evaluate(intent, portfolio.snapshot())
    if approved.rejected:
        audit.log(intent, approved.reason)
        return
    executor.reconcile_to(approved.target_qty, intent.symbol)

Поле reason выглядит любезностью. На деле именно оно позволяет через шесть недель ответить на вопрос «почему бот это сделал». Наш сигнальный движок сохраняет причину для каждой оценки, включая отказы, — поэтому «почему сегодня нет входов» это запрос к базе, а не сеанс отладки.

Целевая позиция, а не купить и продать

Выражайте намерение как желаемое конечное состояние, а не как действие. «Быть в лонге на 3» идемпотентно: если бот перезапустился и повторил это, уже держа 3, сверщик не сделает ничего. «Купить 3» — нет: тот же перезапуск купит ещё 3.

Один этот выбор убирает целый класс багов с двойным исполнением и делает восстановление после обрыва тривиальным: приводим к цели, что бы ни случилось во время разрыва.

Пульт работает рядом, а не внутри

Операторам нужно запускать, останавливать, настраивать и смотреть. Этот интерфейс не должен уметь застопорить торговый цикл. В нашем микроструктурном движке Telegram-пульт — отдельный процесс, общающийся через Unix-сокет: реалтайм-цикл никогда не делает сетевой вызов к API чата, не ждёт его и не может быть заблокирован его медлительностью.

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

Хранение не на горячем пути

Записывать всё — это то, что делает систему честной, а писать синхронно — то, что делает её медленной. Наш сигнальный движок держит 5,76 миллиона оценок за пятнадцатидневное окно — каждую оценку, а не только сработавшие — и делает это пакетными записями в стороне от пути оценки, с индексами под реально выполняемые запросы.

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

Как выглядит хорошо

  1. Слой стратегии запускается на исторических данных вообще без сети.
  2. Вторая площадка добавляется написанием одного адаптера.
  3. На вопрос «какова была суммарная экспозиция в 14:32» отвечает хранилище.
  4. Убийство пульта не влияет на торговлю.
  5. Перезапуск процесса восстанавливает состояние с биржи, а не из локального файла.

Ничего экзотического здесь нет. Это обычное разделение на слои, применённое к области, где цена дырявой границы измеряется деньгами, а не временем на рефакторинг.

Статья описывает инженерную практику. Это не инвестиционная рекомендация. Vizanix разрабатывает программное обеспечение и не обещает торговую доходность.

Блог

Читать дальше

Хотите такое у себя?

Мы пишем о том, что строим. Если нужно построить — напишите, разбор бесплатный.

Бриф

Получить оценку проекта

Четыре вопроса и контакт. Предоплата для разговора не нужна — если задача не наша, скажем сразу.

01Что вам нужно
02Биржа
03Рынок
04Стратегия
05Контакты

Проще написать напрямую? Telegram @vx_ceo

Обсудить систему