Как TradeJS проводит бэктесты торговых стратегий
Бэктест применяет одну конфигурацию стратегии к историческим свечам и моделирует входы, выходы и управление позициями. Он нужен для проверки сформулированной гипотезы и сравнения конфигураций при одинаковых допущениях, а не для прогноза будущей доходности.
Зафиксируйте условия эксперимента
Чтобы результат можно было воспроизвести, сохраните:
- стратегию и версию её пакета;
- полную конфигурацию стратегии;
- коннектор, инструменты и таймфрейм;
- точные начало и конец периода;
- источник свечей и правила корректировки данных;
- комиссии, проскальзывание, модель исполнения и задержку входа;
- комбинации параметров и правило выбора результата.
Изменение любого из этих пунктов создаёт новый эксперимент.
Запуск
Проще всего начать с веб-приложения по инструкции Первый бэктест. Сохранённую конфигурацию можно запустить через CLI:
npx @tradejs/cli backtest \
--user root \
--config <StrategyName:configName> \
--connector <connector> \
--timeframe <minutes> \
--tickers <SYMBOLS> \
--tests <limit> \
--parallel <workers>
Если локальные сервисы остановлены, сначала запустите их:
npx @tradejs/cli infra-up
Флаг --cacheOnly запрещает обновлять историю и подходит для повторной проверки
на уже сохранённых свечах.
Отделяйте издержки исполнения от оценок стратегии
Для воспроизводимого сравнения передавайте издержки моделирования отдельно от конфигурации стратегии:
npx @tradejs/cli backtest \
--config <StrategyName:configName> \
--executionCosts '{"fees":{"makerRate":0.001,"takerRate":0.001},"slippage":{"baseBps":10,"spreadMultiplier":1,"marketImpactBps":0,"delayRiskMultiplier":0},"funding":{"enabled":false}}'
Комиссии задаются десятичной ставкой для одной стороны сделки, поэтому 0.001
означает 0,1%. Проскальзывание ухудшает цену каждого исполнения, а комиссия
считается от полученной стоимости исполнения. Значение false в
funding.enabled исключает funding из расчёта. Для включённого funding нужна
доступная историческая ставка, в том числе при запуске на сохранённых данных.
TradeJS фиксирует объект для всего запуска и включает его в контрольную точку и результат. Продолженный запуск использует те же издержки. Для других допущений создайте новый запуск.
Поля стратегии RISK_FEE_RATE, RISK_SLIPPAGE_BPS и
RISK_MARKET_IMPACT_BPS используются отдельно для проверки входа и расчёта
позиции. Изменение --executionCosts не меняет эти оценки стратегии, а
изменение оценок не меняет моделируемые комиссии, проскальзывание и funding.
Этапы расчёта
- Загружается выбранная сетка параметров.
- Определяются инструменты и исторический период.
- Загружаются или обновляются свечи.
- Формируются комбинации параметров.
- Комбинации распределяются между параллельными процессами.
- Сохраняются сделки и рассчитывается итоговая статистика.
Бэктест и работа с текущим рынком используют одну реализацию стратегии, но условия исполнения различаются. Бэктест не может полностью воспроизвести место ордера в очереди, влияние на рынок, сбои биржи, сетевые задержки и будущую ликвидность.
Перебор параметров
Каждое поле сетки содержит одно или несколько значений. TradeJS проверяет их
декартово произведение с учётом ограничения --tests. Размер поиска должен
иметь экономическое обоснование, а правило выбора итогового варианта следует
зафиксировать заранее.
Большой перебор повышает вероятность случайно получить привлекательный результат. Выбранный вариант нужно проверить на данных, не использованных при выборе, а также на устойчивость к близким параметрам, комиссиям, проскальзыванию и разным рыночным режимам.
Формат и команды описаны в разделе Сетка параметров бэктеста.
Анализ результата
Не ранжируйте конфигурации только по чистой прибыли. Как минимум проверьте:
- число сделок и время в позиции;
- доходность после комиссий и моделируемого проскальзывания;
- максимальную просадку и время восстановления;
- profit factor, математическое ожидание и распределение результатов сделок;
- концентрацию по направлениям и инструментам;
- устойчивость по подпериодам и рыночным режимам;
- чувствительность к небольшим изменениям параметров и издержек.
Результат имеет смысл только при достаточной длине периода и размере выборки для характерного срока удержания и оборота стратегии.
Необязательные данные для AI/ML
Флаг --ml записывает строки для ML-набора, а --ai — для офлайн-проверки
промптов. Эти флаги только добавляют исследовательские данные и не включают
AI/ML-фильтры во время бэктеста. Части набора объединяются командами
ml-export и ai-export.