Разработка системы бэктестинга с поддержкой multi-timeframe

Сигналы на разных таймфреймах расходятся, и результат прогона не совпадает с реальной торговлей. Мы разрабатываем системы multi-timeframe бэктестинга под ключ: согласовываем расчёт по всем периодам и сокращаем время подготовки прогонов в разы. Обсудим задачу и вернёмся с планом работ.
Часто задаваемые вопросы

Почему multi-timeframe бэктестинг ломается на реальных данных

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

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

Третий — подгонка под историю. Чем больше комбинаций параметров прогоняется на одном отрезке, тем выше шанс, что лучший результат — случайность: про это подробно писал Лопес де Прадо. На старшем таймфрейме сделок мало, и «прибыльная» конфигурация часто держится на десятке входов, которые не переживают переноса на другой участок данных.

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

Эффект от согласованного расчёта на нескольких таймфреймах

Пока стратегия принимает решения по одному таймфрейму, расчёт прозрачен: один поток свечей, одна временная шкала. Но как только добавляется подтверждение со старшего периода, появляется источник расхождений — младший бар успевает закрыться несколько раз внутри одного старшего, и вход может опираться на данные, которых в момент расчёта ещё не было. Мы собираем multi-timeframe бэктестинг в одном ядре событий (в основе — Backtrader и собственные расширения), поэтому согласованность сигналов проверяется воспроизводимым прогоном на истории, а не глазами.

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

Время прогона стратегии меняется нелинейно. Старшие серии агрегируются один раз и кэшируются, стратегия обращается к готовым срезам, а не пересчитывает их на каждом шаге: прогон на трёх таймфреймах дороже одиночного примерно на 20–40%, а не втрое.

Доля ложных входов падает за счёт фильтра: сигнал младшего таймфрейма принимается только при совпадении направления старшего. По нашим прогонам такое правило отсекает 30–50% входов против старшего тренда — но часть прибыльных сделок оно тоже срезает, поэтому порог подтверждения подбирается по метрикам, а не включается «на всякий случай».

Форматы прогона multi-timeframe бэктестинга: история, поток, гибрид

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

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

Вариант Когда подходит Ограничения
Пакетный расчёт Отладка правил входа, проверка гипотез на длинной истории, прогон по набору инструментов Расход памяти растёт с числом таймфреймов; синхронизацию закрытий приходится проверять вручную
Потоковый расчёт Финальная проверка стратегии, где критична честность порядка событий Заметно медленнее; сложнее воспроизвести сбойный прогон и отладить логику перехода
Гибридная схема Рабочий режим multi-timeframe бэктестинга: младший ряд идёт потоком, старшие считаются инкрементально Требует явного правила, в какой момент старший таймфрейм считается доступным

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

Этапы внедрения: от аудита данных до передачи контура

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

  1. Аудит исторических данных — проверяем полноту рядов по инструментам и таймфреймам, ищем пропуски, дубли и разрывы, сверяем цены закрытия с независимым источником.
  2. Схема пересборки свечей — описываем правила агрегации: границы старшего интервала, момент закрытия бара, поведение на неполных и аномальных участках.
  3. Настройка контура — разворачиваем расчётную среду, версионируем наборы данных и конфигурации, разграничиваем хранилище истории и вычислительную часть.
  4. Проверка на устойчивость — прогоняем правила на разных периодах и подвыборках, отдельно контролируем подглядывание в будущее и расхождение истории с онлайн-потоком.
  5. Приёмка расчётов — сверяем контрольные примеры и вручную разобранную выборку сделок, фиксируем допустимые отклонения и порог, за которым результат считается недостоверным.
  6. Передача контура — отдаём документацию, регламент обновления данных и доступы, обучаем команду повторять расчёт без нашего участия.

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

Что передаём на руки: конфигурации, схемы и регламенты

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

  • Конфигурации прогона — отдельный профиль на каждый сценарий: состав таймфреймов, правило ресемплинга старших интервалов из младших, окно синхронизации, комиссии и проскальзывание. Меняются правкой одного файла, без вмешательства в код.
  • Схема данных — источник свечей, таймзоны, момент закрытия бара, обработка пропусков и корпоративных действий, плюс чек-лист валидации на дубли и разрывы истории.
  • Эталонный срез истории — зафиксированный набор данных, на котором прогон воспроизводится до последней сделки: по нему сверяют результат после любых правок.
  • Регламент запуска — порядок шагов: подготовка данных, прогрев индикаторов, прогон, сбор метрик, разбор расхождений; с пометками, где вычисление упирается в ресурсы.
  • Политики доступа — роли и права на изменение конфигураций, ключи к рыночным данным только на чтение, журнал правок параметров с автором и причиной.
  • Шаблоны отчётов — метрики по прогону, включая долю сделок, где вход по младшему таймфрейму подтверждён старшим, и разбор расхождений между интервалами.
  • Документация — описание модели данных и соглашений о времени закрытия бара, инструкция «как добавить новый таймфрейм», журнал изменений методики.
  • План передачи — разбор с вашими инженерами и список открытых вопросов, которые закрываем после сдачи.

