ML-ансамбль для торговли криптовалютами полтора месяца показывал на истории AUC до 0,78, но в реальном времени терял весь перевес. Причиной оказался незаметный look-ahead bias: признаки четырёхчасового таймфрейма сообщали ранним 15-минутным барам данные из конца ещё не закрытой свечи.
Суть события
Торговая система из шести моделей — LightGBM, LSTM, Transformer, TCN, PatchTST и iTransformer — оценивала вероятность роста криптопары на горизонте нескольких 15-минутных свечей. На бэктесте по 11 месяцам истории ансамбль давал AUC 0,74–0,78 и заметный лифт лучших сигналов, а в paper trading результат схлопывался почти до нуля.
Месяц команда проверяла очевидные версии: смену рыночного режима, недообучение и слишком короткое окно инференса. Окна от 500 до 4000 свечей ничего не изменили. Настоящая причина пряталась в подготовке признаков старшего таймфрейма и делала историческую проверку нечестной.
Детали
Четырёхчасовые свечи собирались через resample(‘4h’). Агрегат получал метку начала интервала, хотя вычислялся по всем входящим в него барам. Затем reindex с forward fill разносил итоговое значение по всей корзине. Поэтому бар 12:15 уже «знал» данные вплоть до 15:45 — максимальная утечка составляла 3 часа 45 минут.
Баг доказал позиционный тест. Значение признака на полной истории сравнили с тем же значением, пересчитанным на срезе, обрезанном по текущий бар. Расхождение было максимальным в начале четырёхчасовой корзины и падало до нуля на последнем баре. Это точная сигнатура подглядывания в ещё не наступившее будущее.
Цена ошибки оказалась высокой. На скомпрометированные признаки приходилось около 41% суммарной важности моделей. Аудит 35 признаков и 5,5 часа GPU-переобучения пришлось признать недостоверными. Отдельную long-only ветку закрыли: после исправления ни одна из 72 комбинаций параметров не прошла валидацию.
Контекст
Исправление заняло одну операцию: shift(1) перед reindex для каждой серии старшего таймфрейма. Теперь 15-минутный бар получает данные только последней полностью закрытой четырёхчасовой свечи. После фикса позиционный тест показал нулевое расхождение на всех местах корзины, а реальный сигнал сохранился, хотя оказался примерно вдвое слабее прежней оценки.
Этот случай полезен не только трейдерам. Временные ряды встречаются в прогнозировании спроса, антифроде, мониторинге оборудования и риск-моделях. Если обучение и валидация используют одинаково «отравленный» расчёт, обычный holdout может не заметить утечку. Нужна проверка, которая воспроизводит знания, действительно доступные системе в конкретный момент. Похожий разрыв между красивым тестом и поведением в продакшне виден и в опыте <a href=»https://ai-digest.ru/ii-agent-4-mesyaca-dezhuril-na-prod-logah-113-alertov-2-gallyucinacii-i-fiks-za/»>ИИ-агента, дежурившего на прод-логах</a>.
Что дальше
Практический шаг простой: для каждого нового агрегированного признака сравнивать расчёт на полной истории с последовательным расчётом на обрезанных срезах. Такой тест дороже обычного вычисления, поэтому достаточно выборки временных точек — особенно начала и конца агрегированных интервалов.
Дополнительно стоит измерять лифт относительно базовой частоты на том же периоде, делить историю пополам по времени и запускать permutation test. Эти проверки не заменяют позиционный тест, но отсеивают рыночный фон, подгонку и ложные открытия. Несколько минут вычислений здесь дешевле недель оптимизации стратегии, которая работала только потому, что тайно читала будущее.