Машинное обучение: что нужно знать о создании стратегий для торговли на бирже

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

Сегодня же речь пойдет об использовании для этих целей технологий дата майнинга и машинного обучения.

В 1996 году компьютер Deep Blue впервые победил чемпиона мира по шахматам. Прошло еще 20 лет и программа AlphaGo победила в серии с лучшим игроком в Го, уступив лишь одну игру. Deep Blue представлял собой модель-ориентированную систему с жестким набором шахматных правил. AlphaGo же использует технологии Data Mining. Это нейронная сеть, обученная на примерах тысячи партий Го. В отличие от шахмат, в этой игре пространство выбора вариантов настолько огромно, что простой перебор не поможет. Поэтому прорыв произошел не за счет совершенствования «железа», а исключительно благодаря новому софту.

Сегодня мы мы рассмотрим подход к использованию дата-майнинга для разработки торговых стратегий, который не подразумевает глубокого анализа рыночных механизмов. Вместо этого он использует информацию из кривой цен и других источников для поиска в ней предсказуемых аномалий. Машинное обучение или «искусственный интеллект» — не всегда обязательная часть подобной стратегии. На практике самым популярным и самым успешным вариантом применения данного метода является работа без привлечения навороченных нейронных сетей или метода опорных векторов.

Принципы машинного обучения

В основе обучающего алгоритма заложена концепция шаблонов. Обычно это исторические данные о ценах. Каждый шаблон состоит из n переменных x1… xn, обычно называемых маркерами предсказания (предикторами) или просто параметрами. В качестве таких предикторов могут выступать ценовой возврат последних n-делений или набор классических индикаторов, а также любые другие функции кривой цен. Каждый шаблон включает целевую величину y — например, прибыль следующей сделки после применения шаблона или следующее движение цены. В процессе обучения алгоритм узнает, как получить целевую величину, основываясь на предикторах. Это знание хранится в структуре данных, именуемой в нашем случае моделью, индивидуальной для каждого алгоритма. Эта модель может быть функцией языка C, описывающей правила прогнозирования, выработанные в процессе обучения. Или это может быть набор соединений в нейронной сети.

Обучение: x1… xn, y => модель
Предсказание: x1… xn, модель => y

Предикторы должны аккуратно обрабатывать информацию, которая необходима для предсказания целевой величины. Они обязаны отвечать двум формальным условиям: все значения этих маркеров должны быть одного порядка (например, -1… +1 для алгоритмов на R или -100… +100 для алгоритмов на языке Zorro). Это значит, что до отправки торговому «движку» их нужно нормализовать. Во-вторых, шаблоны должны быть сбалансированы, то есть равномерно распределены по всем значениям целевой величины. Шаблонов, описывающих выигрышный вариант, должно быть столько же, сколько и проигрышный.

Регрессивные алгоритмы предсказывают числовые значения, такие как величина следующего изменения цены. Классификационные алгоритмы генерируют класс качественных шаблонов. Например, связанных с прибылью или убытком. Ряд алгоритмов нейронных сетей или опорных векторов могут одновременно работать в обеих версиях. Некоторые алгоритмы не нуждаются в целевой величине для разделения шаблонов на классы. Это так называемое обучение без учителя (unsupervised learning), в отличие от обычного с учителем (supervised learning).

Какие бы сигналы мы не использовали в качестве маркеров предсказания в сфере финансов, большинство из них будет содержать много шума и мало полезной информации. Поэтому финансовое прогнозирование – самая сложная задача в машинном обучении. Более сложные алгоритмы не всегда дают более качественный результат. Для конечного успеха критичным является выбор предикторов. На этот случай в стратегии интеллектуального анализа предусмотрен алгоритм предварительного отбора, который выбирает несколько полезных маркеров предсказаний из множества вариантов. Этот отбор может проходить на основе их корреляции, значимости или просто берутся те, что прошли тест.

Далее мы поговорим о наиболее популярных методиках интеллектуального анализа, используемых в мире финансов.

Метод проб и ошибок

