Все материалыTRADING · Исследования · 9 МИН ЧТЕНИЯ

Почему ваши бэктесты вам врут

Хорошая equity-кривая ещё не доказывает преимущество: исполнение, смена режима, зависимые сделки и перебор гипотез могут сделать бэктест убедительным — и бесполезным.

Недавно мне прислали результаты бэктеста за 5 лет и спросили, насколько им можно доверять.

По цифрам всё выглядело нормально: около 0,28R на сделку, положительное матожидание и примерно 100 сделок в год. Никаких 100% win rate и вертикальной эквити.

Сообщение с вопросом о результатах пятилетнего бэктеста
Исходный вопрос: насколько реалистичен результат после расширения пула монет и таймфреймов?

Я ответил, что результат вполне может быть реальным. Но меня зацепило другое.

Автор тестировал разные периоды, расширял пул монет, добавлял таймфреймы и начал собирать режим-детектор. Мы в Ronin прошли ровно через тот же путь.

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

И это только один способ обмануть себя.

Второй появляется ещё раньше: симулятор может нарисовать тебе сделки, которых в реальности вообще не было бы.

Сначала надо понять, исполнились бы эти сделки

Большинство начинает с TradingView.

Закинул индикаторы, нажал Strategy Tester, получил зелёную кривую. Удобно и быстро.

Для проверки сырой идеи TradingView подходит. Но внутри работает брокерский эмулятор. На исторических данных он видит цены графика и предполагает, как цена двигалась внутри свечи.

Допустим, часовая свеча задела и стоп, и тейк. По OHLC непонятно, что произошло раньше. Эмулятор выбирает путь по своим правилам.

Bar Magnifier добавляет данные младшего таймфрейма и делает расчёт точнее. Но даже он не знает твою реальную позицию в очереди, доступный объём перед заявкой и состояние стакана в момент исполнения. TradingView сам описывает эти ограничения в документации.

Главная проблема лимитных ордеров проста: касание цены не означает исполнение.

Перед тобой мог стоять объём на $2 млн. По уровню прошло $200 000, цена развернулась, а симулятор записал тебе полный вход.

На рынке ты остался бы без позиции.

То же самое с частичным исполнением. На уровне лежит $30 000, твой размер составляет $100 000, а тест заполняет всё одной ценой.

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

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

Как мы считаем это в Ronin

Мы забираем данные с Bybit и работаем с тиковыми сделками и изменениями стакана.

Bybit сначала присылает snapshot, потом передаёт delta-обновления через WebSocket. В сообщениях есть sequence и время matching engine. Это позволяет синхронизировать изменения стакана с потоком сделок. Механика описана в документации Bybit.

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

Стек сейчас такой:

  • Python 3.14: исследования, статистика, расчёт EV и риск-модуль;
  • Go: коннекторы, WebSocket, REST и сервисы исполнения;
  • Redis: горячие данные и промежуточное состояние прогонов.

Своё ядро мы написали ради контроля над исполнением. Нам нужно учитывать очередь заявок, частичные заполнения, динамическое проскальзывание, комиссии, funding и задержку.

Точную позицию в очереди без order-level данных восстановить нельзя. В таких местах мы используем консервативную оценку. Если есть несколько возможных вариантов исполнения, движок не выбирает самый выгодный.

С пингом та же история.

Мы не занимаемся HFT и не пытаемся обогнать маркетмейкера на 1 мс. Но задержку всё равно считаем.

Если переход от 1 до 50 мс убивает матожидание, значит система зависит от идеального входа. Если результат держится при 50, 100 и 200 мс, сервер рядом с биржей ничего принципиально не изменит.

Кстати, Bybit превращает market order в IOC limit order с ограничением по проскальзыванию. Если в допустимом диапазоне не хватает ликвидности, часть заявки не исполнится. Это тоже есть в документации биржи.

Поэтому «я отправил рыночный ордер» и «я получил весь объём по лучшей цене» не одно и то же.

Допустим, исполнение мы посчитали правильно

Стакан восстановили. Очередь оценили. Комиссии, funding, задержку и частичные исполнения добавили.

Теперь бэктест честно показывает, как система торговала бы тогда.

Остаётся вопрос: насколько тот рынок похож на сегодняшний?

В переписке человек очень точно описал свою проблему:

Как только нарратив меняется, я уже слепой котёнок и не понимаю, почему по сетапу всё неплохо, а результат отрицательный.

Сетап на графике выглядит знакомо. Условия под ним уже другие.

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

Стратегия продолжает находить старую картинку, но прежнего преимущества внутри неё уже нет.

Как длинный бэктест прячет эту проблему

Представим 1 000 сделок.

В старом режиме прошло 800 сделок со средним результатом +0,20R.

В текущем режиме прошло 200 сделок со средним результатом −0,35R.

Общий результат остаётся положительным:

0,8 × 0,20R + 0,2 × (−0,35R) = +0,09R

На полном периоде система прибыльная. На последних 200 сделках она стабильно теряет.

Если следующие сделки будут похожи на текущий режим, исторические +0,09R тебе не помогут. Торговать придётся результат −0,35R.

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

Поэтому я не считаю, что старые данные надо выбрасывать. Я просто не хочу смешивать разные рынки в одну среднюю цифру.

5 лет данных ещё не означают хорошую выборку

