На главную

Два бага, которые прятались за одним сработавшим kill-switch

Торговый бот остановился по защитному лимиту риска на 6 суток — разбор показал, что дело не в стратегии, а в двух багах защитного механизма.

У одного из наших ботов-участников торгового челленджа (paper trading, не реальные деньги) есть kill-switch — защитный механизм, который останавливает торговлю, если просадка превышает установленный лимит риска. Это стандартная и правильная защита. Но когда мы разобрали, почему он сработал и простоял 6 суток, выяснилось, что причина не в стратегии, а в двух багах самого защитного кода.

Что случилось на первый взгляд

Kill-switch сработал при просадке -3.24R против лимита -3.0R (R — риск-единица, стандартная метрика в трейдинге). Торговля остановилась и не возобновлялась 6 суток. За всё время работы бот показывал +44.28R, с пиком +47.52R — то есть просадка от пика была реальной, но не катастрофической. Основной вклад в результат — стратегия EMA(10/30) на ETHUSDT, 164 закрытые сделки.

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

Разбор показал: новых потерь не было

Проверка всех сделок с момента срабатывания показала, что реально закрылось только две позиции — обе в момент самого триггера. Новых входов за 6 суток не происходило вообще — то есть стоп-код отработал корректно в своей главной функции: он остановил именно то, что должен был остановить.

Живое значение риска на момент проверки (43.22R) оказалось ниже снапшота на момент триггера (44.28R) — но это floating-просадка по уже открытым позициям, переоценка по текущей цене, а не новые реализованные убытки. Разница между “мы теряем деньги прямо сейчас” и “у нас есть открытая позиция, которая пока не в плюсе” — важная, и её легко перепутать, если смотреть только на итоговое число.

Баг №1: окно месячного лимита не сдвигалось вместе со сбросом

Кроме однократного лимита на общую просадку, у kill-switch есть отдельный месячный лимит риска. Он считался с 1 числа календарного месяца — а не с момента, когда просадка была сброшена в рамках защитного механизма. На практике это означало: если в начале месяца уже накопились убытки хуже лимита (в моменте проверки — -4.30R против лимита -4.0R), бот остановился бы повторно на первой же новой сделке после перезапуска, независимо от того, была она прибыльной или убыточной.

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

Баг №2: мёртвый Telegram-токен

Второй баг был проще по сути, но серьёзнее по последствиям: токен Telegram-бота, зашитый в код для уведомлений о срабатывании kill-switch, оказался нерабочим (HTTP 401 Unauthorized). Сколько именно раз защитный механизм срабатывал молча, без единого уведомления — установить уже нельзя, история не сохранилась.

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

Что в итоге

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

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

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