Скрининг акций с помощью Python Backtrader

Часть 1

Опытные «квантовые» типы совершают сделки, проверяя акции в поисках технических сигналов. Давайте избежим использования подходов «черного ящика» и создадим движок с использованием библиотеки Backtrader на Python для проверки списка акций в поисках потенциально оппортунистической сделки. ~2 страницы кода.

В части 1 мы соберем наши данные. Чистые данные всегда являются обязательным условием для любого проекта по обработке и анализу данных.

Quant — это, по сути, еще одно упражнение по науке о данных.

Как только у нас будут данные, мы познакомимся с Python Backtrader, мощным движком для моделирования сделок.

В части 2 мы будем работать над следующим:

  • загрузить данные по акциям в Python Backtrader
  • узнать об индикаторе HMA
  • Протестируйте каждую акцию за предыдущий год, чтобы найти оптимальный период скользящей средней для нашего индикатора
  • Используйте этот индикатор/период, чтобы увидеть, есть ли сигнал за последние 1–2 дня

Мы должны быть в состоянии сделать все это на десятках акций за считанные секунды.

Сбор данных

Вы можете получать данные об акциях из различных источников, некоторые бесплатные, другие за определенную плату. В этом проекте мы будем использовать https://www.tiingo.com/, который предлагает бесплатный API. Зарегистрируйтесь и попробуйте их API.

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

Вот код для сбора данных по акциям:

https://medium.com/media/8ed6e3427b17fcb02f80dc2ade4ea197Захват данных: https://gist.github.com/ugik/d3c641f68ca3b759adc627ce53671a8b

Обратите внимание, что это формат CSV с разделителями-запятыми. Начальные значения dow — это заголовки столбцов. Простой.

Каждая акция будет создавать файл в текущем каталоге с самым последним годом и тикером акций, например. SPY_2019–02–26_2020–02–26.txt

В этом примере мы будем использовать 60 символов ETF. Узнайте больше о биржевых фондах здесь. Вы можете выбрать любой набор акций.

Интересно, что некоторые из ETF с большим объемом имеют обратный капитал, чтобы получать прибыль на нисходящих колебаниях без временного кредитного плеча опционов. Подробнее об этом позже…

Python Backtrader

Многофункциональный фреймворк Python для тестирования на истории и торговли. Backtrader позволяет вам сосредоточиться на написании многоразовых торговых стратегий, индикаторов и анализаторов вместо того, чтобы тратить время на создание инфраструктуры.

На сайте Backtrader есть хороший набор документации и примеров. Начни здесь.

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

После того, как стратегия определена, вы можете протестировать ее на исторических данных, это будет генерировать сигналы BUY и SELL и отслеживать доходность с течением времени.

Графики могут быть построены для отображения сигналов с течением времени по линии эквити и выбранным индикаторам.

Ниже приведен пример тикера: ORCL в 2000 году и сигналы с помощью простого индикатора скользящей средней.

Зеленые стрелки — это сигналы на покупку, красные стрелки — сигналы на продажу, синие и красные точки над временной шкалой графика показывают выигрышные и проигрышные позиции.

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

Далее по руководству вы увидите пример оптимизации параметров. Период MA («Скользящая средняя») (в днях) — это тестирование для поиска оптимального периода в выбранном диапазоне тестирования.2000-12-29, (MA Period 10) Ending Value 880.30
2000-12-29, (MA Period 11) Ending Value 880.00
2000-12-29, (MA Period 12) Ending Value 830.30
2000-12-29, (MA Period 13) Ending Value 893.90
2000-12-29, (MA Period 14) Ending Value 896.90
2000-12-29, (MA Period 15) Ending Value 973.90
2000-12-29, (MA Period 16) Ending Value 959.40
2000-12-29, (MA Period 17) Ending Value 949.80
2000-12-29, (MA Period 18) Ending Value 1011.90
2000-12-29, (MA Period 19) Ending Value 1041.90
2000-12-29, (MA Period 20) Ending Value 1078.00
2000-12-29, (MA Period 21) Ending Value 1058.80
2000-12-29, (MA Period 22) Ending Value 1061.50
2000-12-29, (MA Period 23) Ending Value 1023.00
2000-12-29, (MA Period 24) Ending Value 1020.10
2000-12-29, (MA Period 25) Ending Value 1013.30
2000-12-29, (MA Period 26) Ending Value 998.30
2000-12-29, (MA Period 27) Ending Value 982.20
2000-12-29, (MA Period 28) Ending Value 975.70
2000-12-29, (MA Period 29) Ending Value 983.30
2000-12-29, (MA Period 30) Ending Value 979.80

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

