Backtesting простыми словами: как проверять стратегию на прошлых периодах

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

Содержание Следующие статьи
Содержание Backtesting простыми словами: как проверять стратегию на прошлых периодах
  1. Почему стратегия на истории кажется умной почти всегда
  2. Что именно делает backtesting
  3. Почему backtesting легко сделать нечестным
  4. Как показать идею в Python

Почему стратегия на истории кажется умной почти всегда

Backtesting очень привлекателен, потому что дает ощущение быстрого ответа: берем стратегию, прогоняем по прошлым периодам и смотрим, как она бы себя вела. Это полезно и в торговых системах, и в продуктовых правилах, и в decision policy задачах. Но именно здесь рождается одна из самых опасных иллюзий аналитики: если стратегия красиво выглядела на истории, значит она хороша и впереди. На практике история легко переобучается так же, как и модель.

Поэтому backtesting полезен только тогда, когда его воспринимают как честную симуляцию прошлого решения, а не как машину для самоуспокоения.

Что именно делает backtesting

Формула: раздел математики — временные ряды и оценка стратегий
$$ Performance = \sum_{t=1}^{T} outcome_t(strategy_t) $$
Что означает эта формула

Backtesting оценивает стратегию как последовательность решений на прошлых периодах и их фактических исходов. Смысл в том, чтобы шаг за шагом проиграть, что произошло бы, если бы в каждый момент применялась именно эта стратегия.

Что означает каждый символ
  • Performance — накопленный результат стратегии на историческом горизонте
  • outcome_t — фактический исход решения в период t
  • strategy_t — решение стратегии в момент времени t
  • T — длина исторического окна проверки

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

Почему backtesting легко сделать нечестным

Во-первых, через look-ahead bias: когда стратегия использует информацию, которая в тот момент времени еще не была доступна. Во-вторых, через подгонку правил под уже известную историю. В-третьих, через игнорирование издержек: задержек, комиссий, операционных ограничений, нагрузки команды, latency в системе. Исторический тест без этих ограничений часто выглядит лучше реальности.

Именно поэтому сильный backtest — это не просто прогон на CSV, а аккуратная реконструкция того, какие данные, сигналы и ограничения были доступны в каждый момент времени.

Как показать идею в Python

example.pyPython
import pandas as pd  # создаем простой пример исторической стратегии по порогу сигнала

frame = pd.DataFrame({  # задаем временные наблюдения и будущий результат действия
    'day': [1, 2, 3, 4, 5],  # временная ось проверки
    'signal': [0.2, 0.7, 0.4, 0.9, 0.6],  # сигнал, доступный в момент решения
    'future_gain': [0.0, 1.2, -0.3, 1.8, 0.4],  # фактический результат действия после решения
})
frame['action'] = (frame['signal'] >= 0.6).astype(int)  # стратегия действует только при сильном сигнале
frame['realized_gain'] = frame['action'] * frame['future_gain']  # считаем фактический результат стратегии по периодам
print(frame)  # смотрим, как историческая проверка раскладывает стратегию по времени
print(round(frame['realized_gain'].sum(), 3))  # суммируем общий результат backtest на истории

Backtesting становится по-настоящему полезным тогда, когда сохраняет уважение к времени, ограничениям и честности данных. Иначе он быстро превращается в красивую, но опасную ретроспективную иллюзию.

Что читать дальше

Связанные статьи по этой теме

Canary deployment для моделей: как выкатывать новую версию без лишнего риска Latency в ML API: почему быстрая модель важна не меньше точной Batch inference и real-time inference: как выбирать режим работы модели
Вернуться в блог