Кодирование алгоритма случайного леса для прогнозирования дневного направления S&P500 через соотношение пут/колл.
Основная идея статьи: мы создадим алгоритм случайного леса, который предсказывает направление отношения пут/колл на завтра. Используя эту информацию, мы попытаемся предсказать завтрашнюю доходность S&P500. Следовательно, мы не будем предсказывать направление фондового рынка, скорее мы попытаемся предсказать направление временного ряда, коррелирующего с S&P500.
Во-первых, колл-опцион — это право купить определенный актив в будущем по определенной цене, а пут-опцион — это право продать определенный актив в будущем. будущее по заранее оговоренной цене.
Следовательно, когда вы покупаете колл, вы можете купить что-то позже, а когда вы покупаете пут, вы можете что-то продать позже. Каждая сделка имеет две стороны, поэтому, когда вы покупаете колл или пут, кто-то другой продает их вам. Это приводит к двум другим позициям, которые можно открывать по опционам: продажа коллов и продажа путов. Индикатор пут/колл имеет дело с покупателями опционов и измеряет количество покупателей пут, деленное на количество покупателей колл. Это дает нам представление об отношении участников рынка к указанной акции (в нашем случае это будет фондовый рынок США).
Более высокоесоотношение пут/колл означает, что больше покупателей пут (трейдеры делают ставку на падение актива), а более низкое соотношение пут/колл означает больше коллов. покупатели (трейдеры делают ставку на рост актива). Известный способ использования этого коэффициента при анализе рыночных настроений заключается в оценке следующих сценариев:
- Повышение коэффициента указывает на медвежьи настроения. Профессионалы «чувствуют», что рынок пойдет вниз.
- Падение коэффициента указывает на бычий настрой. Профессионалы «чувствуют», что рынок пойдет вверх.
Предлагают ли рынки опционов информацию для прибыльной торговли спот/фьючерсами? это то, что мы увидим в этом бэк-тесте. Глядя на соотношение пут/колл, мы хотим преобразовать настроения участников рынка в торговые возможности.
План атаки
Как мы это сделаем? Сначала мы начнем с простой известной стратегии, согласно которой мы покупаем рынок, когда цена пут/колл достигает 1,2, и продаем (короткую) рынок, когда Пут/колл достигает 0,65. Период владения составит 20.
После выполнения и анализа этой стратегии мы обратимся к более продвинутой, которая является ядром этого исследования. Можно ли использовать алгоритм машинного обучения для прогнозирования завтрашнего значения соотношения пут/колл и использовать эту информацию для торговли на рынке? Посмотрим, но сначала давайте попробуем более простой ( первое) стратегия. Обратите внимание, что историческая корреляция между изменениями индекса S&P500 и изменениями соотношения пут/колл находится между -0,35 и -0,45.
Стратегия №1
Интуиция этой торговой стратегии заключается в том, что 0,65 и 1,2 являются статистическими экстремумами, и, следовательно, крайние медвежьи настроения около 1,2 обязательно развернутся, и может произойти дно рынка. И наоборот.
Начнем с импорта необходимых библиотек. Обычные, необходимые каждому исследователю временных рядов.
# Importing libraries import matplotlib.pyplot as plt import numpy as np import pandas as pd
Определим необходимые переменные. период_удержания не требует пояснений и показывает, как долго мы будем удерживать позицию во время открытия. Переменная investment — это наш начальный баланс. И, наконец, уровни поддержки и сопротивления — это просто подразумеваемые статистические экстремумы, которые используются в качестве триггеров.
holding_period = 20 investment = 1000 support = 1.2 resistance = 0.65
Теперь, имея файл Excel с именем PCR, мы импортируем его в Python для чтения и дальнейшей очистки.
# Importing data and calculating Data = pd.read_excel('PCR.xlsx') Data = np.array(Data)
Файл Excel будет состоять из двух столбцов, первый из которых представляет собой соотношение пут/колл, а второй — цену закрытия SPX.
Проще говоря, мы будем покупать всякий раз, когда PCR достигает 1,20, и продавать, когда он достигает 0,65.
# Buy/Sell conditions for i in range(len(Data)): try: if Data[i, 0] >= support and Data[i - 1, 0] < support: Data[i + 1, 2] = 1 # We have added a new column elif Data[i, 0] <= resistance and Data[i - 1, 0] > resistance: Data[i + 1, 3] = -1 # We have added a new column else: continue except IndexError: pass
Если мы быстро проверим количество имеющихся у нас позиций и то, являются ли они длинными (ордера на покупку) или короткими (ордера на продажу), то мы можем использовать следующий код:
np.count_nonzero(Data[:, 2]) np.count_nonzero(Data[:, 3])
Это дает нам 108длинных позиций, 23коротких позиций и 131позицию, занятых в общей сложности в период с 2006 по 2019 год (на этом бесплатные данные PCR заканчиваются). ).
Теперь, чтобы просто рассчитать прибыль по сделкам, имея в виду период удержания 20:
# Returns for i in range(len(Data)): try: if Data[i, 2] == 1: Data[i + holding_period, 4] = (Data[i + holding_period, 1] - Data[i, 1]) if Data[i, 3] == -1: Data[i + holding_period, 5] = (Data[i, 1] - Data[i + holding_period, 1]) except IndexError: pass
Сделав все это, мы можем построить графики сигналов и кривой капитала. Обратите внимание, что ретроспективное тестирование было упрощенным и скорее приблизительным, поскольку мы не включали сборы, комиссионные, изменения контракта или инструменты управления рисками.
Со статистикой производительности:
Profit factor = 3.069Hit ratio = 70.77 %Gross return = 418.0 %Expectancy = 32.17Realized RR = 1.27Buy:Sell ratio = 108 : 23Win% Buy:Sell = 74.0 % : 52.0 %
Некоторые наблюдения, которые необходимо сделать, просто взглянув на диаграмму сигналов: количество длинных сигналов заметно выше, чем количество коротких сигналов, и качество сигнала кажется лучше. Длинные сигналы хорошо отражают дно коррекций и консолидаций. Кривая капитала стратегии в чем-то удовлетворяет, но все же не на 100% отражает реальность (знали ли мы, что эта стратегия сработает еще в 2006 году, если бы мы еще не получили результатов?), но тем не менее интересно посмотреть если он будет продолжать вести себя так в будущем. Мы также отмечаем, что с использованием 20-дневного периода удержания, а также тенденции рынков к росту, этот факт мог бы подтолкнуть нас к большей прибыльности. Тем не менее, редко можно увидеть такую красивую восходящую кривую капитала.
Будет ли эта стратегия работать в обозримом будущем? Трудно сказать, но то, что наверняка, потребуется много времени, чтобы узнать. Судя по приведенным выше данным, за 13 лет у нас была только 131 сделка, что составляет 10 сделок в год. Смягчение некоторых условий даст нам 1 сделку в месяц. Возможно, было бы неплохо разделить портфель на части для активной торговли по этой стратегии, предполагая, что будет проведена дополнительная оптимизация.
Стратегия №2
Интуиция этой торговой стратегии заключается в том, что, используя популярный и хорошо известный алгоритм, мы хотим увидеть, является ли соотношение пут/колл стационарным и достаточно предсказуемым, чтобы давать нам точные сигналы для торговли. Затем мы сравним обе стратегии и посмотрим, какая из них эффективнее, а какая хуже.
Прежде чем мы начнем с определения нашего алгоритма и проведения обратного тестирования, интересно узнать, насколько хорошо наша модель будет работать в утопическом мире, где мы можем предсказать завтрашнее соотношение пут/колл с 100% точностью? Другими словами, зная об отрицательной корреляции и будучи уверенными в завтрашнем изменении коэффициента, насколько хорошо мы будем торговать на рынке США?
Таким образом, становится аппетитно видеть, можем ли мы предсказать соотношение пут/колл или нет, увидев эту почти идеальную кривую капитала (валовая доходность около 1200% с 2006 года и при ежедневной торговле на открытии и закрытии). выходит в конце дня). Конечно, чтобы представить ситуацию в перспективе, мы не получим такую кривую капитала, и мы даже не уверены, что алгоритм сможет так хорошо предсказать PCR. Но стремление к исследованиям заставляет нас двигаться вперед. Факт: я начал писать эту статью, когда создавал алгоритм, поэтому большая часть того, что я написал до сих пор, была написана до начала тестирования на исторических данных. Теперь давайте начнем с серьезных вещей.
Алгоритм случайного леса является частью более широкого типа алгоритмов, называемых ансамблевыми методами. С точки зрения непрофессионала, многие деревья решений образуют случайный лес, который представляет собой разновидность ансамблевых методов.Но какова интуиция дерева решений, если не вдаваться в технические детали?
Дерево решений — это контролируемый алгоритм обучения, который подходит как для задач классификации, так и для задач регрессии благодаря своей линейной и нелинейной пригодности.
Деревья решений разбивают набор данных на более мелкие подмножества, используя условия, чтобы окончательно получить оценку вероятности. Первое дерево называется корневым узлом, а следующие за ним (выходящие из него) называются узлами решений. Алгоритм, используемый для перебора деревьев для вычисления энтропии, называется Итеративный дихотомайзер 3 (ID3) и был изобретен Россом Куинланом. Идея здесь в том, что когда вы усредняете множество моделей, вы получаете более плавный и точный прогноз. Вот почему алгоритмы случайного леса хорошо подходят как для задач классификации, так и для задач регрессии. Алгоритм случайного леса — это не что иное, как набор деревьев решений для уменьшения переобучения и усреднения результатов, что дает нам предположительно более высокую точность. Следовательно, дерево решений — это просто случайный лес с одним деревом решений.
Начнем с импорта необходимых библиотек. Первая строка импортирует функцию RandomForestRegressor из sklearn, которую мы будем использовать ниже для прогнозирования PCR.
# Importing libraries from sklearn.ensemble import RandomForestRegressor import matplotlib.pyplot as plt import numpy as np import pandas as pd
Переменная trees является ключом к алгоритму Random Forest, чем их больше, тем сложнее будет модель. В нашем примере мы выберем 20 деревьев. Переменная запаздывания — это то, как далеко в прошлое мы заглянем, чтобы включить его в формулу прогноза. Значение три означает, что последние 3 значения изменения PCR будут использоваться для прогнозирования завтрашнего изменения.
# Parameters investment = 1000 trees = 20 lag = 2
А теперь какие переменные будет использовать алгоритм Random Forest для прогнозирования завтрашнего PCR? Как было сказано чуть выше, мы будем использовать технику, называемую авторегрессией, в которой лаговые значения используются в качестве независимых переменных. Это означает, что сегодняшнее и вчерашнее изменение PCR может помочь нам спрогнозировать завтрашнее изменение (т. е. будет ли оно повышаться или понижаться по сравнению с сегодняшним значением).
Итак, учитывая следующую структуру данных:
Матрица авторегрессии на ПЦР. Крайний слева — самое последнее наблюдение. Идем налево, берем вчерашние наблюдения.
Приведенная выше матрица означает, что если мы возьмем индекс 3 (первая строка), то -0,02 можно объяснить 0,01, -0,07 и 0,06 с учетом расчетного соотношения. Другими словами, первые три столбца — это независимые переменные, которые должны нести некоторую информацию о последнем столбце.
Мы назовем первые три столбца X (независимые переменные) и последний столбец Y (независимая переменная).
# Separating the data Determinant = len(Data.columns) X = Data.iloc[:, 0:Determinant-1].values Y = Data.iloc[:, -1].values Y = np.reshape(Y, (-1, 1))
Итак, теперь давайте возьмем наборы данных X и Y и разделим их на обучающий набор и тестовый набор:
# Splitting the dataset into the Training set and Test set X_train = X[:-projection,] #Training explanatory variables Y_train = Y[:-projection,] #Training predictions X_test = X[-projection:,] #Test explanatory variables Y_test = Y[-projection:,] #Test predictions
Приведенный ниже код определяет функцию «Случайный лес», выбирает количество деревьев (через переменную n_estimators) и соответствует обучающему набору, чтобы получить подразумеваемую связь, которую мы надеемся сохранить в будущем.
# Fitting the model regressor = RandomForestRegressor(n_estimators = trees) regressor.fit(X_train, Y_train.ravel())
Что мы хотим сделать сейчас, так это взять это отношение, дать ему набор данных, аналогичный X_train, и применить прогнозы. К счастью, мы создали наш набор данных X_test со структурой вне выборки. Это должно выглядеть примерно так:
# Predicting the Test set results Prediction = regressor.predict(X_test) #Predict over X_test Prediction = np.reshape(Prediction, (-1, 1)) Real = Y_test
Это даст нам два набора данных: реальные изменения в PCR и наши прогнозы. Давайте объединим их вместе и рассчитаем коэффициент корреляции, чтобы дать нам представление о том, хорошо у нас дела или нет. Хотя коэффициент корреляции ничего не говорит о точности (поскольку величины могут быть достаточно большими, чтобы ее исказить)
Comparison = np.concatenate((Prediction_LR, RealLR), axis = 1) np.corrcoef(Comparison[:,0], Comparison[:,1])
Результат даст нам
# 0.343
Что неплохо для начала. Но насколько хорошо это будет, если мы попробуем торговать S&P500? Давай продолжим. Приведенный ниже код просто применяет стратегию, которая берет наши прогнозы PCR, размещает их параллельно с изменениями в SPX с учетом временной погрешности, а затем проверяет, связан ли отрицательный прогноз до начала дня с положительное изменение SPX в конце дня или нет?
DataSPX = pd.read_excel('PCR.xlsx') DataSPX = np.array(DataSPX) DataSPX = DataSPX[:, 1] DataSPX = np.reshape(DataSPX, (-1, 1)) DataSPX = pd.DataFrame(DataSPX) DataSPX = DataSPX.diff() DataSPX = DataSPX.iloc[1:,].values DataSPX = DataSPX[-projection:,] Combined = np.concatenate((Prediction_LR, DataSPX), axis = 1) Combined = adder(Combined, 4) #Function to add 4 columns (Check end of article) for i in range(len(Combined)): if Combined[i, 0] < 0: Combined[i, 2] = 1 if Combined[i, 0] > 0: Combined[i, 3] = -1 for i in range(len(Combined)): if Combined[i, 2] == 1 and Combined[i, 1] > 0: Combined[i, 4] = Combined[i, 1] if Combined[i, 2] == 1 and Combined[i, 1] < 0: Combined[i, 4] = Combined[i, 1] if Combined[i, 3] == -1 and Combined[i, 1] > 0: Combined[i, 5] = -Combined[i, 1] if Combined[i, 3] == -1 and Combined[i, 1] < 0: Combined[i, 5] = abs(Combined[i, 1])
Profit factor = 1.209Hit ratio = 51.4 %Gross return = 83.0 %Expectancy = 1.67Realized RR = 1.14
Хорошей новостью об алгоритме является то, что он не страдает какой-либо предвзятостью. Соотношение длинных и коротких позиций составляет около 1,0 (это означает, что ордеров на покупку столько же, сколько ордеров на продажу).
Заключение
После проведения бэк-тестов мы можем сделать следующие наблюдения:
- Идеальное предсказание соотношения пут/колл даст нам утопическую индексную стратегию.
- Результаты первой стратегии показали, что PCR может добавить некоторую ценность в торговле, если он близок к экстремуму. Сигналы, а также производительность показывают некоторые временные возможности. Однако длительное преобладание делает базовую стратегию ПЦР необъективной. Я бы порекомендовал сохранить его как инструмент, помогающий в принятии решений. Например, трейдер хочет открыть длинную позицию на фондовом рынке США, а PCR показывает верхние экстремальные значения. Это может быть подтверждением существующей судимости.
- Результаты второй стратегии показали, что оптимизация необходима для улучшения модели, поскольку чистый случайный лес, состоящий всего из 10 деревьев, мало что дает для прогнозирования направления фондового рынка с помощью PCR.
- Что еще? Библиотека Sklearn имеет множество алгоритмов регрессии. Мы не ограничены только использованием алгоритма Random Forest. Мы можем попробовать столько, сколько захотим, и усреднить их прогнозы, чтобы создать еще лучшую модель. Возможности безграничны.
# The adder function seen above. It adds a number of desired columns to a datasetdef adder(Data, times): for i in range(1, times + 1): z = np.zeros((len(Data), 1), dtype = float) Data = np.append(Data, z, axis = 1)return Data
Если вы нашли эту статью полезной, рассмотрите возможность оставить чаевые. Спасибо за внимание и удачи в поиске работы!
Купите мне кофе, чтобы я мог сделать операцию моей кошке: https://www.buymeacoffee.com/botservices