Мы будем оптимизировать наш период скользящей средней для каждого из десятков акций ETF, используя более сложный индикатор в широком диапазоне длин периодов.

Большой пул акций большого объема увеличивает наши шансы найти ту, которая недавно появилась.

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

Часть 2

Давайте напишем скринер акций на Python с тестированием на истории, оптимизацией модели и посмотрим, какие сделки готовы к запуску. ~2 страницы кода.

Код здесь.

В части 1 мы настроили наши данные и узнали о Backtrader.

В части 2 мы будем работать над следующим:

  • загрузить данные по акциям в Python Backtrader
  • узнать об индикаторе Hull Moving Average (HMA)
  • Протестируйте каждую акцию за предыдущий год, чтобы найти оптимальный период скользящей средней для нашего индикатора
  • Используйте этот индикатор/период, чтобы увидеть, есть ли сигнал за последние 1–2 дня

Последний шаг — это желаемый результат скринера: набор потенциально действенных сделок по сигналам одного или нескольких технических индикаторов.

Каждый [период времени] запускается скринер и дополнительно оцениваются сигналы, чтобы решить, оправдана ли сделка. Есть дополнительные факторы, которые следует учитывать, это похоже на фильтр, позволяющий количественному аналитику сосредоточиться на меньшем количестве акций с более высокой вероятностью.

Переменные

Давайте начнем с настройки переменных рабочего пространства:

https://medium.com/media/6d7f75b5c88888afdab4e4016187aebaПеременные: https://gist.github.com/ugik/3a5eaebd10c2c51b80fc6040fcbc6f70

Обратите внимание на список ETF, которые мы будем проверять. Это может быть любой список, который вам нравится, просто убедитесь, что он точно совпадает со списком захвата данных с тем же именем, чтобы у вас были данные для каждого капитала. Конечно, обязательно соберите все данные, прежде чем переходить к этому разделу. Загрузка данных за год по этим акциям займет несколько секунд.

Создать стратегию

Теперь мы можем настроить нашу торговую стратегию.

https://medium.com/media/408765375a0ef23d6a0ac2de4af96837Стратегия: https://gist.github.com/ugik/7cabb8172fc3ebb0fd7059c76d76ed36

Типичный класс стратегий Backtrader содержит следующее:

  • params (в нашем случае maperiod (Moving Average Period) по умолчанию)
  • log (простой способ вывода информации в журнал во время выполнения)
  • __init__ (код инициализации класса)
  • notify_order (занимается логистикой выполнения заказа)
  • notify_trade (обрабатывает подтверждение сделки)
  • далее (на каждом временном интервале принимайте решение о том, торговать или нет)
  • Остановка (заворачивание)

Инициализируем движок индикатором Hull Moving Average (HMA):

self.hma = bt.indicators.HullMovingAverage(self.datas[0], period=self.params.maperiod)

Существует много типов скользящих средних, самым основным из которых является простая скользящая средняя (SMA). Из всех скользящих средних SMA больше всего отстает от цены. Экспоненциальные и взвешенные скользящие средние были разработаны для устранения этого отставания, уделяя больше внимания более свежим данным. Скользящая средняя Халла (HMA), разработанная Аланом Халлом в 2005 году, является чрезвычайно быстрой и плавной скользящей средней. HMA почти полностью устраняет запаздывание и в то же время улучшает сглаживание.