Кейс: убрали расхождение сигналов на разных таймфреймах

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

Что было на входе

Прогон одной сетки параметров занимал около трёх часов, поэтому гипотезы проверяли пачками по ночам. Доля сделок, где сигнал старшего таймфрейма расходился с фактическим входом, доходила до 6,4% — на дистанции в сотни сделок это съедало преимущество стратегии. Покрытие ограничивалось двумя таймфреймами: добавление третьего удваивало время прогона и ломало воспроизводимость.

Что изменили

Расчёт развели на независимые календари таймфреймов, а решения принимали строго по факту закрытия бара — сигнал попадает в исполнение с явным детерминированным лагом. Агрегаты старших рядов считаются один раз и кладутся в кэш, поэтому добавление таймфрейма больше не пересчитывает всю историю. Ядро оставили на Backtrader: библиотека даёт событийную модель, но синхронизацию рядов и порядок исполнения пришлось выстраивать вручную.

Что стало

Доля расхождений упала до 0,2% — это сделки на границе пропусков в данных, они помечаются и разбираются отдельно. Полный прогон занимает 22 минуты, в сетке теперь четыре таймфрейма вместо двух. Повторный запуск на тех же данных воспроизводит результат до последней сделки, а версия расчётной конфигурации сохраняется вместе с отчётом — откат к предыдущей занимает минуты.

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

Чем отличается пересборка свечей от потокового расчёта?

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

Пересборка свечей платит за точность расчёта задержкой данных — пока ряд не развёрнут и не агрегирован, multi-timeframe бэктестинг не стартует, а на глубокой истории это заметная пауза. Потоковый расчёт отвечает почти мгновенно, но его состояние живёт в памяти: при разрыве канала или перезапуске агрегатор нужно восстанавливать, иначе бар «поедет».

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

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

Частые технические сомнения перед стартом работ

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

Как вы проверяете качество исторических данных?

Сверяем источник с независимым, ищем пропуски, дубликаты и разрывы торговых сессий, приводим бары к единому часовому поясу. Для multi-timeframe бэктестинга критично выравнивание: старший таймфрейм собирается только из закрытых младших баров, иначе в расчёт просачивается будущее. Данные с дырами и неверной агрегацией дают красивую кривую на истории и нулевой результат на живом рынке.

Как убедиться, что результат не подогнан под прошлое?

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

Что будет, если мы добавим новый таймфрейм или инструмент?

Стратегия описывает правила, а не конкретный набор баров: таймфреймы, инструменты и источники подключаются настройкой. Новый ряд добавляется без переписывания логики и тестов — контур рассчитан на рост числа таймфреймов и инструментов.

Можно ли проверить стратегию на демо-счёте?

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

Обсудим задачу и вернёмся с планом работ

Чтобы обсуждение задачи было предметным, к нему стоит собрать вводные, которые определяют архитектуру: как хранятся и синхронизируются данные разных таймфреймов, где узкие места по скорости и что считается корректным результатом. Для системы бэктестинга с поддержкой multi-timeframe это ядро будущего решения.

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

С нашей стороны первый ответ — рабочий документ, а не письмо о намерениях. В нём будет план работ по этапам, оценка сроков на каждый этап, состав команды с ролями (архитектор, инженер по данным, разработчик расчётного ядра, тестировщик) и перечень рисков с тем, как мы их закрываем. Если по ходу разбора окажется, что часть задачи решается проще, скажем об этом прямо. Опишите задачу — вернёмся с оценкой и планом.

Направления блокчейн-разработки

Последние работы

  • Разработка сайта компании B2B ADVANCE
    Разработка сайта компании B2B ADVANCE
    1542
  • Разработка веб-приложения для компании FEEDME
    Разработка веб-приложения для компании FEEDME
    1393
  • Разработка веб-сайта для компании БЕЛФИНГРУПП
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    1081
  • Разработка интернет магазина для компании FURNORO
    Разработка интернет магазина для компании FURNORO
    1368
  • Разработка логотипа компании B2B Advance
    Разработка логотипа компании B2B Advance
    815
  • Разработка веб-приложения для компании Enviok
    Разработка веб-приложения для компании Enviok
    1139