Выбор используемых индикаторов является одним из наиболее важных и сложных аспектов построения успешной торговой стратегии.
Существуют тысячи различных индикаторов, большинство индикаторов имеет множество настроек, из которых можно составить практически бесконечное количество комбинаций. Протестировать каждую комбинацию невозможно, поэтому многие трейдеры выбирают для построения своей стратегии случайный набор индикаторов.
К счастью, такой процесс, известный как «отбор признаков» (feature selection), является очень хорошо изученной темой в мире машинного обучения. В этом посте мы будем использовать популярный метод, известный как «метод обертки» (wrapper method), который использует метод опорных векторов (SVM) и поиск восхождением к вершине (hill climbing), чтобы найти надежное подмножество индикаторов для использования в торговой стратегии.
Выбор функции с помощью машинного обучения: метод обертки и поиск восхождением к вершине
Выбор из почти неограниченного числа возможных комбинаций индикаторов для использования в вашей стратегии может быть очень сложным. Тем не менее, специалисты по машинному обучению и ученые-аналитики долгое время пытались ее решить и разработали широкий спектр инструментов и методов, которые вам помогут в решении этой задачи.
Одним из популярных методов является метод обертки. Метод обертки использует алгоритм машинного обучения для оценки каждого подмножества индикаторов. Основным преимуществом этого метода, в отличие от оценки каждого индикатора по отдельности, является то, что мы можем найти отношения и зависимости между индикаторами. Например, 14-периодный RSI или только 30-периодный CCI по отдельности могут не быть хорошими предикторами, но в совокупности они могут дать некоторую ценную информацию.
Следующий вопрос: как вы определите, какие подмножества индикаторов должны оцениваться? Если вы смотрите только на несколько индикаторов, то можно попытаться перебрать все возможные комбинации, но выбор, например, 3 индикаторов для использования в стратегии из 15 дает более чем 450 различных возможных комбинаций! Другие методы либо ранжируют индикаторы на основе определенного показателя эффективности, например корреляции, либо начинаются с полного или пустого набора и добавляют/убирают индикаторы по одному. Эти типы поиска известны как «жадные», что означает, что они могут искать только в одном направлении, например от сильной корреляции к слабой, но при этом могут пропустить некоторые важные соотношения между индикаторами.
Один из методов, который пытается обойти этот недостаток, известен как поиск восхождением к вершине. Он начинается со случайного подмножества индикаторов и затем оценивает все «соседние» комбинации, выбирая наилучшую. Хотя это позволяет нам находить интересные соотношения между индикаторами, есть шанс, что мы застрянем в так называемом «локальном максимуме», то есть это может быть просто лучшая комбинация соседей, но не обязательно лучшая общая комбинация во всем множестве. Чтобы обойти этот недостаток, мы можем запустить поиск несколько раз, чтобы увидеть, какие паттерны появляются в лучших соседних подмножествах.
В этой статье мы будем использовать метод опорных векторов (который мы ранее использовали для построения стратегии RSI) и повторим поиск восхождением к вершине 10 раз, чтобы найти лучшее подмножество индикаторов.
Выбор индикаторов
Даже при использовании вышеописанных методов нам по-прежнему необходимо определить пространство признаков для поиска. Здесь вам поможет ваш опыт. Вы можете не знать лучший таймфрейм, но у вас, скорее всего, есть набор «любимых» индикаторов, которые вы хорошо знаете. Вы можете дать процессу поиска хорошую начальную точку, выбрав осмысленные, релевантные индикаторы, которые вы понимаете.
Для простоты мы начнем с 5 различных и широко используемых базовых индикаторов: SMA, EMA, RSI, CCI и MACD.
Для создания признаков мы будем использовать различные периоды и соотношения этих индикаторов.
Например, ниже 20 различных "признаков":
Price - SMA(5) Price - SMA(30)
Price - SMA(50) SMA(5) - SMA(30)
SMA(5) - SMA(50) SMA(30) - SMA(50)
Price - EMA(5) Price - EMA(30)
Price - EMA(50) EMA(5) - EMA(30)
EMA(5) - EMA(50) EMA(30) - EMA(50)
RSI(5) RSI(14)
RSI(30) CCI(5)
CCI(14) CCI(30)
MACD_Line MACD_Signal
Можно видеть, что всего 5 индикаторов позволяет создать огромное количество комбинаций. Давайте начнем строить нашу модель. Мы оценим полезность этих 20 признаков при построении стратегии.
Построение модели
Теперь, когда у нас есть наши признаки, мы можем построить модель в R (при работе с SVM важно нормализовать данные: вы можете скачать исходные и нормализованные данные, которые мы вводим в модель, здесь).
Во-первых, нам необходимо установить необходимые библиотеки:
install.packages('FSelector') # библиотека для поиска восхождением к вершине
library(FSelector)
install.packages('e1071') # библиотека для SVM
library(e1071)
install.packages('ggplot2') # библиотека для построения графиков
library(ggplot2)
Загружаем нормализованные данные из файла.
Далее разделим данные на обучающую и тестовую выборки. Мы будем использовать 2/3 данных для построения модели и 1/3 для тестирования.
Breakpoint <- nrow(Model_Data)*(2 / 3)
Training<-Model_Data[1:Breakpoint, ]
Validation<-Model_Data[(Breakpoint+1):nrow(Model_Data), ]
Затем нам нужно будет построить функцию, которая оценивает каждое подмножество с помощью SVM. Мы разделим нашу обучающую выборку на еще одну обучающую и тестовую выборки, чтобы оценить эти модели на данных, которые не использовались в процессе их построения. Это еще одна проверка, чтобы убедиться, что мы не переобучим модель.
SVM_Evaluator<-function(subset){
data<-Training
break_point<-(2/3)*nrow(data)
Training_Set<-data[1:break_point,]
Test_Set<-data[(break_point+1):nrow(data),]
SVM<-svm(Predicted_Class~.,data=Training_Set, kernel="radial",cost=1,gamma=1/20)
SVM_Predictions<-predict(SVM,Test_Set,type="class")
Accuracy<-sum(SVM_Predictions == Test_Set$Predicted_Class)/nrow(Test_Set)
return(Accuracy)
}
Теперь мы можем запустить поиск восхождением к вершине.
set.seed(2)
Attribute_Names<-names(Training)[-ncol(Training)]
Hill_Climbing<-hill.climbing.search(Attribute_Names,SVM_Evaluator)
Далее необходимо повторить поиск 10 раз, чтобы стабилизировать результаты (это займет пару минут).
set.seed(2)
Replication_Test <-replicate(10,hill.climbing.search(Attribute_Names,SVM_Evaluator))
Давайте погрузимся в полученные результаты и выясним, какие из индикаторов чаще оказываются в лучших подмножествах:
Indicator_Count<-function(names){
as.numeric(length(grep(names,Replication_Test)))
}
Distribution<-lapply(Attribute_Names,Indicator_Count)
Attribute_Names_df<-as.data.frame(Attribute_Names)
Distribution_df<-t(data.frame(Distribution))
Indicator_Distribution<-data.frame(Attribute_Names_df,Distribution_df,row.names=NULL)
ggplot(Indicator_Distribution,aes(x=Attribute_Names,y=Distribution_df))+geom_bar(fill="blue",stat="identity")+ theme(axis.text.x = element_text (size=10,angle=90,color="black"), axis.title.x=element_text(size=15),axis.title.y=element_text(size=15),title=element_text(size=20))+labs(y="Appearances in Subsets",x="Indicator Name",title="Indicator Subset Frequency")+ylim(c(0,10))
Интересно, что расстояние между ценой и 5-периодным простым скользящим средним («Price_Minus_SMA_5») появилось в 9 из 10 подмножеств, за ним следуют расстояние между ценой и 5-периодном экспоненциальном скользящем среднем ("Price_Minus_EMA_5 ") и расстояние между ценой и 50-периодной экспоненциальной скользящей средней (« Price_Minus_EMA_50 »), которые фигурируют в 8 из 10 подмножеств. Поскольку мы хотим предсказать только следующую свечу, имеет смысл то, что лучше всего будут работать более короткие периоды, но интересно, что простая скользящая средняя была выбрана в большем количестве подмножеств, чем экспоненциальная скользящая средняя.
Теперь давайте посмотрим количество индикаторов в каждом подмножестве:
summary(Replication_Test)
Итак, в пятой и восьмой итерации нашего поиска лучшие подмножества состояли из 6 индикаторов, но я склоняюсь к подмножествам с меньшим количеством индикаторов, В 4-й итерации было наименьшее подмножество, включающее нашу главную функцию - Price_Minus_SMA_5, поэтому давайте примем его как нашу окончательную модель:
Replication_Test[ [ 4 ] ]
PRICE_Minus_SMA_5 | PRICE_Minus_SMA_30 | PRICE_Minus_SMA_50 |
PRICE_Minus_EMA_30 | CCI_5 | CCI_30 |
MACD_Signal |
Мы построим окончательную модель по всей обучающей выборке и протестируем его на нашей еще доступной тестовой выборке:
SVM_Final<-svm(Predicted_Class~PRICE_Minus_SMA_5+PRICE_Minus_SMA_30+PRICE_Minus_SMA_50+PRICE_Minus_EMA_30+CCI_5+CCI_30+MACD_Signal,data=Training, kernel="radial",cost=1,gamma=1/20)
SVM_Predictions_Final<-predict(SVM_Final,Validation,type="class") # Predict over the Validation set
Accuracy_Final<- Accuracy<-sum(SVM_Predictions_Final == Validation$Predicted_Class) /nrow(Validation)
Отлично, на нашей тестовой выборке мы смогли получить точность 53%! Хотя это значение не кажется таким уж большим, нашей целью был поиск надежного подмножества индикаторов. Теперь у нас есть базовая точность 53%, которую мы можем использовать для дальнейшего построения и улучшения нашей стратегии.
Комментариев нет:
Отправить комментарий