Большинство торговых систем, которые компания автора блога Financial Hacker разрабатывает для своих клиентов, изначально основаны не на финансовой модели. Заказчик хочет получать сигналы для совершения транзакций, опирающиеся на конкретные технические индикаторы, фильтруемые через индикаторы с использованием еще большего числа технических индикаторов. Обычно, никто толком не может ответить на вопрос о том, как это месиво индикаторов может являться рабочей стратегией. Ответ, как правило, такой: «Просто поверьте. Я так вручную торгую уже много лет, и все работает».

На самом деле, все так и есть. По крайней мере, в некоторых случаях. Хотя многие эти системы не были прошли форвардный анализ (некоторые — даже элементарный бэктест), большинство неплохо справляется со своими задачами. Клиент систематически экспериментирует с техническими индикаторами, пока не найдет нужную комбинацию, которая работает на реальном рынке с выбранными активами. Метод проб и ошибок – это классический вариант интеллектуального анализа. Просто он производится человеком, а не машиной. Иногда это дает хороший результат.

Свечные паттерны

Нет смысла останавливаться на разборе устаревших методик, типа японских свечных паттернов, которые были популярны 200 лет назад. Современный эквивалент свечных паттернов – это безиндикаторный анализ price action. В нем трейдеры все еще пытаются найти паттерн, предсказывающий движение цены. Но в данном случае они анализируют современные ценовые кривые. Для этой цели существует набор специальных программ. Они подбирают подходящие паттерны по заложенным пользователем критериям и используют их для построения функции. В системе Zorro это может выглядеть так:

int detect(double* sig)
{
  if(sig[1]<sig[2] && sig[4]<sig[0] && sig[0]<sig[5] && sig[5]<sig[3] && sig[10]<sig[11] && sig[11]<sig[7] && sig[7]<sig[8] && sig[8]<sig[9] && sig[9]<sig[6])
      return 1; 
  if(sig[4]<sig[1] && sig[1]<sig[2] && sig[2]<sig[5] && sig[5]<sig[3] && sig[3]<sig[0] && sig[7]<sig[8] && sig[10]<sig[6] && sig[6]<sig[11] && sig[11]<sig[9])
      return 1;
  if(sig[1]<sig[4] && eqF(sig[4]-sig[5]) && sig[5]<sig[2] && sig[2]<sig[3] && sig[3]<sig[0] && sig[10]<sig[7] && sig[8]<sig[6] && sig[6]<sig[11] && sig[11]<sig[9])
      return 1;
  if(sig[1]<sig[4] && sig[4]<sig[5] && sig[5]<sig[2] && sig[2]<sig[0] && sig[0]<sig[3] && sig[7]<sig[8] && sig[10]<sig[11] && sig[11]<sig[9] && sig[9]<sig[6])
      return 1;
  if(sig[1]<sig[2] && sig[4]<sig[5] && sig[5]<sig[3] && sig[3]<sig[0] && sig[10]<sig[7] && sig[7]<sig[8] && sig[8]<sig[6] && sig[6]<sig[11] && sig[11]<sig[9])
      return 1;
  ....
  return 0;
}


Функция C делает возврат 1, когда сигнал соответствует одному из паттернов. В ином случае значение – 0. По этому коду можно видеть, что это не самый быстрый путь поиска паттернов. Альтернативный вариант – вначале сортировать сигналы по их значению, затем проверять порядок сортировки.

Даже несмотря на применение техник дата-майнинга такой ценовой трейдинг должен иметь под собой какие-то рациональные основания. Можно представить, что определенные последовательности движения цены приводят к определенной реакции участников рынка. Это и будет паттерном прогноза. Число паттернов всегда будет ограничено, если внимательно присмотреться к последовательности смежных свечей. Следующий шаг – сравнение свечей, которые находятся на расстоянии друг от друга. Мы выбираем их произвольно за достаточно долгий период времени. В этом случае число паттернов может быть безграничным. Но здесь легко потерять почву под ногами. В то же время, трудно представить, что движение цены может быть предсказано свечным паттерном недельной давности. Но в целом задача поиска свечных паттернов архисложная и чревата множеством ошибок.

