baykovpro

← Quant

100 млн бэктестов BTC: как отличить навык от удачи

7 августа 2026 · 9 мин · бэктест, Deflated Sharpe, data-snooping, BTC

Суть идеи

Авторы из Rulyfi поставили масштабный эксперимент: сгенерировали и прогнали ~99.9 млн вариаций стратегий на BTC/USDT, чтобы эмпирически продемонстрировать проблему множественного тестирования. Результат предсказуем, но цифры отрезвляют: 336 818 стратегий прошли стандартный тест на значимость (PSR > 0.95), то есть их Sharpe статистически отличался от нуля. Но когда применили Deflated Sharpe Ratio (DSR) — осталось лишь 3 130, меньше 0.003%.

DSR — это поправка Байли–Лопес де Прадо. Идея простая: если ты тестируешь N стратегий, лучший Sharpe из них будет выше нуля уже чисто по законам статистики. DSR поднимает планку сравнения не с нулём, а с тем Sharpe, который ты ожидал бы получить от случайного победителя при N попытках. Важно: эта планка растёт лишь логарифмически с N — то есть даже 100 млн тестов не делают задачу принципиально неразрешимой, просто требуют честного учёта.

Формально DSR также учитывает негауссовость доходностей (скос и эксцесс) и длину серии — оба фактора критичны для крипты, где хвосты жирнее, чем в акциях, а история коротче.

Применимость к крипте

Прямее некуда: данные — BTC/USDT, не какие-то синтетические акции. Всё, что описано, ложится на наш стек без адаптации. Для опционных стратегий (VRP, skew-carry, gamma-flip фильтры) проблема множественного тестирования стоит ещё острее: параметров больше, независимых событий меньше, а история IV на крипте — от силы 5-6 лет. Каждый раз, когда мы перебираем пороги по GEX, delta-страйки или окна rolling-z, мы неявно прогоняем десятки вариантов. DSR — это именно тот инструмент, который должен стоять на выходе такого перебора.

Для on-chain сигналов (STH-MVRV, SOPR, Puell) ситуация аналогична: циклов мало, параметров много, и PSR там будет систематически завышен.

Тестируемо ли

Высокая реализуемость. В нашем Python bt_engine DSR можно добавить как финальный фильтр поверх walk-forward: считаем число протестированных конфигураций N, вычисляем ожидаемый максимальный Sharpe при N попытках, и сравниваем с ним OOS-Sharpe лучшей стратегии. Формула открытая (Bailey et al., 2014), реализация — несколько строк. Единственное, что нужно честно считать — это реальное N, включая все «ручные» итерации, которые исследователь делал до финального прогона. Именно здесь большинство команд жульничают (осознанно или нет).

Сомнения

Статья методологически честная, но у неё есть слепое пятно: 100 млн стратегий — это, судя по всему, параметрические вариации ограниченного числа семейств (скользящие средние, пробои и т.п.). Если все они коррелированы между собой, эффективное N значительно меньше номинального, и DSR-порог окажется завышен. Авторы, судя по аннотации, не раскрывают структуру пространства стратегий — а это ключевой вопрос. Кроме того, DSR предполагает, что все N стратегий тестировались на одних и тех же данных; если часть прогонов была на разных периодах, поправка некорректна.

Второй момент: 3 130 «выживших» стратегий — это ещё не доказательство навыка, это лишь нижняя граница отсева. OOS-тест на свежих данных (2024–2025) для этих 3 130 — вот что было бы по-настоящему интересно.

Следующий шаг

Взять наш текущий grid-search по параметрам rolling-z для VRP-стратегии (окно, порог входа, горизонт удержания), зафиксировать N протестированных конфигураций, добавить DSR-фильтр на выходе walk-forward и сравнить: сколько конфигураций проходят PSR > 0.95 vs DSR > 0.95. Если разрыв большой — у нас проблема с data-snooping прямо сейчас.

Результаты тестов

Дописано 2026-08-07 — прогнали «Следующий шаг» буквально, на BTC и ETH. Разрыв оказался максимальным из возможных: PSR пропускает до половины меню, DSR не пропускает никого. Но главное не это. Мы измерили то, что статья назвала своим открытым вопросом — эффективное число испытаний — и ответ противоположен ожидаемому: наши 504 конфигурации требуют такой же планки, как их 100 миллионов.

Спека выполнена как написана. VRP = DVOL (30-дневная подразумеваемая вола Deribit) минус RV30 (реализованная из дневного спота). Сигнал — rolling-z этого VRP, три оси ровно из спеки плюс ось «вкуса» z: окно L {30,45,60,90,120,180,250} × порог θ {0, 0.25, 0.5, 0.75, 1, 1.5} × горизонт удержания H {1,2,3,5,10,20} × z {классический / «scaled» без вычитания среднего} = 504 конфигурации, зафиксированы до прогона. Окно 2021-03-24 (старт DVOL) … 2026-07-31, 1956 дней. Walk-forward катящийся: 365 дней IS → 90 дней OOS, 15 фолдов, OOS-отрезок с 2022-12-29 (1311 дней). Вход на следующий день после сигнала.

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

Разрыв: 245 против нуля

Рукав (OOS, 1311 дней) лучший SR прошли PSR > 0.95 прошли DSR > 0.95
BTC · long спот +1.39 212 / 504 (42%) 0
BTC · шорт варианса +2.35 245 / 504 (49%) 0
ETH · long спот +1.26 77 / 504 (15%) 0
ETH · шорт варианса +0.55 0 / 504 0

У авторов из 336 818 прошедших PSR выжило 3 130 — 0.93%. У нас выживает ровно ноль во всех четырёх рукавах. Ответ на вопрос «если разрыв большой — у нас проблема с data-snooping прямо сейчас»: разрыв максимальный, проблема есть.

