Разработка системы бэктестинга: где ломаются портфельные криптостратегии
Разработка системы бэктестинга начинается не с кода, а с честного ответа на вопрос: почему бэктест портфеля показывает рост, а реальный счёт — просадку. Типовая причина — модель исполнения. В тестировании криптостратегий сделка закрывается по цене из свечи, а в реальности ордер проходит по нескольким уровням стакана, и на тонких парах проскальзывание в бэктесте съедает всю прибыль стратегии. Если этого не заложить в движок, результат красивой кривой не имеет отношения к торговле.
Вторая группа ошибок бэктестинга — комиссии и задержки. Мейкер-тейкер, ставка финансирования по фьючерсам, стоимость вывода между биржами, лаг между сигналом и постановкой ордера: каждая из этих статей по отдельности выглядит мелочью, но на портфеле из десятков инструментов и обороте в сотни сделок в сутки они меняют знак доходности. Портфельный бэктест обязан считать их на уровне каждой сделки, а не вычитать средний процент в конце.
Третье узкое место — данные. Дыры в истории, разные таймфреймы у источников, делистинг и ренеймы токенов, отсутствие стакана за ранние периоды. Стратегия, которая «видит» будущую цену из-за сдвига свечей или заполнения пропусков, показывает доходность, недостижимую в реальности. Поэтому корректный бэктест портфеля строится на едином хранилище данных с явной политикой обработки пропусков и версионированием наборов.
Четвёртый слой — портфельная логика. Ребалансировка, пересечение сигналов по инструментам, лимиты на корреляцию и общую экспозицию, распределение капитала между стратегиями. Ошибка здесь не в отдельной сделке, а в том, как стратегии конкурируют за один и тот же капитал и одновременно открывают позиции в одну сторону рынка.
Разбираем, как это закрывается: от архитектуры движка и модели исполнения до валидации на out-of-sample и сверки с реальными сделками.
Что даёт корректная разработка системы бэктестинга портфельных стратегий
Событийный и векторный подход: где проходит граница
Векторный бэктест считает доходность по массиву цен за один проход — прогон на нескольких годах истории укладывается в секунды, и это удобно для первичного отбора гипотез. Ограничение проявляется на портфеле: просадки, ребалансировки и частичные исполнения заявок в такой модели не воспроизводятся, поэтому результат годится только для отсева заведомо слабых стратегий.
Событийный бэктест обрабатывает поток рыночных событий по одной свече или сделке, и каждый ордер проходит через модель исполнения. Прогон дольше, но именно он показывает реальную просадку и поведение стратегии на разрывах ликвидности. В нашей практике портфель из десятков инструментов на нескольких годах истории считается за минуты, а не часы — за счёт предзагрузки данных и распараллеливания по инструментам.
Воспроизводимость как инженерное требование
Каждый прогон фиксируется: версия данных, набор параметров, состояние портфеля на старте. Повторный запуск с теми же входными данными даёт бит-в-бит совпадающий отчёт — расхождение означает баг в модели, а не «рыночный шум». Это убирает целый класс ошибок, когда стратегия выглядит прибыльной из-за подглядывания в будущее или неверного учёта комиссий.
| Подход | Когда подходит | Ограничения |
|---|---|---|
| Векторный | Быстрый отбор гипотез, одиночные инструменты | Не моделирует просадку и очередь заявок |
| Событийный | Портфель, ребалансировки, оценка риска | Дольше прогон, сложнее в реализации |
| Гибридный | Отбор на векторе, проверка на событиях | Требует согласования моделей данных |
Метрики стратегии — доходность, максимальная просадка, коэффициент Шарпа, оборот — считаются на одном и том же движке для всех прогонов, поэтому результаты сравнимы между собой. Архитектура бэктестера строится так, чтобы тестируемая стратегия не знала, работает она на истории или на живых данных: один и тот же код идёт в бой без переписывания. Такой подход лежит в основе Backtrader и родственных фреймворков.
Как мы строим систему бэктестинга: этапы инженерной работы
Разработка системы бэктестинга начинается не с кода, а с аудита данных и правил, по которым стратегия принимает решения. На входе — выгрузки сделок, котировки с нескольких площадок, история ребалансировок портфеля. На выходе — воспроизводимый конвейер, где каждая цифра в отчёте объясняется конкретным источником и настройкой симулятора.
- Аудит торговых данных. Сверяем источники котировок, проверяем пропуски, дубли и расхождения между площадками, приводим таймзоны и валюты к единому виду. Без этого шага любая метрика стратегии — случайное число.
- Формализация стратегии и портфельных правил. Фиксируем логику входов и выходов, размер позиции, лимиты по инструментам и правила ребалансировки. Спорные места выносим в явные параметры, а не в скрытые допущения в коде.
- Настройка симулятора исполнения. Задаём комиссии, проскальзывание, задержку исполнения и модель ликвидности. Симулятор должен воспроизводить реальные условия сделки, иначе результаты на истории не переносятся на живой рынок.
- Внедрение бэктестера и прогон на истории. Собираем конвейер расчёта, запускаем стратегию на исторических данных, считаем доходность, просадку, оборот и распределение сделок по времени.
- Валидация стратегий. Проверяем устойчивость результата: разбиение истории на периоды, тесты на разных наборах инструментов, проверка чувствительности к параметрам. Стратегия, которая держится только на одном удачном отрезке, отсеивается здесь.
- Сверка с независимым расчётом. Сравниваем ключевые метрики с ручным пересчётом на выборке сделок — так ловим ошибки в логике портфеля и учёте издержек.
- Передача системы. Разворачиваем конвейер в инфраструктуре заказчика, документируем параметры, обучаем команду запускать прогоны и добавлять новые стратегии самостоятельно.
Каждый этап заканчивается артефактом: очищенный набор данных, спецификация правил, конфигурация симулятора, отчёт по прогону. Это позволяет вернуться на любой шаг без пересборки всего конвейера. Опишите вашу задачу — вернёмся с оценкой и планом работ.
Чем событийный бэктест отличается от векторного и когда что выбирать?
Векторный бэктест считает всю историю одним матричным проходом: сигналы, доходности и веса портфеля перемножаются массивами, позиции пересчитываются синхронно на каждом баре. Это даёт скорость — десятки тысяч прогонов параметров за минуты, что критично на этапе первичного отбора стратегий. Ограничение в том, что такой подход предполагает идеальное исполнение: заявка всегда срабатывает по цене закрытия, ликвидность бесконечна, а порядок событий внутри бара не важен. Для стратегий на ликвидных инструментах с редкой ребалансировкой этого достаточно.
Событийный бэктест воспроизводит работу системы по шагам: приходит рыночное событие, стратегия реагирует, заявка уходит в симулятор исполнения, портфель пересчитывается с учётом комиссий, проскальзывания и частичного заполнения. Здесь корректно моделируются стоп-заявки, лимитки, внутрибарные срабатывания и задержки между сигналом и исполнением. Цена — время: один прогон может занимать минуты вместо секунд, поэтому массовый перебор параметров на нём не делают.
Выбор метода определяется типом стратегии, а не удобством. Для моментум-портфелей, ребалансируемых раз в неделю или месяц, векторный подход даёт ту же картину доходности, что и событийный, но в разы быстрее. Для стратегий с частыми входами, стопами и зависимостью от микроструктуры рынка векторный бэктест завышает результат: он «видит» цены, которых в реальном исполнении не было.
Практика — двухступенчатая. Сначала векторный прогон отсекает заведомо слабые конфигурации по широкой сетке параметров, затем финалисты проверяются событийным движком с реалистичной моделью издержек. Расхождение между двумя результатами — сам по себе диагностический сигнал: если событийная доходность заметно ниже векторной, стратегия живёт за счёт идеального исполнения, и в реальной торговле это не воспроизведётся.
В разработке системы бэктестинга мы закладываем оба движка на общем слое данных, чтобы переход между ними не требовал переписывать логику стратегии.
Кейс: как портфельная криптостратегия перестала расходиться с реальностью
Заказчик пришёл с классической болью: портфельная стратегия на исторических данных показывала ровный рост, а на реальном счёте результат расходился с бэктестом на десятки процентов. Разбор показал три причины — учёт комиссий и проскальзывания по усреднённой ставке вместо модели по каждому инструменту, ребалансировка по цене закрытия без задержки на исполнение и подглядывание в будущее при расчёте сигналов. То есть расхождение бэктеста с торговлей было не рыночной случайностью, а дефектом самой модели.
Мы переписали ядро прогона: свечи грузятся по каждому инструменту отдельно, комиссия и проскальзывание считаются на каждую сделку, сигнал формируется только на закрытой свече, а исполнение сдвинуто на следующий бар. Добавили журнал решений — по каждой сделке видно, какой сигнал её породил и какие данные были доступны в тот момент. Это превратило оптимизацию стратегии из подбора красивых чисел в проверку логики.
Что изменилось в цифрах
| Метрика | До | После |
|---|---|---|
| Расхождение бэктеста с торговлей | 30–40% по доходности | в пределах 3–5% |
| Время прогона портфеля | часы на одну конфигурацию | минуты, прогон в параллель |
| Найдено ошибок в логике стратегии | не отслеживалось | 11 подтверждённых дефектов |
| Воспроизводимость результата | зависела от порядка запуска | детерминированный прогон |
Отдельно закрыли воспроизводимость: один и тот же набор данных и параметров теперь даёт идентичный результат независимо от порядка запуска и машины. Это то, без чего кейс бэктестинга не имеет смысла — если прогон нельзя повторить, сравнивать конфигурации не с чем.
VectorBT взяли как основу для векторизованного прогона — он даёт скорость на портфеле из десятков инструментов, а обвязку под учёт комиссий и задержек исполнения писали сами, потому что типовые настройки не покрывали нужную модель сделки.
Совместимость, миграция и доступы: что обсудить до старта
Разработка системы бэктестинга почти никогда не начинается с чистого листа: у заказчика уже есть биржевые ключи, исторические котировки, внутренние отчёты по портфелям и, возможно, собственные расчёты в таблицах или скриптах. Поэтому до старта важно зафиксировать три вещи: как система встанет рядом с текущей инфраструктурой, каким путём переносятся накопленные данные и кто получает доступ к торговым ключам.
Если это не проговорить заранее, на этапе приёмки всплывают сюрпризы — расхождение исторических данных с прежними расчётами, отсутствие ролей у аналитиков или невозможность откатить обновление стратегии без остановки всего контура.
Что если у нас уже есть свои расчёты? Мы не ломаем их, а сверяем: прогоняем эталонный набор сделок через новую систему и старую логику, расхождения разбираем до цифры. Что если понадобится откат? Каждая версия конфигурации стратегии и набора данных версионируется, поэтому возврат к предыдущему состоянию — это переключение на зафиксированную версию, а не восстановление из резервной копии. Что с доступами? Ключи к биржам хранятся в защищённом хранилище, права раздаются по ролям: аналитик видит данные и результаты, но не может вывести средства.
Можно ли внедрять поэтапно, не останавливая текущую работу?
Да. Сначала поднимаем контур на исторических данных в режиме чтения, сверяем результаты с вашими эталонами, и только после этого подключаем реальные источники и торговые ключи. Текущие процессы на это время не затрагиваются.
На руки после сдачи заказчик получает:
- развёрнутую конфигурацию системы с описанием всех параметров расчёта;
- схему интеграции с биржами и источниками исторических данных;
- политику доступа и разграничения ролей, включая работу с торговыми ключами;
- регламент миграции накопленных данных и сверки с прежними расчётами;
- инструкцию по откату изменений и возврату к предыдущей версии стратегии;
- документацию по эксплуатации: мониторинг, обновление данных, реакция на сбои.
Опишите вашу задачу и текущий стек — вернёмся с оценкой, планом работ и перечнем данных, которые понадобятся на старте.
Сроки внедрения системы бэктестинга по этапам
Сроки зависят от трёх вещей: сколько исторических источников нужно подключить, насколько сложна логика ребалансировок и требуется ли учитывать исполнение сделок с проскальзыванием и комиссиями. Ниже — ориентировочная раскладка по этапам для типовой портфельной стратегии. Границы этапов пересекаются: подготовка данных идёт параллельно с проектированием ядра, чтобы не терять недели на ожидании.
Что сдвигает сроки вверх
Самый частый источник задержек — не код, а данные: биржевые выгрузки приходят с разрывами, разными таймзонами и задним числом переписанной историей. Если стратегия торгует на нескольких биржах, добавляется сверка цен между площадками и учёт расхождений. Вторая причина — сложная логика ребалансировки: правила с порогами, ограничениями по ликвидности и частичным исполнением требуют отдельного слоя симуляции сделок.
Что ускоряет работу
Когда заказчик сразу даёт доступ к историческим данным и описывает правила входа-выхода формально, этап подготовки сокращается вдвое. Готовый слой метрик и отчётов переиспользуется между стратегиями — вторая и последующие модели проходят путь заметно быстрее первой.
Backtrader — один из движков, на которых мы собираем такие системы: он даёт готовую инфраструктуру прогона по истории, а мы дописываем под задачу учёт издержек и отчётность.