Линейная регрессия

Смысл работы большинство сложных алгоритмов машинного обучения прост: нужно предсказать переменную целевую величину y через линейную комбинацию предикторов x1 … xn.

Коэффициент an рассчитывается для минимизации суммы квадратов различий между истинным значением y обучающего шаблона и предсказываемыми значениями y по следующей формуле:

Машинное обучение: что нужно знать о создании стратегий для торговли на бирже


Для нормального распределения шаблонов минимизация возможна через математическую матрицу, поэтому никакой итерации не требуется. В случае n = 1 с одной переменной предиктора x формула регрессии упрощается до:

Машинное обучение: что нужно знать о создании стратегий для торговли на бирже


Это является простой линейной регрессией. Она применяется на большинстве торговых платформ. Если y = цена, а x = время, то она часто используется как альтернатива скользящим средним. Есть еще полиноминальная регрессия, когда все еще есть один предиктор x, но есть и x2 и в более высокой степени. Таким образом, xn == xn.

Машинное обучение: что нужно знать о создании стратегий для торговли на бирже


Перцепция

Нередко этот метод рассматривают как нейронную сеть с одним нейроном. На самом деле перцепция – это та же функция регрессии, которую мы рассмотрели выше. Но с двоичным результатом. Поэтому ее еще называют логической регрессией. Хотя, по сути, это алгоритм классификации. Функция advise(PERCEPTRON, …) в Zorro генерирует C-код, делающий возврат 100 или -100, в зависимости от того, расположен ли предсказанный результат в рамках или за рамками установленного порога.

int predict(double* sig)
{
  if(-27.99*sig[0] + 1.24*sig[1] - 3.54*sig[2] > -21.50)
    return 100;
  else
    return -100;
}


В этом фрагменте видно, что массив sig эквивалентен нашим маркерам предсказания xn в формуле регрессии, а числовые множители – это коэффициенты an.

Нейронные сети

Линейная или логическая регрессия может решить лишь линейные проблемы. Многие просто не работают с такой категорией вопросов. Искусственная нейронная сеть (ИНС) призвана решать нелинейные проблемы. Она представляет собой пучок перцептронов, соединенных в набор слоев. Каждый из них является нейроном сети. Вот как выглядят инпуты и аутпуты такой сети:

Машинное обучение: что нужно знать о создании стратегий для торговли на бирже


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

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

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

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

Функция активации имитирует порог перцептора. Для обратного распространения ошибки нужна непрерывно дифференцируемая функция, которая генерирует «мягкий» шаг на определенное значение x. Для этого обычно используются функции sigmoid, tanh, или softmax. В нашем примере функция может быть использована для регрессии и предсказания числовых значений вместо двоичного выхода.

Глубокое обучение

Если речь идет о множестве скрытых слоев и тысячах нейронов, то это уже глубокое обучение. Здесь стандартное обратное распространение не работает. В последние несколько лет появились несколько популярных методик обучения такой огромной системы. Обычно они включают этап пред-обучения скрытых слоев для достижения нужного эффекта. Один из вариантов – машина Больцмана – неконтролируемый классифицирующий алгоритм со специальной структурой сети, где отсутствуют соединения между скрытыми нейронами. Разреженный автокодировщик (Sparse Autoencoder) – другой вариант, он использует стандартную структуру сети и предобучает скрытые слои через воспроизводство сигналов инпута для аутпута слоев с минимальным, насколько это возможно, количеством активных соединений. Такие методы уже позволяют решать серьезные задачи. Ну, например, побеждать лучшего в мире игрока в го.

Ниже пример скрипта на R, использующий автокодировщик с тремя скрытыми слоями для определения сигналов трейдинга с помощью функции neural() пакета Zorro:

library('deepnet', quietly = T) 
library('caret', quietly = T)

