На вопрос «почему бэктест не совпадает с реальной торговлей» обычно отвечают проскальзыванием, комиссиями и задержками. Всё это реально. В нашей собственной платформе причина была не в них.
Причина была в том, что правило, решающее, входить ли в сделку, существовало дважды — в боевом движке и в бэктестере, — и две копии отвечали РАЗНОЕ. 28 августа 2026 года мы построили прибор, который сверяет их бар в бар. Он нашёл двадцать расходящихся пар из пятидесяти восьми, и худшая из них позволяла бэктестеру видеть будущее.
Почему правило вообще написано дважды
Это не халатность, и если вы пользуетесь любой ботовой платформой — у неё почти наверняка так же.
Боевой движок получает свечи от биржи по одной и решает в момент закрытия последней. Бэктестер держит всю историю в массивах и идёт по ней векторно, потому что иначе год минутных баров считается часами.
Намерение одно, форма разная. Математику индикаторов можно сделать общей — у нас она общая, — и всё равно две дорожки способны разойтись в том, *на каком баре мы стоим*. Именно этот вопрос оказывается местом, где лежат деньги.
Что мы мерили
Одна конфигурация системы идёт по обеим дорожкам: напрямую в боевой фильтр и в бэктестер через того же владельца поверхности, которым пользуется продукт. Обе спрашиваются на каждом баре, вердикты сравниваются. 29 фильтров входа × 2 стороны × 2 ряда свечей (гладкий и рваный).
Прибор меряет ещё и себя, и это оказалось важнее самой сверки: для каждой пары он печатает, сколько баров фильтр РАЗЛИЧИЛ. Фильтр, который ни разу не запретил (или запретил всегда), ничего не сравнил, и «совпало» у него не значит ничего. На первом прогоне таких слепых пар было шесть.
Находка 1: выравнивание массива УГАДЫВАЛОСЬ
Чтобы спросить «какой был MACD на баре 400», нужно знать, где в массиве индикатора лежит этот бар. Массивы индикаторов короче массива свечей: первые N баров уходят на прогрев. Наш бэктестер выводил это смещение из периода индикатора.
Догадка была верна ровно для одного индикатора из девяти.
| индикатор | какой бар читался на самом деле |
|---|---|
| MACD | idx +7 |
| ADX | idx +13 |
| Stochastic | idx +1 |
| EMA, SMA, CCI, %R, Боллинджер | idx −1 |
Положительное смещение означает, что бэктестер спрашивал бар, которого в момент решения ещё не было. У двух самых ходовых фильтров платформы вход в бэктесте гейтился данными из будущего.
Это ровно тот класс дефекта, из-за которого стратегия хорошо выглядит на истории и иначе ведёт себя в бою, — и никакое чтение двух реализаций рядом его не покажет, потому что по отдельности верны обе.
Починка — не «догадка получше»: смещение теперь выводится из длин массивов и указывает на последний ЗАКРЫТЫЙ бар, тот же, который видит бой.
Находка 2: три разных способа прочитать половину свечи
Текущая свеча ещё формируется. Включать её или нет — это решение, и оно обязано быть одинаковым на обеих дорожках.
| что | расхождений |
|---|---|
| фильтр объёма в бою снимал формирующийся бар ДВАЖДЫ | 17 из 400 |
candle3 и дивергенция в черновике читали срез до формирующегося бара | 60 и 28 из 400 |
| ATR % делился на разные цены (закрытый бар против текущей) | 7 из 400 |
Обратите внимание на вторую строку: 60 из 400 — пятнадцать процентов баров. Это не краевой случай, это другая стратегия.
Находка 3: прогрев — часть правила, а не деталь
Рекурсивный индикатор (RSI, ATR, ADX — семейство Уайлдера) никогда не забывает затравку полностью, он лишь ослабляет её вес. Правило у нас было: подать столько баров, чтобы вес затравки стал меньше 1 %, и начинать.
Это правило пришло из рассуждения, а не из замера исхода. Прибор замерил исход: при остаточном весе в 1 % затравка ещё решает — RSI 54,7 против порога 55, ADX −DI 24,7 против +DI 25,4. Три пары из пятидесяти восьми переворачивались на этом.
Теперь порог 0,1 %, он распространён на всё семейство Уайлдера и заведён для семейства EMA, где бой брал period + 21 свечу, оставляя затравке около 45 % веса.
Находка 4: с выходом было хуже
Затем мы навели тот же метод на выход — на цену, по которой закрывается позиция. Десять расходящихся пар из двадцати, слепых ноль.
| что | бой | черновик | чем это было для пользователя |
|---|---|---|---|
| безубыток | avg ± 0,2 % (две комиссии тейкера) | ровно avg | прогон рисовал безубыток бесплатным; в бою он платит комиссию круга |
| трейлинг до безубытка | тралит только ПОСЛЕ прохождения безубытка | тралил с первого бара | порог 99,50 против боевых 95,14 — прогон закрывал циклы, которых в бою не было |
| ATR-стоп | возвращал ATR-уровень сразу, минуя безубыток и трейлинг | применял защиту поверх ATR-базы | включённая пользователем защита прибыли не работала никогда |
| ступенчатый безубыток | ведёт стоп по ценам исполненных частичных тейков | не знал о нём вовсе | до 5 % цены — прогон рисовал просадку, которой в бою не бывает |
Три дефекта из четырёх — дефекты черновика. Один — дефект БОЯ: ATR-ветка молча выключала защиту, которую пользователь включил явно. Это не выбор модели: настройка сохранена, показана в форме и не исполняется.
Вот на этом стоит задержаться. Правило выхода решает, сколько денег остаётся в цикле. Человек доказывал систему прогоном по одному правилу, а деньги терял по другому.
Находка 5: дорожек три, и третья — самая коварная
Бэктест и бой — те две, что сравнивают все. У большинства платформ есть третья: бумажная торговля, режим, которым набирают уверенность до того, как заводить деньги.
У нас это отдельная реализация тика, не имеющая с боевым движком общего кода. Когда мы наконец сравнили РЕШЕНИЯ — та же конфигурация, байт в байт, один путь цены, — выяснилось, что фильтры входа на бумажной дорожке не работали вовсе. Замер на паре одинаково настроенных систем (short, RSI ≥ 70): бой не поставил ни одного ордера за 33 часа, бумага отработала четыре цикла со входами при RSI 67,1 · 45,6 · 43,4 · 34,5.
Бумажный трек доказывал систему без фильтра входа — то есть чужую.
Чтением кода это тоже не находилось: гейт стоял НИЖЕ раннего return бумажной ветки. Имя правила в файле было, исполнения не было.
Самое полезное, что мы поняли про приборы
Промежуточная версия прибора паритета выравнивала обе дорожки «по закрытию бара», и расхождения исчезали. Выглядело как успех.
Но объявленная в проекте модель решения другая — уровень индикатора с последнего ЗАКРЫТОГО бара против цены СЕЙЧАС, — и расхождение поймал уже существовавший гард. Останься та версия, мы доказали бы совпадение с ошибкой.
Подгонять прибор, пока код не пройдёт, — самая дорогая ошибка из возможных здесь, потому что на выходе получается не красный прибор, который игнорируют. Получается зелёный, которому верят.
Как проверить это на любой платформе, включая нашу
Наш код для этого не нужен. Нужна одна дисциплина: сравнивать РЕШЕНИЯ, а не результаты.
- Возьмите одну конфигурацию и прогоните её по обеим дорожкам — бэктест и бой (или бумага).
- Сравнивайте на каждом баре, а не в конце. Кривая доходности прячет взаимно компенсирующиеся ошибки, побарные вердикты — нет.
- Считайте, сколько баров правило различило. Если фильтр в вашей выборке ни разу не запретил, он ничего не доказал, и его «совпало» — артефакт.
- Проверьте границу явно: какой бар был последним закрытым в момент решения и обе ли стороны взяли именно его?
- Проверьте прогрев: сколько баров прошло до первого сигнала и какой вес ещё несёт затравка?
Если платформа говорит, что её бэктест и боевой движок используют общий код, следующий вопрос — какие именно части: у нас была общей математика индикаторов, и это не помешало разойтись в двадцати парах из пятидесяти восьми.
Границы этого замера
- •Это наша реализация, а не утверждение про чужие. Мы вправе говорить о том, что нашли у себя. Любое утверждение о другой платформе требует того же прибора, наведённого на неё.
- •Синтетические ряды свечей, две формы. Гладкий и рваный, подобранные так, чтобы фильтры реально срабатывали. Мерится согласие правил, а не доходность.
- •Совпадение — не правильность. Две дорожки могут совпасть и обе быть неверны. Паритет — условие необходимое, а не достаточное; ровно поэтому версию «выровнять, пока не сойдётся» пришлось отвергнуть.
- •Комиссии, проскальзывание и задержки — отдельные вопросы. Они реальны, и они не то, что здесь замерено.
- •Это не инвестиционная рекомендация, и ничто из перечисленного не является советом торговать.
Где это сейчас
Паритет входа: 58 пар из 58 совпадают, слепых ноль. Паритет выхода: 34 из 34. Оба прибора стоят в гейте перед пушем, поэтому повторное расхождение роняет сборку, а не ждёт, пока кто-нибудь вспомнит о проверке.
Бумажную дорожку судит третий прибор, сравнивающий решения, а не текст: выставленные уровни, сколько их реально в стакане, исполненные входы, позиция, цикл, построенный тейк — против замороженного списка известного долга, чтобы НОВОЕ расхождение роняло тест, а известное оставалось на виду.
Мы публикуем эти числа, потому что вторая формулировка была бы нечестной. Ничего экзотического здесь не было. Был один обыкновенный вопрос — *на каком баре мы стоим* — на который в двух местах ответили по-разному люди, каждый из которых был прав насчёт своей половины.