При торговле по стратегии «Парного трейдинга» часто встречаются пары🎏, где цены каждого актива сильно отличаются друг от друга. Для получения лучшей доходности📈 и сокращения риска📉 необходимо правильно определить размер⚖ сделки по каждому активу.
Сегодня мы рассмотрим расчет дельты позиций используя метод наименьших квадратов (МНК).
Тестировать будем в Quantopian, а код пишем на Python🐍.
🗃Краткая справка
- За основу статьи взяты материалы с Quantopian.
- Стратегия «Парного трейдинга» подробно описана в этой статье.
- Поиск пар для торговли можно изучить здесь.
- Выбор основания для сигналов z-оценки здесь.
- Регрессионный анализ описан в Вики.
- Линейная регрессия доступна в Вики.
- Метод Наименьших Квадратов (МНК, Ordinary Least Squares, OLS) описан в Вики.
Тестировать будем на парах, найденных в прошлых статьях:
- CIT, STT
- ALNY, DATA
- DRE, O
🎓Зачем нам линейная регрессия?
Мы нашли пару активов, которые имеют связь. Следующим шагом мы должны определить пропорции этой связи. В этом нам поможет регрессионный анализ зависимости цен одного актива относительно цен другого.
Слева на графике показан разброс значений зависимости цен хорошей пары, а справа — плохой пары. Прямая линия на каждом графике — это регрессия по найденным неизвестным. Линия строится по формуле:
a — смещение по оси Y.
b — угол наклона. Эту величину мы будем использовать для расчета размера позиций.
🛠Алгоритм расчета размера позиции
Для получения величины зависимости мы будем использовать Python-пакет statsmodels. Ниже исходный код использования OLS метода:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
import statsmodels.api as sm # ... def hedge_ratio(Y, X, add_const=True): if add_const: # добавление постоянной величины для нахождения "a" X = sm.add_constant(X) model = sm.OLS(Y, X).fit() # модель содержит оба параметра: "a" и "b" # нам интересен только "b" return model.params[1] model = sm.OLS(Y, X).fit() return model.params.values |
В массив X необходимо добавить колонку с постоянной величиной, для нахождения значения a.
В алгоритме мы используем 20-дневный период для построения регрессии, чтобы зависимость была наиболее актуальной. Сигнальную z-оценку мы также построим относительно значений угла регресии. Исходный код алгоритма:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
# ... # используем OLS для расчета размера позиций context.lookback = 20 context.z_window = 20 Y = hist['close'][stocks[0]][-context.lookback:] X = hist['close'][stocks[1]][-context.lookback:] try: hedge = hedge_ratio(Y, X, add_const=True) except ValueError as e: log.debug(e) return # собираем историю найденных значений context.hedgeRatioTS = np.append(context.hedgeRatioTS, hedge) # при недостаточной истории данных, выходим if context.hedgeRatioTS.size < context.HRlag: return # получаем величину отношения размера позиции за прошлый день, # считаем величину спреда и добавляем в историю hedge = context.hedgeRatioTS[-context.HRlag] context.spread = np.append(context.spread, Y[-1] - hedge * X[-1]) # z-оценка на основе истории величины спреда z_hedge = 0 if context.spread.size > context.z_window: # оставляем ограниченную длину истории величины спреда spreads = context.spread[-context.z_window:] z_hedge = (spreads[-1] - spreads.mean()) / spreads.std() # ... # пример ордеров order_target_percent(stocks[0], -1) order_target_percent(stocks[1], 1*hedge) |
👎CIT, STT
На всех графиках под доходностью показана стоимость открытых позиций в обе стороны. Результат торговли с помощью МНК (верхний график) значительно хуже и обладает большей просадкой относительно торговли на равные суммы (следующий график).
На верхнем графике:
- торговля с помощью OLS;
- сигналы по z-оценке на основе OLS;
- без проверки коинтеграции.
На нижнем графике:
- торговля позициями на равные суммы;
- сигналы по z-оценке на основе доходности;
- фильтр по наличию коинтеграции за предыдущие 120 дней.
👎ALNY, DATA
На этой паре использование МНК принесло только проблемы. По датам видно, что здесь может помочь фильтр по коинтеграции спреда доходности, но это уже переоптимизация.
👎DRE, O
На последней паре также результаты плачевны. Предположу, что связано это с природой пар, о чем подробнее в выводах.
🎁Код в студию
Вопросы по коду пишите в комментариях💬.
Исходный код доступен в репозитории.
🏁Вывод
Результаты разочаровали. Но это можно было предвидеть взглянув на следующие графики. Это наложение цен обоих активов одной из пар друг на друга: слева — без изменений; центр — использование коэффициента регрессии; справа — использование отношения цен друг к другу в первый день. Вряд ли коэффициент, полученный при помощи МНК, может быть полезен в определении размеров позиций.
Как объяснить успех торговли равными долями? Данные пары были найдены на спреде относительных значений. То есть мы сравнивали спреды ежедневных изменений цены и ушли от самих цен. Торговать таким спредом достаточно на равные суммы. Дополнительно мы постоянно проверяем стационарность спреда.
Интересной находкой стал коэффициент смешанной корреляции (показан на графике регрессии в начале статьи). Как мы видим, у хорошей пары он ближе к единице. Это может помочь нам фильтровать пары при поиске для торговли. Подробнее об этом я напишу в следующей статье.
💬В комментариях напишите, какие еще могут быть проблемы плохой результативности? Где я мог допустить ошибку? Что можно изменить?
Автор Quantrum.me
Telegram-канал📣: @quantiki
Подбор и тестирование портфелей. Подключение стратегий к IB.