Быстрый бектестинг стратегии на python с pandas

 

Я уже давно использую для бектестов python и pandas. pandas это библиотека для работы с матрицами и её прелесть в том, что она оперирует векторами и работает ГОРАЗДО быстрее, чем обычные циклы. Для того, чтобы сохранить это достоинство при бектестах я использую логарифмическую доходность (log-return на английском). Не ручаюсь за русские термины, так как узнал про них из англоязычных статей. Написанное ниже не истина в первой инстанции, а моя попытка разобраться как это всё работает чтобы применять на практике. Если я не прав, напишите. Я хоть и защищал кандидатскую диссертацию, но не по математике или экономике.

Немного теории

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

Формула для рассчёта логарифмической доходности, логарифм натуральный

Теперь на примере акций теслы. Цена по дням:

Цена теслы по дням

Логарифмическая доходность:

Логарифмическая доходность

На самом деле есть хитрость, если считать всё последовательно, то можно посчитать разницу между первой и последней ценой, так как остальные взаимно уничтожатся.

При рассчёте нескольких дней подряд, можно посчитать разницу только между первой и последней ценой

Но это если считать всё руками. Дальше будем считать всё подряд, так удобнее.

Предположим, мы купили акции теслы в начале периода и продали в конце. Чтобы посчитать прибыль такой сделки, нужно посчитать сумму логарифмов накоплением (cumulative sum) и посчитать экспоненту.

Прибыль сделки:

Как меняется доходность с изменением цены (последний столбец). Это цифра в разах, чтобы получить привычные проценты нужно умножить на 100%

Пример рассчёта стратегии на python

Есть акции теслы c января 2020 года. Дневной таймфрейм. Считаем две сользящие средние за 3 дня и 10 дней. Стратегия очень простая: если трёхдневная средняя выше десятидневной, то покупаем, если ниже, то продаём.

Импортируем котировки из yahoo finance и получаем вот такой dataframe:

Тесла с января 2020 года на дневном таймфрейме

Считаем две скользящие средние:

tsla_history['ma_3'] = tsla_history['Close'].rolling(window=3).mean()
tsla_history['ma_10'] = tsla_history['Close'].rolling(window=10).mean()


Скользящие средние и цена закрытия

Считаем позицию. 1 покупка, -1 продажа:

tsla_history['position'] = (tsla_history['ma_3']-tsla_history['ma_10']).apply(np.sign)

Считаем логарифмическую доходность:

tsla_history['log_return'] = tsla_history['Close'].apply(np.log).diff(1)

Считаем логарифмическую доходность с учётом позиции:

tsla_history['my_log_return'] = tsla_history['position'].shift(1)*tsla_history['log_return']

Считаем прибыль стратегии:

tsla_history['return'] = tsla_history['my_log_return'].cumsum().apply(np.exp)


Прибыль стратегии

Можно добавить ещё рассчёт комиссий. Возьмём 0,3% как у некоторых брокеров.

transaction_costs = 0.003
tsla_history['delta'] = tsla_history['position'].diff(1).abs()
tsla_history['tcs'] = tsla_history['delta']*transaction_costs
tsla_history['my_log_return_tcs'] = tsla_history['position'].shift(1)*tsla_history['log_return'] - tsla_history['tcs']
tsla_history['performance_tcs'] = tsla_history['my_log_return_tcs'].cumsum().apply(np.exp)


Сравнение стратегии с комиссей и без

И чё?

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

Полный код в jupyter notebook можно найти у меня в телеграм канале https://t.me/zenoftrading