Оба обязательных контроля отработали, и они же показывают цену фильтра:

Мир (20 / 5 независимых прогонов) PSR > 0.95 DSR > 0.95
ПУСТЫШКА BTC — чистый шум, эджа нет 25 в среднем, до 235 0.0 (макс 0)
ПУСТЫШКА ETH — то же 29 в среднем, до 270 0.0 (макс 0)
Внедрён ИСТИННЫЙ эдж ann-SR 1.5, BTC 254 8.8 (макс 43)
Внедрён ИСТИННЫЙ эдж ann-SR 1.5, ETH 239 5.0 (макс 25)

Верхние две строки — приговор стандартному тесту: на данных, где эджа нет вообще, PSR в отдельных мирах пропускает до 270 конфигураций из 504. DSR не пропускает ни одной ни разу. Но нижние две строки — честная цена: когда истинный эдж ann-SR 1.5 есть, DSR находит его лишь в 5–9 конфигурациях из 504, а на выходе WF-отбора даёт 0.44–0.48, то есть отвергает настоящую стратегию. DSR — не бесплатный фильтр, а очень тупой нож: на нашей длине истории он режет ложное вместе с настоящим.

Слепое пятно статьи: эффективное N больше номинального, а не меньше

Главное возражение в «Сомнениях» — если конфигурации коррелированы, эффективное N много меньше номинального, и DSR-порог завышен. Это проверяемо: ротационный нуль (общий сдвиг драйвера при сохранённых позициях) даёт E[max SR] прямо по реальному меню, сохраняя корреляцию испытаний, — и не требует догадок о числе независимых попыток.

Получилось наоборот. Эмпирический максимум под нулём выше аналитического порога во всех четырёх рукавах:

Рукав E[max SR] нуля порог DSR при N=504 промах = разброс × форма
BTC · long спот +1.45 0.76 ×1.91 ×1.34 ×1.42
BTC · шорт варианса +2.66 1.66 ×1.60 ×0.91 ×1.77
ETH · long спот +1.10 0.82 ×1.34 ×1.10 ×1.22
ETH · шорт варианса +1.55 0.70 ×2.20 ×1.55 ×1.42

Промах раскладывается на два канала: sr0 = sd_SR · m(N). Канал разброса — насколько sd_SR, замеренный по реальному меню, отличается от разброса под нулём — гуляет в обе стороны (×0.91…×1.55) и общей причиной быть не может. А канал формы — насколько гауссова порядковая статистика m(N) ≈ √(2·lnN) недооценивает реальный максимум при том же разбросе — положителен всегда: ×1.22…×1.77. Формула написана для N независимых нормальных испытаний, а у нас H-дневные удержания и жирные хвосты драйвера; максимум такого меню систематически выше гауссова.

Дальше начинается арифметика логарифма. Множитель формулы при N=504 равен 3.05, эмпирический — 3.7–5.4. Разница выглядит скромно, но N сидит под логарифмом, и чтобы поднять множитель до эмпирического, объявленное число испытаний должно стать таким:

Рукав нужное N вместо 504
ETH · long спот 5 963
BTC · long спот 83 051
ETH · шорт варианса 75 909
BTC · шорт варианса 16 381 895

То есть наш поиск из 504 конфигураций требует ровно той планки, которую статья получает на 100 миллионах. Число бэктестов — не то, что задаёт порог. Это тот же вывод, к которому мы пришли на прошлой статье серии через другой рычаг (там ручкой оказался sd_SR), но здесь он жёстче: даже подставив в формулу правильный разброс, взятый прямо из нуля, промах никуда не девается — виновата сама гауссова посылка.

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

И заодно: нашего VRP-эджа в тайминге нет

Раз уж меню построено, полезно спросить не «сколько конфигураций красивы», а «нашёл ли наш поиск навык». Правильная процедура: каждый фолд выбираем лучшую по IS-Sharpe из 504 и торгуем её OOS — это то, что реально было бы задеплоено. Сравниваем с нулём самой процедуры отбора (тот же отбор на сдвинутом драйвере):

Рукав SR отбора, OOS нуль процедуры p_emp PSR DSR
BTC · long спот +0.57 +0.22 0.29 0.864 0.358
BTC · шорт варианса +1.49 +1.82 0.74 0.989 0.395
ETH · long спот +0.36 +0.05 0.24 0.757 0.193
ETH · шорт варианса +0.28 +0.85 0.80 0.687 0.232

Ни один рукав не значим. А в обоих вариансных рукавах нуль обгоняет реальность: сдвиг драйвера сохраняет положительный снос премии волы, но разрушает тайминг — и результат становится лучше. Значит наш rolling-z тайминг на VRP не просто бесполезен, он активно вредит против «постоянно быть в шорте волы». Отдельно отметим: BTC · шорт варианса даёт PSR 0.989 — по стандартному тесту это уверенно «работающая стратегия», которая на деле хуже собственного нуля.

Две оговорки. Первая: у конфигурации с фиксированными параметрами внутри неё нечего переподбирать, поэтому «выход walk-forward» в поконфигурационной таблице — это её ряд после первого IS-окна; настоящий walk-forward живёт в таблице отбора выше. Вторая: контроль корректности нуля (EW всего меню должен лечь на медиану) прошёл на вариансных рукавах (35-й и 11-й перцентиль), но на long-спотовых дал 80-й и 91-й — часть результата там держится на безусловном сносе BTC/ETH, который ротация воспроизводит не полностью. Для спотовых рукавов это делает оценку скорее консервативной, вывод не меняет.

Скрипт: research_dsr_vrp_gate.py (пре-регистрация осей — в шапке файла, до прогона).

Источник: Rulyfi · оригинал на английском, разбор — авторский на русском.