# called by Zorro for training
neural.train = function(model,XY) 
{
  XY <- as.matrix(XY)
  X <- XY[,-ncol(XY)] # predictors
  Y <- XY[,ncol(XY)]  # target
  Y <- ifelse(Y > 0,1,0) # convert -1..1 to 0..1
  Models[[model]] <<- sae.dnn.train(X,Y,
      hidden = c(20,20,20), 
      activationfun = "tanh", 
      learningrate = 0.5, 
      momentum = 0.5, 
      learningrate_scale = 1.0, 
      output = "sigm", 
      sae_output = "linear", 
      numepochs = 100, 
      batchsize = 100,
      hidden_dropout = 0, 
      visible_dropout = 0)
}

# called by Zorro for prediction
neural.predict = function(model,X) 
{
  if(is.vector(X)) X <- t(X) # transpose horizontal vector
  return(nn.predict(Models[[model]],X))
}

# called by Zorro for saving the models
neural.save = function(name)
{
  save(Models,file=name) # save trained models
}

# called by Zorro for initialization
neural.init = function()
{
  set.seed(365)
  Models <<- vector("list")
}

# quick OOS test for experimenting with the settings
Test = function() 
{
  neural.init()
  XY <<- read.csv('C:/Project/Zorro/Data/signals0.csv',header = F)
  splits <- nrow(XY)*0.8
  XY.tr <<- head(XY,splits) # training set
  XY.ts <<- tail(XY,-splits) # test set
  neural.train(1,XY.tr)
  X <<- XY.ts[,-ncol(XY.ts)]
  Y <<- XY.ts[,ncol(XY.ts)]
  Y.ob <<- ifelse(Y > 0,1,0)
  Y <<- neural.predict(1,X)
  Y.pr <<- ifelse(Y > 0.5,1,0)
  confusionMatrix(Y.pr,Y.ob) # display prediction accuracy
}


Метод опорных векторов

Также как и нейронная сеть, метод опорных векторов – это расширенный вариант линейной регрессии. Взглянем на эту формулу еще раз:

Маркеры предсказания xn можно рассматривать как координаты пространства с n измерениями. Привязав целевую величину y к фиксированному значению, мы определим плоскость или, как ее еще называют – гиперплоскость. Она отделяет шаблоны с y > 0 от шаблонов с y t от шаблонов со значением x1 < t. Разделительный порог t является выборочным, поэтому информационный прирост (отношение информационной энтропии всего пространства к сумме информационных энтропий двух разделенных субпространств) будет максимальным. Это тот случай, когда шаблоны в субпространствах более схожи друг с другом, чем шаблоны в целом пространстве.

Затем процесс запускается для следующего маркера x2, тогда уже две гиперплоскости расщепляют два субпространства. В каждом случае условием для этого является сравнение маркера с установленным порогом. В скором времени мы получаем разветвленное дерево с тысячами сравнений. Следом процесс запускается в обратном направлении, нам нужно подрезать дерево, удалив все решения, которые не ведут к существенному информационному приросту. Наконец, получается относительно небольшое дерево, как в примере кода выше.

Дерево решений может быть применено по-разному. Но его нельзя использовать в качестве решения всех проблем, так как его плоскости деления всегда параллельны осям пространства маркеров. Это ограничивает возможности делать точные предсказания. Для регрессии его также можно использовать. Например, для определения доли шаблонов, привязанных к определенной ветке дерева. Дерево Zorro – это дерево регрессии. Самый распространенный алгоритма классификации по методу дерева — C5.0, доступный в пакете C50 для R.

Заключение

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

Каждую неделю в специализированных изданиях появляется новая статья о методах машинного обучения. К выводам этих статей стоит относиться с долей скепсиса. Многие из них обещают фантастический уровень отдачи в 70-85% прибыли. Если бы все это было правдой, количество миллиардеров среди математиков бы уже зашкаливало. В реальности удачных стратегий, основанных на машинном обучении до обидного мало.
Источник / https://habrahabr.ru/company/itinvest/
При копировании ссылка http://elitetrader.ru/index.php?newsid=289886 обязательна
Условия использования материалов