При частоте 100 сделок в год за 5 лет получится около 500 сделок. На первый взгляд нормально.

Но 500 строк в отчёте не всегда означают 500 независимых ставок.

Допустим, BTC падает, а система одновременно открывает шорты по 20 альткоинам. В журнале появилось 20 сделок. По факту все они зависят от одного движения биткоина.

Расширение пула монет увеличило частоту, но почти не добавило независимой информации.

С таймфреймами то же самое. Сигналы на 1H и 4H могут использовать один импульс. Тест запишет две сделки, хотя система два раза поставила на одно событие.

Есть ещё survivorship bias.

Если сегодня взять список живых монет и прогнать его на истории, тест уже знает, кто пережил прошлые циклы. Умершие и делистнутые проекты в выборку не попадут. Вместе с ними исчезнут и потенциальные убытки.

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

Потом начинается перебор гипотез

Допустим, ты проверил:

  • 10 периодов средней;
  • 8 вариантов стопа;
  • 5 пулов монет;
  • 4 таймфрейма;
  • 3 фильтра режима.

Получается 4 800 комбинаций. И это без вариантов выхода, тейков и управления позицией.

Среди 4 800 тестов почти точно найдётся красивый.

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

Это называется backtest overfitting и multiple testing. Чем больше вариантов ты проверил, тем меньше можно доверять лучшему результату без поправки на количество попыток.

Для этого существуют Probability of Backtest Overfitting и Deflated Sharpe Ratio. Они не делают тест идеальным, но хотя бы учитывают, сколько раз исследователь пытался найти победителя. Нормальное объяснение этой проблемы есть у Bailey и López de Prado.

И ещё важный момент: после просмотра данных они перестают быть для тебя новыми.

Увидел просадку, добавил фильтр. Увидел мало сделок, расширил пул. Не понравился лонг на 1H, оставил только шорт.

Все решения могут быть логичными. Но история уже повлияла на систему. Называть итоговый результат полноценным out-of-sample после этого нельзя.

Биткоин как пример смены режима

В 2017 году рынок был тоньше. Огромную роль играли розница, спот, форумы и ICO.

К 2021 году появились развитые perpetual-фьючерсы, большие плечи и каскады ликвидаций.

В январе 2024 года SEC разрешила американские спотовые bitcoin ETP. К началу 2026 года ETP и крупные публичные компании вместе держали почти 12% предложения BTC. Это уже другой состав капитала. SEC, Fidelity

Тикер остался тем же. Поведение изменилось.

Биткоин впервые обновил старый ATH до халвинга 2024 года. В октябре 2025 года цена дошла примерно до $126 000. От цены халвинга это около 2X, что заметно слабее прошлых циклов.

Потом BTC потерял больше 50% от пика. При этом к 5 июля 2026 года почти 15 млн BTC не двигались минимум 155 дней. Рынок стал крупнее, доля долгосрочных держателей выросла, а волатильность и циклическая амплитуда снизились. Glassnode, Fidelity

По срокам 4-летний цикл примерно совпал. Пик пришёл через 1,5 года после халвинга.

Но календарь ничего не сказал про амплитуду, ликвидность и состав участников.

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

Значит ли это, что короткий бэктест лучше

Иногда да. Но не из-за самой длины.

Короткий тест ближе к текущему режиму. В нём меньше старых условий, которые уже не имеют отношения к сегодняшнему рынку.

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

Поэтому сейчас я разделяю задачи.

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

Свежий участок нужен, чтобы понять, соответствует ли система текущему режиму.

Новые данные, которые не участвовали в разработке, нужны для проверки результата.

Сваливать всё в одну общую доходность больше не вижу смысла.

Как мы сейчас тестируем

Сначала формулируем, откуда вообще берётся EV.

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

Потом делим историю по времени:

  1. Train для разработки.
  2. Validation для выбора параметров.
  3. Test, который не трогаем до фиксации системы.

Дальше запускаем walk-forward. Настроили систему на прошлом окне, зафиксировали параметры, проверили на следующем участке. Потом сдвинули окно и повторили.

Отдельно считаем результат по рыночным режимам.

Для режима смотрим realized volatility, характер тренда, spread, глубину, slippage, funding, basis, открытый интерес и rolling-корреляции.

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

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

После этого идёт shadow trading и минимальный реальный объём. Сравниваем цену из модели с фактическим исполнением, slippage, заполнение и live-expectancy.

Только форвард-тест может показать то, чего не видел разработчик.

Почему я пересобрал Ronin

В конце июля я полностью пересобрал систему.

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

Я специально гонял тест на участке своей просадки. Хотел понять, где именно исчезло преимущество: в волатильности, структуре движения, исполнении или самой логике входа.

Но после изменений этот участок уже нельзя считать независимым тестом. Я его видел и использовал для настройки.

Поэтому правила новой версии зафиксированы. Теперь доказательство должны дать следующие сделки.

Не прошлая зелёная кривая. Новые данные.

Что в итоге

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

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

Общая доходность идёт после этого.

Длинный тест показывает, где система ломалась. Свежий тест показывает, подходит ли она текущему рынку. Форвард проверяет, совпала ли модель с реальным исполнением.

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

Система должна знать не только когда входить.

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

Материал носит образовательный характер и не является инвестиционной рекомендацией.

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