Блог им. tradezen

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

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

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



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


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

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


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

Логарифмическая доходность:  
Быстрый бектестинг стратегии на python с pandas




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

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


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

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

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

Прибыль сделки:  
Быстрый бектестинг стратегии на python с pandas




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

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



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

Импортируем котировки из yahoo finance и получаем вот такой dataframe:  
Быстрый бектестинг стратегии на python с pandas


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

Считаем две скользящие средние:
tsla_history['ma_3'] = tsla_history['Close'].rolling(window=3).mean()
tsla_history['ma_10'] = tsla_history['Close'].rolling(window=10).mean()


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


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

Считаем позицию. 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)
 
Быстрый бектестинг стратегии на python с pandas


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

Можно добавить ещё расчёт комиссий. Возьмём 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)
 
Быстрый бектестинг стратегии на python с pandas


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

И чё?



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

Полный код в jupyter notebook можно найти у меня в телеграм канале t.me/zenoftrading
★33
28 комментариев
А Вы проверили что покупатете на следующий день.<br />Потому что здесь<br />
<br />tsla_history['position'] = (tsla_history['ma_3']-tsla_history['ma_10']).apply(np.sign)<br /><br />

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

<br />покупка идет и считается последний день<br />
<br />это заглядывание в историю.<br /><br />

Вы покупаете вначале дня а информацию о сигнале получаете в конце этого-же дня.
avatar
Антон Б, наоборот же, сначала сигнал, а потом покупка. Вот тут это учитывается:

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

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

tsla_history['log_return'] — а здесь почем сдвига нет?

avatar
Офигеть,  я настолько тупой, что даже не понял, что тут считается. 
Это как то помогает заработать?
А локальные минимумы и максимумы можно предсказать?  Хотя бы по одному ближайшему?
avatar
Дмитрий К, обычная стратегия на скользящих средних, на такой не заработаешь много. 
avatar
websan, я просто не понял, что тут считается.
То, что если использовать индикаторы на базе скользящих средних,  и по сигналам совершать сделки,  с помощью питона можно рассчитать сколько бы заработал/потерял?
Если так, то я просто не понимаю, зачем изобретать велосипед?
Капец хобби.
Лучше бы робота какого написал, который статьи в Телеграм сам пишет, чтоб время себе сэкономить.
Таких встроенных средств навалом  есть, в терминале альфадирект точно есть, в метатрейдере по моему есть.
Ладно бы чувак, анализируя данные,  придумал находить точки входа, которые статистически,  давали бы вероятность точного прогноза хотя бы процентов 60
avatar
Дмитрий К, здесь код просто делает бэк тест, но мне кажется он немного некорректен, т.к. не ясно когда открывать позиции, а когда закрывать. Проблемы средних скользящих это постоянные пробои ценой туда сюда, что создаёт кучу сделок ложных 
avatar
websan, точнее сольешь и очень хорошр)
avatar
Дмитрий К, не важно что тут считается, важно как. Это всего лишь технология. Если не понимаете, значит оно вам не нужно.
avatar
zenoftrading, хм,  Вы знаете,  как с помощью пандаса, загрузив тиковые данные,  найти все экстермумы, затем отфильтровать их по заданной дельте,  оставив только соответствующие, (например найти только экстремумы, разница между которыми 500 пунктов, отбросив все промежуточные с меньшей разницей), затем сделать анализ зависимости, по разным параметрам,  например через сколько в среднем времени, или после какого объёма, после одного экстермума цена доходит до следующего, или сколько было в промежутке между экстремумами сделок купли и продажи с каким объёмом,  и наконец сделать визуализацию в виде графиков, диаграмм,  гистограмм и прочего,  чтобы можно было статистически наконец понять, что любые исторически найденные неэффективности на одних участках и инструментах анализируемых данных, не работают на других.?

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

Ещё раз повторю свой вопрос,  что Вы считаете? Можете сформулировать,  раз пост запилили? Уточню также, что самое важно не как,  и не что,  а зачем.

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

Дак вот, для тех, кому это интересно,  все это проще, нагляднее, быстрее сделать в каком нибудь Microsoft power by например, если самому охота повозиться. Или есть ещё масса инструментов для анализа, причём встроенные в терминалы некоторые.
avatar
Может быть использовать ТС Лаб? В нем все есть уже.
Тестировать можно бесплатно
avatar
На меньшем не выйдет, яхуфинанс тоьтко дневки даёт, тоже делал такие штуки, боьлше в академических целях, так как практичнее в тслаб загнать, такую стратегию прогнать минуты 3 с учётом времени на оптимизацию
Андрей Алферов, из примеров:

valid intervals: 1m,2m,5m,15m,30m,60m,90m,1h,1d,5d,1wk,1mo,3mo (https://pypi.org/project/yfinance/)
avatar
Eugene Logunov, так а развернуть мысль? Почему?
avatar
Парсер по ключевым словам на форумах будет куда эффективнее, да и разве что дивергенция цены к всему подряд. Остальное эффекта на рынках не даст.
Рынки — недетерминированные структуры. Формулы — не дадут ничего, уже проверено.     
Ваши логарифмические доходности показались мне слишком маленькими (в абсолютных величинах) и я решил их подсчитать самостоятельно. Вместо ряда 0.021, -0.010, -0.003… я получил: 0.0481, -0.022, -0.0067… Не пойму, где у меня ошибка. Как эти доходности Вы считали в Python?
avatar
DR. LECTER, видимо вы про изменение в процентах? они отличаются от логарифмической доходности
avatar
zenoftrading, нет, видимо, я про это: log return = ln(P[t]/P[t-1]) 
ln(98.43/93.81)=0.0481, а не 0.021.
avatar
DR. LECTER, точно, спасибо. В экселе не тот логарифм написал. В питоне использовал numpy.log это натуральный логарифм.
avatar
Eugene Logunov, но удобен. 
Любой расчет должен имитировать не только схему принятия решения и её влияние на результат, но также транзакционные издержки и правило управления капиталом. Расчет в логарифмах позволяет очень легко учесть транзакционные издержки и близко к действительности — самофинансируемую стратегию. Для одного лота надо действовать иначе. 
avatar
Eugene Logunov, по опыту, разница невелика. Для разработки систем точность достаточная. Для того, чтобы сравнивать теоретическую систему с реально торгуемой, надо очень точно эмулировать торговую деятельность. Мало кому это нужно. Я лично использую эмуляцию только для отладки реальных ТС. 
avatar
Eugene Logunov, ага, понял о чём вы. Согласен, это не супер точный метод, но для первоначальной оценки подойдёт. На практике всё равно будут отличия от любого тестирования.
avatar
BRENT PROFIT, спасибо за корректуру)
avatar
Вообще-то, библиотека для работы с матрицами — это numpy. А pandas оперирует объектами более сложной структуры — Series и DataFrame. И там могут быть не только числа. А работает pandas быстро именно с числами, потому как под капотом у нее numpy.

теги блога zenoftrading

....все тэги



UPDONW
Новый дизайн