Подробнее о HMA читайте здесь.

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

Формула HMA

Не нужно изобретать математический велосипед.

Оптимизация периода скользящей средней

Теперь мы можем закодировать раздел __main__.

Это будет содержать 2 раздела, первый будет оптимизировать параметры нашего индикатора. Это период для HMA.

Это направлено на то, чтобы ответить на следующий важный вопрос: учитывая сигналы для нашего индикатора (индикаторов) за последние месяцы, какой период дает наилучшие результаты?

https://medium.com/media/43f373606ea3c6466fdcc28c7c785e7f

Мы будем использовать грубую силу, потому что можем. За считанные секунды движок покажет оптимальный период MA для индикатора(ов), выбранного на наших данных.

У нас будет cerebro через ряд периодов:

strats = cerebro.optstrategy( TestStrategy, maperiod=range(15, 30))

Далее загружаем наши данные:

data = bt.feeds.YahooFinanceCSVData(…)

Другие основные функции настройки, включая настройку размера сделки 1 акции:

cerebro.addsizer(bt.sizers.FixedSize, stake=1)

А пока можно не обращать внимания на расчеты комиссий:

cerebro.broker.setcommission(комиссия=0.0)

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

Запустите бэктест

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

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

https://medium.com/media/0d94eb45f5235194a674395176457403

Обратите внимание, что раздел 2 примерно такой же, как и раздел 1, за исключением того, что на этот раз мы используем не диапазон параметров, а скорее оптимальный:

cerebro.addstrategy(TestStrategy, maperiod = bestPeriod)

ЛучшийПериод был установлен в разделе 1.

Завершите скринер

Теперь мы готовы вывести любые/все акции с недавней потенциально действенной сделкой.

https://medium.com/media/c150b7c67e9c2247d3da398e306cdc49

Наконец, мы строим график сигнала с:

cerebro.plot(numfigs=1)

График показан непосредственно в записной книжке Jupyter

В это время фондовые рынки падали в течение 3 дней подряд, этот капитал: MYY является инверсным ETF на акции S&P Midcap. Он растет, когда соответствующие акции снижаются, отсюда и график.

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

Вот тот же график в TradingView, снова с HMA и сигналом [B] в начале недели.

График TradingView того же эквити/тайма/сигнала
Крупный план сигнала и последующего движения

Предполагая, что кто-то совершил сделку в сигнальный день по выгодной цене для этой торговой сессии, потенциальная прибыль составила почти 9% за 3 дня.

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

В этот день у нас был еще один сигнал для другого инверсного ETF: SH, это КОРОТКАЯ позиция по S&P 500. Он тоже вырос по тем же причинам, сигнал был сгенерирован за день до запуска этого скринера.

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

Если вам интересно, длительный спад, предшествовавший этому недавнему действию, был бы применим к обратному ETF, в данном случае к тикеру: SPY

Мы можем четко видеть сигналы на графике SH (который является перевернутым видом SPY)

Во время этого длительного нисходящего тренда (восходящего тренда для его зеркального ETF) было 2 ложных сигнала в противоположном направлении, которые легко могли иметь СТОП-ЛОСС, чтобы избежать значительных потерь.

Если вам интересно узнать о потенциале этого спада в начале года по этому капиталу: ~ 12% (10 октября 2019 г. — 22 января 2020 г.)

Там у нас есть скринер акций, написанный на Python с использованием движка Backtrader.

Несколько примечательных предметов

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

Движок использует консервативную цену покупки и продажи для смоделированных сделок, учитывая высокие/низкие значения этой торговой сессии.

Большая часть торговой доходности связана с деталями исполнения сделок с обеих сторон каждой сделки.

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

Нет ограничений на то, сколько акций и сколько индикаторов можно быстро проверить.

Источник