Привет! Сегодня не про результаты, а про методы. Закончил писать базовый функционал библиотеки для количественных исследований. Вот что из него можно выжать:
- Моделирование портфелей по кросс-секции и временным рядам;
- Квантильная методика формирования портфелей в % от выборки или фиксированное число инструментов;
- Возможность гибко задавать веса в портфеле по дополнительному фактору (почти smart beta);
- Можно вырывать данные для аналитики на каждом промежуточном этапе: сделки, размер позиций, комиссии, доходность портфелей;
- Возможность относительно точно учесть комиссионные расходы;
- Пока самая простая визуализация и метрики.
Как выглядит итоговая отрисовка:
Небольшая предыстория или зачем писать свой тестер
Не являясь базовым программистом, я пользовался готовыми решениями для бэктестов и особенно долго засиживался на платформе Quantopian. В прошлом году компания не получила нового транша от инвесторов и объявила о закрытии. Вместе с ней сгинул и весь написанный код, а знания синтаксиса несуществующей платформы близки по полезности к 1С-программированию при переезде в долину.
Поработав с другими сервисами, понял, что их существенные недостатки можно разделить на 3 группы:
- Отсутствие гибкости в плане выбора параметров и получения промежуточных результатов;
- Работа в закрытой экосистеме из данных и тестов. Проблемно загрузить много своих альтернативных данных или существенно поменять логику тестов;
- Отсутствие системного тестирования рынка и работа по отдельным инструментам.
Последний пункт наиболее критичный. Мне хотелось тестировать технические индикаторы или отбор акций по EV/EBITDA не на выборке из 1/2/25 бумаг, а на всех 500+ акциях, которые обращались на Мосбирже или 10к+ на NYSE. Данных и идей будет много, поэтому программа должна быть умеренно быстрой. Остановился на векторных вычислениях в numpy.
Логика расчетов не убойная и ее не сложно переписать на ваш любимый язык. Пример c расчетом весов портфеля по заданному фактору. Например, это может быть рыночная капитализация:
Как можно тестировать свои идеи в PQR
- Загружаем библиотеку и смотрим примеры использования в main.py и в папке с примерами. Там ноутбуки с простыми идеями. Будут пополняться;
- Находим данные по ценам и факторам для множества компаний. Цена тоже может быть фактором, если ее преобразовать в изменение или другой показатель. Допустим, выбраны мультипликаторы P/E и месячные цены закрытия для 200 российских акций;
- Составляем одинаковые по размеру таблицы (матрицы) в экселе/csv/txt или в чем угодно, что сможете загрузить в программу. По вертикальной оси будут названия компаний, а по вертикальной временной ряд. Матрицы обязательно должны быть одинаковы по размеру;
- Выбираем параметры тестирования: сколько периодов мы наблюдаем за фактором перед покупкой и сколько будем держать позиции. Устанавливаем лаг, комиссии и требуемый % акций из выборки в каждом портфеле;
- Подаем данные по P/E в функцию get_factor и получаем готовые ряды для дальнейших тестов. Все расчеты по укрощению lookahead bias выполняются здесь. Дополнительно сдвигать ряды не нужно;
- Задаем фильтры (опционально). Например, выкидываем из выборки компании со среднедневным объемом торгов за прошлый месяц менее 100 млн рублей;
- Считаем позиции по отдельным бумагам в каждом портфеле. Эти бинарные матрицы уже почти портфели, но не хватает весов;
- Задаем способ расчета весов в портфеле. Если выбираете взвешенный по фактору, то этот фактор нужно загрузить, не забывая про размер матрицы;
- Опционально считаем комиссии;
- Подаем все полученные данные в последний скрипт для расчета доходности портфеля, метрик и сравнения с бенчмарком. Если есть интересная альфа – можно углубиться в отдельные портфели и подумать над усложнением стратегии. Если нет – копаем дальше.
В папке examples на Гитхабе есть ноутбук с примером расчета небольших портфелей из FAANG и анти-FAANG акций. Пример ознакомительный и по понятным причинам выкладывать большие массивы вендоров в открытый доступ не могу.
Почему квантильная методика так важна
Количество акций в отдельные периоды на ЕМ сильно отличается, особенно если используете фильтры по ликвидности. Количество бумаг на нашей бирже в 1997 и 2021 не подлежит сравнению. 10 портфелей по 5 ликвидных (относительно) акций это очень много для того периода и мало для текущего. Квантильный способ удобен тем, что мы всегда берем одинаковый относительный охват рынка и получаем полную картину на каждый период.
Интересно наблюдать, как меняется результативность портфеля от первых 10% с наименьшим P/E, затем следующим 10% и т.д. Если альфа ломается при малейших изменениях параметров – тревожный признак. U-образная доходность портфелей – уже интереснее.
Что будет и чего не будет в будущих версиях
- Расширю количество метрик и графиков, добавлю мультифакторные стратегии и способы расчета бенчмарка
- Возможно будет коллаборация с подгрузкой данных из бесплатных источников;
- Больше статистики и аналитики по карте портфелей;
- Точно не будет всего что касается исполнения ордеров, производных инструментов и микроструктуры рынка. Это инструмент для первых прогонок стратегий. Копать дальше и торговать лучше более подходящим инструментом.
Ссылку на гитхаб с программой выложил в телеге :) https://t.me/sentimetrica
В следующий раз разберу принцип работы на конкретных примерах по нашему рынку. Идеи и пожелания по инструменту @atomtosov
Так же можно использовать zipline локально
Есть еще альтернатива с quantconnect, тоже доступна для локальной работы
Понимаю, что свой велосипед приятнее и роднее )
Но все же рекомендую глянуть на готовые решения, если вдруг пока не довелось, возможно, они закроют большую часть потребностей
broker25, приветствую. Делистингованные компании тоже есть(свойство delisting) Вот ссылка на доку по ресерчу. www.quantconnect.com/docs/research/fundamental-data
Качать данные… наверно можно исхитрится, чтобы отправлять себе почту. Но по сути это ненужно.
Вот пример кода по отбору и сделкам на основе балансовой стоимости. Пример на питоне. На С# переключать не стал, так как сейчас идет бектест, чтобы ничего не сломалось. Но старожилы квантконекта рекомендуют использовать С#, так как бектесты работают в десятки раз быстрее. К сожалению отступы не копируются на смарт лабе. Но зная вас, думаю общее впечатление себе вы сможете составить.
_________________________________
from datetime import timedelta
from QuantConnect.Data.UniverseSelection import *
from Selection.FundamentalUniverseSelectionModel import FundamentalUniverseSelectionModel
class LiquidValueStocks(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2017, 5, 15)
self.SetEndDate(2017, 7, 15)
self.SetCash(100000)
self.UniverseSettings.Resolution = Resolution.Hour
self.AddUniverseSelection(LiquidValueUniverseSelectionModel())
#1. Create and instance of the LongShortEYAlphaModel
self.AddAlpha(LongShortEYAlphaModel())
self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel())
self.SetExecution(ImmediateExecutionModel())
class LiquidValueUniverseSelectionModel(FundamentalUniverseSelectionModel):
def __init__(self):
super().__init__(True, None, None)
self.lastMonth = -1
def SelectCoarse(self, algorithm, coarse):
if self.lastMonth == algorithm.Time.month:
return Universe.Unchanged
self.lastMonth = algorithm.Time.month
sortedByDollarVolume = sorted([x for x in coarse if x.HasFundamentalData],
key=lambda x: x.DollarVolume, reverse=True)
return [x.Symbol for x in sortedByDollarVolume[:100]]
def SelectFine(self, algorithm, fine):
sortedByYields = sorted(fine, key=lambda f: f.ValuationRatios.EarningYield, reverse=True)
universe = sortedByYields[:10] + sortedByYields[-10:]
return [f.Symbol for f in universe]
# Define the LongShortAlphaModel class
class LongShortEYAlphaModel(AlphaModel):
def __init__(self):
self.lastMonth = -1
def Update(self, algorithm, data):
insights = []
#2. If else statement to emit signals once a month
if self.lastMonth == algorithm.Time.month:
return insights
self.lastMonth = algorithm.Time.month
#3. For loop to emit insights with insight directions
# based on whether earnings yield is greater or less than zero once a month
for security in algorithm.ActiveSecurities.Values:
direction = 1 if security.Fundamentals.ValuationRatios.EarningYield > 0 else -1
insights.append(Insight.Price(security.Symbol, timedelta(28), direction))
return insights
broker25, а ничего качать не надо. Там же webIDE. При бектестах дается бесплатная виртуалка. Все деплоится нажатием кнопки. Раздел рисерч предназначен для быстрого поиска идей(я новенький в квантконекте, по этому не разобрался нафиг он нужен когда есть webIDE, аж с двумя подходами: класcическим и на основе нового фремворка). Я пока пытаюсь разобраться с классическим подходом. Там вобще все просто относительно. Но я не профессиональный прогер, поэтому иногда возникают глупые затыки. Но если уж такой тупень как я, смог начать в этом потихоньку разбираться, то вы разберетесь очень быстро.
В открытых источниках есть проблема с компаниями которые больше не торгуются, но есть недорогие платные, например, tiingo за 10$ /мес
Есть еще market-archive.appspot.com, не проверял лично, но на сайте указано, что за 60$ можно получить дневки по всем акциям, в том числе и снятым с листинга
Ковырял тут otcmarkets, на удивление, там можно вытащить историю не только по otc рынку, но и по основному
Подергал недокументированное апи на счет всяких эплов и фэйсбуков
Годовые отчеты есть до 96 года, квартальные только до 2015