Кодирование алгоритма случайного леса для прогнозирования ежедневного направления движения индекса S & P500 через соотношение пут / колл.

Основная идея статьи: мы создадим алгоритм случайного леса, который предсказывает направление соотношения пут / колл на завтра. Используя эту информацию, мы попытаемся предсказать завтрашнюю доходность индекса S & P500. Следовательно, мы не будем предсказывать направление фондового рынка, скорее мы попытаемся предсказать направление временного ряда, который коррелирует с индексом S & P500.

Я только что опубликовал новую книгу после успеха Новые технические индикаторы в Python. Он содержит более полное описание и добавление сложных торговых стратегий со страницей Github, посвященной постоянно обновляемому коду. Если вы считаете, что это вас заинтересует, не стесняйтесь перейти по приведенной ниже ссылке или если вы предпочитаете купить версию в формате PDF, вы можете связаться со мной в Linkedin.



Но обо всем по порядку, опцион колл - это право купить определенный актив в будущем по определенной цене, а опцион пут - это право продать определенный актив за будущее по заранее определенной цене.

Следовательно, когда вы покупаете колл, вы можете купить что-то позже, а когда вы покупаете пут, вы можете что-то продать позже. Каждая транзакция имеет две стороны, поэтому, когда вы покупаете колл или пут, кто-то другой продает их вам. Это дает две другие позиции, которые могут быть открыты по опционам: продажа колл и продажа пут. Индикатор пут / колл работает с покупателями опционов и измеряет количество покупателей пут, деленное на количество покупателей колл. Это дает нам представление о настроениях участников рынка в отношении указанного капитала (в нашем случае это будет фондовый рынок США).

более высокое соотношение пут / колл означает, что имеется больше покупателей пут (трейдеры делают ставку на снижение актива), а более низкое соотношение пут / колл означает больше колл. покупатели (трейдеры делают ставку на рост актива). Известный способ использования этого коэффициента при анализе настроений рынка - оценка следующих сценариев:

  • Рост коэффициента означает медвежье настроение. Профессионалы «чувствуют», что рынок пойдет ниже.
  • Падение коэффициента означает бычье настроение. Профессионалы «чувствуют», что рынок пойдет вверх.

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

План атаки

Как мы это сделаем? Сначала мы начнем с простой известной стратегии, в которой мы покупаем рынок, когда пут / колл достигает 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

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

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.069
Hit ratio            =  70.77 %
Gross return         =  418.0 %
Expectancy           =  32.17
Realized RR          =  1.27
Buy:Sell ratio       =  108 : 23
Win% Buy:Sell        =  74.0 % : 52.0 %

Некоторые наблюдения, которые необходимо сделать, просто взглянув на диаграмму сигналов: количество длинных сигналов заметно больше, чем количество коротких сигналов, и качество сигнала кажется лучше. Длинные сигналы, кажется, хорошо отражают дно коррекций и консолидаций. Кривая справедливости стратегии в некоторой степени удовлетворительна, но все же не на 100% отражает реальность (действительно ли мы знали, что эта стратегия будет работать еще в 2006 году, если бы у нас еще не было результатов?), Но все же интересно наблюдать если он будет продолжать вести себя таким же образом в будущем. Мы также отмечаем, что с использованием 20-дневного периода удержания, а также тенденции рынков к росту, этот факт мог подтолкнуть нас к тому, чтобы стать более прибыльными. Тем не менее, редко можно увидеть такую ​​красивую наклонную вверх кривую капитала.

Будет ли эта стратегия работать в обозримом будущем? Трудно сказать, но то, что можно сказать наверняка, займет много времени. Судя по приведенным выше данным, за 13 лет у нас была всего 131 сделка, что составляет 10 сделок в год. Ослабление некоторых условий даст нам 1 сделку в месяц. Может быть неплохо, если разделение портфеля приведет к активной торговле по этой стратегии, если будет проведена дополнительная оптимизация.

Стратегия # 2

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

