Python-снасти 12.10.2026 · 7 мин чтения · 👁 8 просмотров

Бэктест стратегии на pandas: шаг за шагом

Бэктест стратегии на pandas: шаг за шагом

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

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

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

Что делать, если вы хотите провести полноценный бэктест, но не знаете, с какого конца подойти к pandas? В следующей части расскажу про основные шаги и подводные камни, которые вас ждут.

Подготовка данных и первый шаг к бэктесту

Теперь перейдём непосредственно к практике. Допустим, у нас уже есть исторические котировки акций компании ABC за последние три года. Данные представлены в виде датафрейма df, который содержит столбцы 'Date', 'Open', 'High', 'Low', 'Close' и 'Volume'.

Для начала нам нужно привести временные метки к нужному формату. Обычно в pandas они хранятся в формате Timestamp, что удобно для работы с датами, но усложняет расчеты прошлых значений. Чтобы упростить дальнейшие вычисления, преобразуем timestamp в числовой формат, соответствующий дням:

df['Date'] = pd.to_datetime(df['Date'])
df.set_index('Date', inplace=True)
df.index = (df.index - df.index.min()).days

Теперь наши данные готовы к использованию. Следующий важный этап – определение уровней поддержки и сопротивления. Предположим, наша стратегия основана на пробое уровня поддержки. Для этого нам потребуется рассчитать минимальные цены за определённый период, например, за последние 20 дней.

support_level = df['Low'].rolling(window=20).min()

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

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

buffer = 0.01 * support_level
df['Support_Buffer'] = support_level - buffer

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

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

Допустим, мы хотим протестировать нашу стратегию покупки при пробое уровня поддержки на реальных данных. Для этого возьмём исторические котировки акций Apple (AAPL) за период с января 2020 года по декабрь 2022 года. Эти данные можно свободно скачать с Yahoo Finance или другого сервиса.

Наша стратегия будет выглядеть так:

  1. Найти уровни поддержки и сопротивления на графике цены.
  2. Когда цена пробивает уровень поддержки снизу вверх, открывать длинную позицию.
  3. Закрывать позиции через фиксированный процентный прирост (+5%).

Шаг 1: Загрузка и подготовка данных

Сначала загружаем исторические котировки с Yahoo Finance:

import yfinance as yf
import pandas as pd

## Загружаем данные за последние два года
data = yf.download('AAPL', start='2020-01-01', end='2022-12-31')

## Проверяем структуру данных
print(data.head())

Получаем датафрейм с колонками ['Open', 'High', 'Low', 'Close', 'Adj Close', 'Volume']. Теперь наша задача – найти уровни поддержки и сопротивления.

Шаг 2: Определение уровней поддержки и сопротивления

Уровни поддержки и сопротивления определяются как локальные минимумы и максимумы ценового графика. Для этого используем скользящие средние и стандартные отклонения:

## Рассчитываем простые скользящие средние
ma10 = data['Close'].rolling(window=10).mean()
ma20 = data['Close'].rolling(window=20).mean()

## Определяем уровни поддержки и сопротивления
support = ma10 - 2 * data['Close'].std()
resistance = ma20 + 2 * data['Close'].std()

## Добавляем новые колонки в датафрейм
data['Support'] = support
data['Resistance'] = resistance

Теперь у нас есть дополнительные колонки 'Support' и 'Resistance', которые помогут определить моменты пробоя.

Шаг 3: Тестирование стратегии

Реализуем саму стратегию покупки при пробое уровня поддержки:

def buy_on_breakout(df):
 positions = []

 for i in range(len(df)):
 if df['Close'][i] > df['Support'][i]:
 positions.append((df.index[i], 'Buy'))

 elif df['Close'][i] < df['Support'][i]:
 positions.pop() if len(positions) > 0 else None

 return positions

positions = buy_on_breakout(data)

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

Таким образом, с помощью простых инструментов pandas и базовых знаний технического анализа мы можем эффективно тестировать свои торговые стратегии даже на небольших объёмах данных.

Создание индикаторов и фильтрация сигналов

На предыдущем этапе мы подготовили наши данные и привели временные метки к нужному виду. Теперь пришло время добавить технические индикаторы и создать фильтры для наших торговых сигналов.

Допустим, наша стратегия предполагает вход в позицию при пробое уровня поддержки. Для этого можно использовать индикатор EMA (экспоненциальное скользящее среднее). Он поможет определить направление тренда и момент пробоя.

Вот пример кода для добавления EMA-индикатора в наш датафрейм:

df['ema_50'] = pd.Series(df['Close']).ewm(span=50, min_periods=50).mean()

Здесь мы рассчитали экспоненциальное скользящее среднее с периодом 50 баров. После этого добавим условие для фильтрации сигналов:

df['signal'] = np.where(df['Close'] > df['ema_50'], 1, 0)

Этот код создаёт новый столбец 'signal', значение которого равно 1, если текущая цена выше EMA, и 0 в противном случае. Таким образом, мы получаем простые сигналы для входа в сделку.

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

df_signal = df[(df['signal'].shift(1) 1)]

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

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

Следующий этап будет посвящен созданию функции для расчета доходности стратегии и оценке её эффективности.

Что я вынес из этой истории

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

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

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


Вывод

  • 🎣 Тестируй стратегию постепенно Не бросайся сразу торговать крупными суммами. Сначала проверь свою идею на небольших объёмах и минимальных рисках.
  • ⚠ ️ Не забывай про тестирование на реальных данных Даже самая красивая теория может провалиться на практике. Используй реальные исторические данные, чтобы избежать неприятных сюрпризов.
  • ⚠️ ️ Всегда проверяй корректность данных перед началом бэктеста. Ошибки в ценах или объемах могут привести к неверным результатам и ложному чувству уверенности в своей стратегии.

📚 Читайте также

Логирование торгового бота: что и как писать
Python-снасти

Логирование торгового бота: что и как писать

Читать →
Асинхронный парсинг цен 100 монет через aiohttp
Python-снасти

Асинхронный парсинг цен 100 монет через aiohttp

Читать →
🎣
Python-снасти

Как написать торгового бота на ccxt за вечер

Читать →

Понравилась статья? Поделись с друзьями:

📱 Telegram 💬 ВКонтакте 📌 Pinterest
📡 RSS-фид ← Другие статьи