Прежде чем мы начнем с определения нашего алгоритма и прохождения теста на истории, интересно узнать, насколько хорошо наша модель будет работать в утопическом мире, где мы можем предсказать завтрашнее соотношение пут / колл с 100% точностью ? Другими словами, насколько хорошо мы будем торговать на рынке США, зная отрицательную корреляцию и будучи уверенными в завтрашнем изменении этого отношения?

Таким образом, становится аппетитно видеть, можем ли мы предсказать соотношение пут / колл или нет, увидев эту почти идеальную кривую капитала (валовая доходность около 1,200% с 2006 года и ежедневная торговля на открытии и закрытии. в конце дня). Конечно, если смотреть на вещи в перспективе, мы не собираемся получить такую ​​кривую капитала, и мы даже не уверены, что алгоритм может даже предсказать PCR так хорошо. Но интерес к исследованиям - это то, что заставляет нас двигаться вперед. Факт: я начал писать эту статью, когда создавал алгоритм, поэтому большая часть того, что я написал до сих пор, была написана до начала бэк-тестов. А теперь давайте начнем с серьезного.

Алгоритм случайного леса является частью более широкого типа алгоритмов, называемых методами ансамбля. С точки зрения непрофессионала, многие деревья решений образуют случайный лес, который является разновидностью ансамблевых методов. Но какова интуиция дерева решений, если не вдаваться в технические детали?

Если вас также интересуют другие технические индикаторы и использование Python для создания стратегий, то моя книга-бестселлер по техническим индикаторам может вас заинтересовать:



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

Деревья решений разбивают набор данных на более мелкие подмножества с использованием условий для окончательного получения оценки вероятности. Первое дерево называется корневым узлом, а следующие за ним (выходящие из него) называются узлами принятия решений. Алгоритм, используемый для перебора деревьев для вычисления энтропии, называется Итерационный дихотомизатор 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

Переменная деревья является ключом к алгоритму случайного леса. Чем их больше, тем сложнее будет модель. В нашем примере мы выберем 20 деревьев. Переменная запаздывания - это то, как далеко в прошлом мы будем включать в формулу прогноза. Значение три означает, что последние 3 значения изменения PCR будут использоваться для прогнозирования завтрашних изменений.

# Parameters
investment     = 1000                  
trees          = 20
lag            = 2

Итак, какие переменные будет использовать алгоритм случайного леса для прогнозирования завтрашнего ПЦР? Как было сказано выше, мы будем использовать технику, называемую авторегрессией, в которой запаздывающие значения используются в качестве независимых переменных. Это означает, что сегодняшнее и вчерашнее изменение 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.209
Hit ratio            =  51.4 %
Gross return         =  83.0 %
Expectancy           =  1.67
Realized RR          =  1.14

Хорошая новость об алгоритме заключается в том, что в нем нет предвзятости. Соотношение длинных и коротких позиций составляет около 1,0 (это означает, что ордеров на покупку столько, сколько ордеров на продажу).

Заключение

После проведения бэк-тестов мы можем сделать следующие наблюдения:

  • Идеальное предсказание соотношения пут / колл даст нам утопическую стратегию индексации.
  • Результаты первой стратегии показали, что PCR может добавить некоторую ценность в торговле, если она близка к экстремальной. Сигналы, а также производительность показывают некоторые временные характеристики. Однако длительное преобладание делает основную стратегию ПЦР необъективной. Я бы рекомендовал сохранить его как инструмент для помощи в принятии решений. Например, трейдер, желающий открыть длинную позицию на фондовом рынке США, и PCR показывает верхние экстремальные значения. Это могло быть подтверждением существующей судимости.
  • Результаты второй стратегии показали, что оптимизация необходима для улучшения модели, поскольку чистый случайный лес всего с 10 деревьями мало что дает для прогнозирования направления фондового рынка с помощью PCR.
  • Что еще? Библиотека Sklearn имеет множество алгоритмов регрессии. Мы не ограничены только использованием алгоритма случайного леса. Мы можем попробовать столько, сколько захотим, и усреднить их прогнозы, чтобы создать еще лучшую модель. Возможности безграничны.
# The adder function seen above. It adds a number of desired columns to a dataset
def 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