English 中文 Español Deutsch 日本語 Português 한국어 Français Italiano Türkçe
Прогнозирование временных рядов в MetaTrader 5 при помощи библиотеки машинного обучения ENCOG

Прогнозирование временных рядов в MetaTrader 5 при помощи библиотеки машинного обучения ENCOG

MetaTrader 5Примеры | 25 апреля 2011, 17:20
24 980 12
investeo
investeo

Введение

В этой статье мы познакомим MetaTrader 5 с библиотекой ENCOG - пакетом для работы с нейросетями и системой машинного обучения, разработанной Heaton Research. Практические аспекты использования пакетов FANN, NeuroSolutions, Matlab и NeuroShell для работы с терминалом MetaTrader уже рассматривались ранее.  Я надеюсь, что ENCOG также станет достойным решением благодаря своей устойчивости и хорошо спроектированному коду.

Почему я выбрал ENCOG? Есть несколько причин.

  1. Пакет ENCOG используется в двух других коммерческих торговых системах. Один из них основан на C#, другой на Java. Это означает, что он уже был протестирован на предмет способности прогнозирования финансовых временных рядов. 
  2. Библиотека ENCOG является бесплатной, ее исходные коды доступны. Если вы захотите посмотреть что происходит внутри нейросети, можно посмотреть исходники. В процессе работы над задачей прогнозирования временных рядов мне пришлось с этим столкнуться. Язык программирования C# чистый и легкий для понимания.
  3. Пакет ENCOG очень хорошо документирован. Mr. Heaton, основатель компании Heaton Research, предоставил в открытый доступ онлайн курс по нейронным сетям, машинному обучению и использовании ENCOG для предсказания будущих данных. Перед написанием статьи я изучил множество его уроков, которые помогли мне лучше понять искусственные нейронные сети. В дополнение к этому, на сайте Heaton Research доступны книги по программированию с использованием ENCOG на языках Javа и C#. На сайте разработчика также доступна онлайн-документация по ENCOG.
  4. ENCOG не является "мертвым" проектом. Во процессе написания статьи разрабатывалась ENCOG 2.6, недавно была опубликована карта разработки (roadmap) ENCOG 3.0.
  5. Библиотека ENCOG является робастной. Она очень хорошо спроектирована, поддерживает работу с несколькими процессорами/потоками для ускорения нейросетевых расчетов. Некоторые коды уже начали портироваться в OpenCL для расчета на графических процессорах (GPU).
  6. На текущий момент ECNOG предоставляет следующие возможности:

Методы машинного обучения (Machine Learning Types)

Архитектуры нейронных сетей (Neural Network Architectures)

Методы обучения (Training Techniques)Активационные функции (Activation Functions)Генераторы случайных чисел (Randomization Techniques)
  • Range Randomization
  • Gaussian Random Numbers
  • Fan-In
  • Nguyen-Widrow

Планируемые к реализации (Planned features):

Как видите, список довольно внушительный.

В этой вводной статье мы будем использовать нейронную сеть прямого распространения (feed forward Neural Network architecture) с обучением при помощи эластичного распространения (Resilient Propagation, RPROP). Также мы рассмотрим основы подготовки данных (метод timeboxing и нормализацию).

При написании статьи в основном были использованы учебники по ENCOG, доступные на сайте Heaton Research и свежие статьи по предсказанию временных рядов в NinjaTrader.  Отметим, что библиотека ENCOG реализована на Java и C#, поэтому эта работа не могла бы быть сделана без использования методики, описанной в моей предыдущей статье Как открыть мир C# из MQL5 путем экспорта неуправляемого кода. Это позволило использовать DLL, написанную на C# в качестве моста между индикатором MetaTrader 5 и системой предсказания временных рядов, построенной на базе ENCOG.


1. Использование значений технических индикаторов в качестве входных параметров нейросети

Искусственная нейронная сеть представляет собой алгоритм, разработанный человеком, при помощи которого моделируется работа нейронов мозга.

Существует много различных алгоритмов работы нейросетей, есть множество нейросетевых архитектур. Область исследований настолько широка, что отдельным типам нейронных сетей посвящены целые книги. Детальное их описание выходит за рамки этой статьи, я лишь могу порекомендовать пройтись по учебникам от Heaton Research или почитать специализированную литературу. В статье мы рассмотрим работу с входными и выходными параметрами нейросети прямого распространения (feed forward neural network) и разберем практический пример решения задачи предсказания финансовых временных рядов.

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

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

Ситуация выглядит следующим образом:

Рисунок 1. Прогноз финансовых временных рядов при помощи технических индикаторов

Рисунок 1. Прогноз финансовых временных рядов при помощи технических индикаторов

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

Нейронная сеть прямого распространения состоит из нейронов, которые сгруппированы в слоях. Должно присутствовать как минимум 2 слоя: входной слой, содержащий входные нейроны и выходной слой с нейронами выходного слоя. Между входным и выходным слоями также могут присутствовать и скрытые слои. Входной слой может быть обычным массивом из чисел типа double, выходной слой может содержать один или более нейронов, которые (в общем случае) также представляют собой одномерный массив из чисел типа double.

Посмотрим на рисунок:

 Figure 2. Feedforward neural network layers

Рисунок 2. Слои нейронной сети прямого распространения

Для упрощения мы не отметили здесь связи между нейронами. Каждый из нейронов входного слоя связан с нейронами скрытого слоя (h1 и h2). Каждый из нейронов скрытого слоя связан с нейроном выходного слоя (o1).

Каждая связь имеет свой вес, который также представляет собой число типа double, и функцию активации с порогом, который отвечает за активацию нейрона и прохождение информации к следующему нейрону. По этой причине такая сеть называется сетью прямого распространения (feed forward network) - информация с выходов активированных нейронов проходит вперед к следующему слою нейронов. Более подробные вводные видеоматериалы по нейросетям прямого распространения вы можете найти по ссылкам:

Возможно, вопросы останутся даже после изучения архитектуры и механизмов работы нейросети прямого распространения.

Основные проблемы:

  1. Какие данные нужно предоставить нейросети?
  2. Как мы их должны предоставлять?
  3. Как подготовить входные данные нейросети? 
  4. Как выбрать архитектуру нейросети? Сколько нам потребуется нейронов во входном, выходном и скрытых слоях?
  5. Как обучать сеть?
  6. Что мы ожидаем получить на выходе?


2. Какие данные предоставлять нейронной сети

Поскольку мы будем строить предсказания с использованием индикаторов, мы должны снабдить нейросеть значениями индикаторов. Для этой статьи в качестве входных параметров нейросети я выбрал значения линий %K и %D индикатора Stochastic, а также значения индикатора %R Вильямса.

Figure 3. Technical indicators used for prediciton

Рисунок 3. Технические индикаторы, используемые для предсказания

Для получения значений индикаторов мы можем использовать функции iStochastic и iWPR языка MQL5:

double StochKArr[], StochDArr[], WilliamsRArr[];

ArraySetAsSeries(StochKArr, true);   
ArraySetAsSeries(StochDArr, true);   
ArraySetAsSeries(WilliamsRArr, true);

int hStochastic = iStochastic(Symbol(), Period(), 8, 5, 5, MODE_EMA, STO_LOWHIGH);
int hWilliamsR = iWPR(Symbol(), Period(), 21);
   
CopyBuffer(hStochastic, 0, 0, bufSize, StochKArr);
CopyBuffer(hStochastic, 1, 0, bufSize, StochDArr);
CopyBuffer(hWilliamsR, 0, 0, bufSize, WilliamsRArr);

После выполнения этого кода три массива (StochKArr, StochDArr и WilliamsRArr) должны быть заполнены значениями индикаторов. В зависимости от размера обучающей выборки может понадобится несколько тысяч значений. Имейте ввиду, что эти два технических индикатора мы взяли лишь в качестве иллюстрации.

Вы можете экспериментировать с любыми другими индикаторами, которые найдете пригодными для предсказания. Можно дать нейросети данные по золоту или нефти для предсказания индексов фондового рынка или же вы можете использовать скоррелированные валютные пары для предсказания другой валютной пары.

 

3. Подготовка исходных данных (Timeboxing)

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

1. С каждого индикаторного буфера собираем данные. Нам нужно скопировать INPUT_WINDOW элементов с начальной позиции - это число баров, которое будет использоваться предсказания.

 Figure 4. Gathering input window data from indicator buffer

Рисунок 4. Собираем данные индикаторного буфера для входного окна

Как видно из рисунка 4, в данном случае размер входного окна (INPUT_WINDOW) равен 4 барам и мы скопировали их в массив I1. Первым элементом данного массива является I1[0], последний элемент - I[3]. Аналогичным образом следует скопировать данные других индикаторных буферов в массивы размера INPUT_WINDOW. Схема, представленная на рис. 4, корректна для случая, если в индикаторных буферах используется индексация как в таймсериях (флаг AS_SERIES для буфера установлен в true).

2. Собирем массивы размером INPUT_WINDOW в один массив, который будет передан нейросети в качестве входного слоя.

Figure 5. Timeboxed input window arrays 

Рисунок 5. Timeboxed input window arrays

У нас 3 индикатора, сначала мы берем первое значение с каждого из индикаторов, потом берем второе значение, и так продолжаем до тех пор, пока входное окно не заполниться данными, как показано на рис. 5. Такой массив объединенных данных индикаторов может быть передан нейросети в качестве входных значений.  При появлении нового бара данные сдвигаются на один элемент и вся процедура повторяется снова. Если вас интересуют подробности подготовки данных для предсказания, посмотрите видео.


4. Нормализация входных данных

Чтобы нейросеть была эффективной, мы должны нормализовать данные. Эта процедура необходима для правильного расчета функций активации. Нормализация данных представляет собой математическое преобразование данных в диапазон [0..1] или [-1,1]. Нормализованные данные могут быть денормализованы, т.е. преобразованы обратно в начальный диапазон.

Денормализация требуется для преобразования выходных данных нейросети в вид, воспринимаемый человеком. К счастью, ENCOG может самостоятельно позаботиться о нормализации и денормализации, поэтому не требуется реализация данных методов.

Если интересно как это делается, посмотрите на код:

/**
         * Возвращает нормализованное значение числа.
         * @param value Число для нормализации.
         * @return Нормализованное значение.
         */
        public static double normalize(final int value) {
                return ((value - INPUT_LOW) 
                                / (INPUT_HIGH - INPUT_LOW))
                                * (OUTPUT_HIGH - OUTPUT_LOW) + OUTPUT_LOW;
        }
        
        /**
         * Возвращает денормализованное значение числа.
         * @param value Число для денормализации.
         * @return Денормализованное значение.
         */
        public static double deNormalize(final double data) {
                double result = ((INPUT_LOW - INPUT_HIGH) * data - OUTPUT_HIGH
                                * INPUT_LOW + INPUT_HIGH * OUTPUT_LOW)
                                / (OUTPUT_LOW - OUTPUT_HIGH);
                return result;
        }

и прочитайте статью по нормализацию.

 

5. Выбираем архитектуру нейросети и число нейронов

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

Для входного и выходного слоя мы cможем точно рассчитать количество требуемых нейронов. Для скрытого слоя мы попытаемся минимизировать ошибку нейросети при помощи алгоритма "forward selection". Вы можете попробовать использовать другие методы для определения количества нейронов в скрытом слое, например, генетические алгоритмы.

Другой метод, используемый в ENCOG называется "backward selection", или "обрезкой", в основном он имеет дело с оптимизацией связей между слоями и удаляет нейроны скрытых слоев с нулевыми весами, вы также можете его попробовать.

5.1. Входной слой

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

Если мы используем значения 3-х индикаторов и размер входного окна в 6 баров, входной слой нейросети будет содержать 18 нейронов. Данные, подготовленные алгоритмом timeboxing, затем предоставляются нейросети в качестве входных параметров.

5.2. Скрытый слой

Количество нейронов скрытого слоя должно определяться на основе погрешности расчета нейронной сети. Явного математического выражения для числа нейронов скрытого слоя не существует. До написания этой статьи, методом проб и ошибок я испробовал множество различных подходов, затем на сайте Heaton Research я нашел алгоритм, который помогает понять метод "forward selection":

Рисунок 6. Алгоритм "Forward selection" для определения числа нейронов скрытого слоя 

Рисунок 6. Алгоритм "Forward selection" для определения числа нейронов скрытого слоя

5.3. Выходной слой

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

 

6. Экспортируем данные для обучения из MetaTrader 5 в ENCOG

Для обучения нейросети библиотека Encog принимает файлы формата CSV.

Рассмотрев формат данных, экспортируемый для ENCOG другими программами, я реализовал в MQL5 скрипт для подготовки данных для обучения нейросети в том же формате. Сначала я приведу вариант с одним индикатором, далее рассмотрим случай работы с несколькими индикаторами.

Первая строка представляет собой заголовок, разделенный запятыми:

DATE,TIME,CLOSE,Indicator_Name1,Indicator_Name2,Indicator_Name3

Первые три колонки содержат дату, время и цену закрытия бара, следующие колонки содержат имена индикаторов. Строки файла с данными для обучения нейросети представляют собой данные, разделенные запятыми, значения индикаторов должны быть записаны в виде:

20110103,0000,0.93377000,-7.8970208860e-002

Вот готовый скрипт для экспорта данных одного индикатора:

//+------------------------------------------------------------------+
//|                                                ExportToEncog.mq5 |
//|                                      Copyright 2011, Investeo.pl |
//|                                                http:/Investeo.pl |
//+------------------------------------------------------------------+
#property copyright "Copyright 2011, Investeo.pl"
#property link      "http:/Investeo.pl"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+

// Экспортирует значения индикатора для обучения нейросети в ENCOG
extern string IndExportFileName = "mt5export.csv";
extern int  trainSize = 400;
extern int  maPeriod = 210;

MqlRates srcArr[];
double expBullsArr[];

void OnStart()
  {
//---
   ArraySetAsSeries(srcArr, true);   
   ArraySetAsSeries(expBullsArr, true);      
         
   int copied = CopyRates(Symbol(), Period(), 0, trainSize, srcArr);
   
   if (copied!=trainSize) { Print("Недостаточно данных по символу " + Symbol()); return; }
   
   int hBullsPower = iBullsPower(Symbol(), Period(), maPeriod);
   
   CopyBuffer(hBullsPower, 0, 0, trainSize, expBullsArr);
   
   int hFile = FileOpen(IndExportFileName, FILE_CSV | FILE_ANSI | FILE_WRITE | FILE_REWRITE, ",", CP_ACP);
   
   FileWriteString(hFile, "DATE,TIME,CLOSE,BullsPower\n");
   
   Print("Экспортирую значения индикатора в файл " + IndExportFileName);
   
   for (int i=trainSize-1; i>=0; i--)
      {
         string candleDate = TimeToString(srcArr[i].time, TIME_DATE);
         StringReplace(candleDate,".","");
         string candleTime = TimeToString(srcArr[i].time, TIME_MINUTES);
         StringReplace(candleTime,":","");
         FileWrite(hFile, candleDate, candleTime, DoubleToString(srcArr[i].close), DoubleToString(expBullsArr[i], -10));
      }
      
   FileClose(hFile);   
     
   Print("Данные индикатора экспортированы."); 
  }
//+------------------------------------------------------------------+

Результирующий файл, готовый для обучения нейросети, должен выглядеть следующим образом:

DATE,TIME,CLOSE,BullsPower
20110103,0000,0.93377000,-7.8970208860e-002
20110104,0000,0.94780000,-6.4962292188e-002
20110105,0000,0.96571000,-4.7640374727e-002
20110106,0000,0.96527000,-4.4878854587e-002
20110107,0000,0.96697000,-4.6178012364e-002
20110110,0000,0.96772000,-4.2078647318e-002
20110111,0000,0.97359000,-3.6029181466e-002
20110112,0000,0.96645000,-3.8335729509e-002
20110113,0000,0.96416000,-3.7054869514e-002
20110114,0000,0.96320000,-4.4259373120e-002
20110117,0000,0.96503000,-4.4835729773e-002
20110118,0000,0.96340000,-4.6420936126e-002
20110119,0000,0.95585000,-4.6868984125e-002
20110120,0000,0.96723000,-4.2709941621e-002
20110121,0000,0.95810000,-4.1918330800e-002
20110124,0000,0.94873000,-4.7722659418e-002
20110125,0000,0.94230000,-5.7111591557e-002
20110126,0000,0.94282000,-6.2231529077e-002
20110127,0000,0.94603000,-5.9997865295e-002
20110128,0000,0.94165000,-6.0378312069e-002
20110131,0000,0.94414000,-6.2038328069e-002
20110201,0000,0.93531000,-6.0710334438e-002
20110202,0000,0.94034000,-6.1446445012e-002
20110203,0000,0.94586000,-5.2580791504e-002
20110204,0000,0.95496000,-4.5246755566e-002
20110207,0000,0.95730000,-4.4439392954e-002

В нашем примере с индикаторами Stochastic и Williams' R, требуется экспортировать три колонки данных, разделенных запятыми. Каждая из них содержит значения индикаторов, поэтому нам нужно расширить файл и добавить дополнительные буферы:

//+------------------------------------------------------------------+
//|                                                ExportToEncog.mq5 |
//|                                      Copyright 2011, Investeo.pl |
//|                                                http:/Investeo.pl |
//+------------------------------------------------------------------+
#property copyright "Copyright 2011, Investeo.pl"
#property link      "http:/Investeo.pl"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+

// Индикатор экспорта значений для обучения нейросети в ENCOG
extern string IndExportFileName = "mt5export.csv";
extern int  trainSize = 2000;

MqlRates srcArr[];
double StochKArr[], StochDArr[], WilliamsRArr[];

void OnStart()
  {
//---
   ArraySetAsSeries(srcArr, true);   
   ArraySetAsSeries(StochKArr, true);   
   ArraySetAsSeries(StochDArr, true);   
   ArraySetAsSeries(WilliamsRArr, true);
         
   int copied = CopyRates(Symbol(), Period(), 0, trainSize, srcArr);
   
   if (copied!=trainSize) { Print("Недостаточно данных по символу " + Symbol()); return; }
   
   int hStochastic = iStochastic(Symbol(), Period(), 8, 5, 5, MODE_EMA, STO_LOWHIGH);
   int hWilliamsR = iWPR(Symbol(), Period(), 21);
   
   
   CopyBuffer(hStochastic, 0, 0, trainSize, StochKArr);
   CopyBuffer(hStochastic, 1, 0, trainSize, StochDArr);
   CopyBuffer(hWilliamsR, 0, 0, trainSize, WilliamsRArr);
    
   int hFile = FileOpen(IndExportFileName, FILE_CSV | FILE_ANSI | FILE_WRITE | FILE_REWRITE, ",", CP_ACP);
   
   FileWriteString(hFile, "DATE,TIME,CLOSE,StochK,StochD,WilliamsR\n");
   
   Print("Экспортирую данные индикатора в файл " + IndExportFileName);
   
   for (int i=trainSize-1; i>=0; i--)
      {
         string candleDate = TimeToString(srcArr[i].time, TIME_DATE);
         StringReplace(candleDate,".","");
         string candleTime = TimeToString(srcArr[i].time, TIME_MINUTES);
         StringReplace(candleTime,":","");
         FileWrite(hFile, candleDate, candleTime, DoubleToString(srcArr[i].close), 
                                                 DoubleToString(StochKArr[i], -10),
                                                 DoubleToString(StochDArr[i], -10),
                                                 DoubleToString(WilliamsRArr[i], -10)
                                                 );
      }
      
   FileClose(hFile);   
     
   Print("Данные индикатора экспортированы."); 
  }
//+------------------------------------------------------------------+

Выходной файл должен содержать значения всех индикаторов:

DATE,TIME,CLOSE,StochK,StochD,WilliamsR
20030707,0000,1.37370000,7.1743119266e+001,7.2390220187e+001,-6.2189054726e-001
20030708,0000,1.36870000,7.5140977444e+001,7.3307139273e+001,-1.2500000000e+001
20030709,0000,1.35990000,7.3831775701e+001,7.3482018082e+001,-2.2780373832e+001
20030710,0000,1.36100000,7.1421933086e+001,7.2795323083e+001,-2.1495327103e+001
20030711,0000,1.37600000,7.5398313027e+001,7.3662986398e+001,-3.9719626168e+000
20030714,0000,1.37370000,7.0955352856e+001,7.2760441884e+001,-9.6153846154e+000
20030715,0000,1.38560000,7.4975891996e+001,7.3498925255e+001,-2.3890784983e+000
20030716,0000,1.37530000,7.5354107649e+001,7.4117319386e+001,-2.2322435175e+001
20030717,0000,1.36960000,7.1775345074e+001,7.3336661282e+001,-3.0429594272e+001
20030718,0000,1.36280000,5.8474576271e+001,6.8382632945e+001,-3.9778325123e+001
20030721,0000,1.35400000,4.3498596819e+001,6.0087954237e+001,-5.4946524064e+001
20030722,0000,1.36130000,2.9036761284e+001,4.9737556586e+001,-4.5187165775e+001
20030723,0000,1.34640000,1.6979405034e+001,3.8818172735e+001,-6.5989159892e+001
20030724,0000,1.34680000,1.0634573304e+001,2.9423639592e+001,-7.1555555556e+001
20030725,0000,1.34400000,9.0909090909e+000,2.2646062758e+001,-8.7500000000e+001
20030728,0000,1.34680000,1.2264922322e+001,1.9185682613e+001,-8.2705479452e+001
20030729,0000,1.35250000,1.4960629921e+001,1.7777331716e+001,-7.2945205479e+001
20030730,0000,1.36390000,2.7553336360e+001,2.1035999930e+001,-5.3979238754e+001
20030731,0000,1.36990000,4.3307839388e+001,2.8459946416e+001,-4.3598615917e+001
20030801,0000,1.36460000,5.6996412096e+001,3.7972101643e+001,-5.2768166090e+001
20030804,0000,1.34780000,5.7070193286e+001,4.4338132191e+001,-8.1833910035e+001
20030805,0000,1.34770000,5.3512705531e+001,4.7396323304e+001,-8.2006920415e+001
20030806,0000,1.35350000,4.4481132075e+001,4.6424592894e+001,-7.1972318339e+001
20030807,0000,1.35020000,3.3740028156e+001,4.2196404648e+001,-7.7681660900e+001
20030808,0000,1.35970000,3.0395426394e+001,3.8262745230e+001,-6.1245674740e+001
20030811,0000,1.35780000,3.4155781326e+001,3.6893757262e+001,-6.4532871972e+001
20030812,0000,1.36880000,4.3488943489e+001,3.9092152671e+001,-4.5501730104e+001
20030813,0000,1.36690000,5.1160443996e+001,4.3114916446e+001,-4.8788927336e+001
20030814,0000,1.36980000,6.2467599793e+001,4.9565810895e+001,-2.5629290618e+001
20030815,0000,1.37150000,6.9668246445e+001,5.6266622745e+001,-2.1739130435e+001
20030818,0000,1.38910000,7.9908906883e+001,6.4147384124e+001,-9.2819614711e+000

На базе второго примера вы легко сможете построить скрипт, который вам требуется.


7. Обучение нейронной сети

Алгоритм обучения нейросети уже реализован разработчиками ENOG на языке C#.

ENCOG 2.6 использует пространство имен Encog.App.Quant в качестве основы для предсказания финансовых временных рядов. Скрипт обучения очень гибкий и легко может быть адаптирован на любое количество входных индикаторов. Вам лишь следует заменить константу DIRECTORY местом расположения каталога терминала MetaTrader 5.

Архитектура нейросети и параметры обучения могут быть легко настроены изменением следующих переменных:

        /// <summary>
        /// Размер входного окна. Представляет собой количество баров, используемых для предсказания следующего бара.
        /// </summary>
        public const int INPUT_WINDOW = 6;        

        /// <summary>
        /// Количество баров в будущем, которые пытаемся предсказать. Обычно это всего 1 бар. 
         /// Предсказание будущего на 1 бар работает лучше всего.
        /// </summary>
        public const int PREDICT_WINDOW = 1;

        /// <summary>
        /// Количество баров вперед, используемых для получения лучшего результата.
        /// </summary>
        public const int RESULT_WINDOW = 5;

        /// <summary>
        /// Количество нейронов в первом скрытом слое.
        /// </summary>
        public const int HIDDEN1_NEURONS = 12;

        /// <summary>
        /// Ошибка обучения нейросети.
        /// </summary>
        public const double TARGET_ERROR = 0.01;

Код не нуждается в комментариях, поэтому лучше внимательно его посмотреть:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Encog.App.Quant.Normalize;
using Encog.Util.CSV;
using Encog.App.Quant.Indicators;
using Encog.App.Quant.Indicators.Predictive;
using Encog.App.Quant.Temporal;
using Encog.Neural.NeuralData;
using Encog.Neural.Data.Basic;
using Encog.Util.Simple;
using Encog.Neural.Networks;
using Encog.Neural.Networks.Layers;
using Encog.Engine.Network.Activation;
using Encog.Persist;

namespace NetworkTrainer
{
    public class Program
    {
        /// <summary>
        /// Каталог, в котором храняться все файлы.
        /// </summary>
        public const String DIRECTORY = "d:\\mt5\\MQL5\\Files\\";

        /// <summary>
        /// Входной файл, с которого все начинается.
        /// </summary>
        public const String STEP1_FILENAME = DIRECTORY + "mt5export.csv";

        /// <summary>
        /// мы применили индикатор предсказания будущего и сгенерировали второй файл с дополнительным полем.
        /// </summary>
        public const String STEP2_FILENAME = DIRECTORY + "step2_future.csv";

        /// <summary>
        /// Теперь все данные нормализованы и размешены в этом файле.
        /// </summary>
        public const String STEP3_FILENAME = DIRECTORY + "step3_norm.csv";

        /// <summary>
        /// Подготовленный (time-boxed) для создания данных обучения.
        /// </summary>
        public const String STEP4_FILENAME = DIRECTORY + "step4_train.csv";

        /// <summary>
        /// Окончательный файл с обученной нейросетью содержится в этом файле.
        /// </summary>
        public const String STEP5_FILENAME = DIRECTORY + "step5_network.eg";
       
        /// <summary>
        /// Размер входного окна. Это число баров, используемое для предсказания следующего бара.
        /// </summary>
        public const int INPUT_WINDOW = 6;        

        /// <summary>
        /// Количество баров в будущем, которые пытаемся предсказать. Обычно это всего 1 бар.
        /// Предсказание будущего на 1 бар работает лучше всего. 

        /// </summary>
        public const int PREDICT_WINDOW = 1;

        /// <summary>
        /// Используемое количество баров будущего.
        /// </summary>
        public const int RESULT_WINDOW = 5;

        /// <summary>
        /// Количество нейронов в первом скрытом слое.
        /// </summary>
        public const int HIDDEN1_NEURONS = 12;

        /// <summary>
        /// Ошибка обучения нейросети.
        /// </summary>
        public const double TARGET_ERROR = 0.01;

        static void Main(string[] args)
        {
            // Step 1: Create future indicators
            Console.WriteLine("Step 1: Analyze MT5 Export & Create Future Indicators");
            ProcessIndicators ind = new ProcessIndicators();
            ind.Analyze(STEP1_FILENAME, true, CSVFormat.DECIMAL_POINT);
            int externalIndicatorCount = ind.Columns.Count - 3;
            ind.AddColumn(new BestReturn(RESULT_WINDOW,true)); 
            ind.Process(STEP2_FILENAME);          
            Console.WriteLine("External indicators found: " + externalIndicatorCount);
            //Console.ReadKey();

            // Шаг 2: Нормализация и подготовка данных (Step 2: Normalize)
            Console.WriteLine("Step 2: Create Future Indicators");
            EncogNormalize norm = new EncogNormalize();
            norm.Analyze(STEP2_FILENAME, true, CSVFormat.ENGLISH);
            norm.Stats[0].Action = NormalizationDesired.PassThrough; // дата (Date)
            norm.Stats[1].Action = NormalizationDesired.PassThrough; // время (Time)
            
            norm.Stats[2].Action = NormalizationDesired.Normalize; // цена закрытия бара(Close)
            norm.Stats[3].Action = NormalizationDesired.Normalize; // значение линии Stoch K
            norm.Stats[4].Action = NormalizationDesired.Normalize; // значение линии Stoch Dd
            norm.Stats[5].Action = NormalizationDesired.Normalize; // значение индикатора WilliamsR
       
            norm.Stats[6].Action = NormalizationDesired.Normalize; // best return [RESULT_WINDOW]

            norm.Normalize(STEP3_FILENAME);

            // расчет количества нейронов входного слоя
            int inputNeurons = INPUT_WINDOW * externalIndicatorCount;
            int outputNeurons = PREDICT_WINDOW;

            // Step 3: Time-box
            Console.WriteLine("Step 3: Timebox");
            //Console.ReadKey();
            TemporalWindow window = new TemporalWindow();
            window.Analyze(STEP3_FILENAME, true, CSVFormat.ENGLISH);
            window.InputWindow = INPUT_WINDOW;
            window.PredictWindow = PREDICT_WINDOW;
            int index = 0;
            window.Fields[index++].Action = TemporalType.Ignore; // дата date
            window.Fields[index++].Action = TemporalType.Ignore; // время time
            window.Fields[index++].Action = TemporalType.Ignore; // цена закрытия бара close
            for(int i=0;i<externalIndicatorCount;i++)
                window.Fields[index++].Action = TemporalType.Input; // external indicators
            window.Fields[index++].Action = TemporalType.Predict; // PredictBestReturn

            window.Process(STEP4_FILENAME);

            // Шаг 4: обучение нейронной сети
            Console.WriteLine("Step 4: Train");
            Console.ReadKey();
            INeuralDataSet training = (BasicNeuralDataSet)EncogUtility.LoadCSV2Memory(STEP4_FILENAME, inputNeurons, 
                                                                                      outputNeurons, true, CSVFormat.ENGLISH);

            BasicNetwork network = new BasicNetwork();
            network.AddLayer(new BasicLayer(new ActivationTANH(), true, inputNeurons));
            network.AddLayer(new BasicLayer(new ActivationTANH(), true, HIDDEN1_NEURONS));
            network.AddLayer(new BasicLayer(new ActivationLinear(), true, outputNeurons));
            network.Structure.FinalizeStructure();
            network.Reset();

            //EncogUtility.TrainToError(network, training, TARGET_ERROR);
            EncogUtility.TrainConsole(network, training, 3);

            // Шаг 5: Сохранение нейросети и статистики (Step 5: Save neural network and stats)
            EncogMemoryCollection encog = new EncogMemoryCollection();
            encog.Add("network", network);
            encog.Add("stat", norm.Stats);
            encog.Save(STEP5_FILENAME);
            Console.ReadKey();
        }
    }
}

Возможно, вы заметили, что я закомментировал строку обучения EncogUtility.TrainToError() и заменил ее на EncogUtility.TrainConsole().

EncogUtility.TrainConsole(network, training, 3);

Метод TrainConsole указывает количество минут для обучения нейронной сети. В данном примере я произвожу обучение в течение трех минут. В зависимости от сложности нейросети и размера обучающей выборки, процесс обучения может занимать от нескольких минут до часов или даже дней. Рекомендую почитать о расчете ошибки и алгоритмах обучения на сайте Heaton Research или в книгах по нейросетям.

Метод EncogUtility.TrainToError() останавливает процесс обучения после получения заданной погрешности расчетов. Вы можете закомментировать вызов EncongUtiliy.TrainConsole() и раскомментировать EncogUtility.TrainToError() для обучения нейросети до заданной погрешности, как в нашем примере.

EncogUtility.TrainToError(network, training, TARGET_ERROR);

Имейте ввиду, что возможны случаи, когда нейронная сеть не может быть обучена до некоторой точности из-за того, что количество нейронов слишком мало.


8. Используем обученную нейронную сеть для построения индикатора в MetaTrader 5

Обученная нейронная сеть может быть использована в нейросетевом индикаторе, который будет пытаться предсказать изменение цены (best return on investment).

Нейросетевой индикатор ENCOG для MetaTrader 5 состоит из двух частей. Первая часть написана на MQL5, главным образом, она берет значения тех же самых индикаторов, которые использовались нами для обучения нейросети и отдает их нейронной сети в качестве входных параметров.

Вторая часть написана на C#, она подготавливает входные данные, осуществляет timeboxing, производит расчет и возвращает результат работы нейросети в MQL5.  Код индикатора на C# основан на моей предыдущей статье Как открыть мир C# из MQL5 путем экспорта неуправляемого кода.

using System;
using System.Collections.Generic;
using System.Text;
using RGiesecke.DllExport;
using System.Runtime.InteropServices;
using Encog.Neural.Networks;
using Encog.Persist;
using Encog.App.Quant.Normalize;
using Encog.Neural.Data;
using Encog.Neural.Data.Basic;

namespace EncogNeuralIndicatorMT5DLL
{

    public class NeuralNET
    {
        private EncogMemoryCollection encog;
        public BasicNetwork network;
        public NormalizationStats stats;

        public NeuralNET(string nnPath)
        {
            initializeNN(nnPath);
        }

        public void initializeNN(string nnPath)
        {
            try
            {
                encog = new EncogMemoryCollection();
                encog.Load(nnPath);
                network = (BasicNetwork)encog.Find("network");
                stats = (NormalizationStats)encog.Find("stat");
            }
            catch (Exception e)
            {
                Console.WriteLine(e.StackTrace);
            }
        }
    };

   class UnmanagedExports
   {

      static NeuralNET neuralnet; 

      [DllExport("initializeTrainedNN", CallingConvention = CallingConvention.StdCall)]
      static int initializeTrainedNN([MarshalAs(UnmanagedType.LPWStr)]string nnPath)
      {
          neuralnet = new NeuralNET(nnPath);

          if (neuralnet.network != null) return 0;
          else return -1;
      }

      [DllExport("computeNNIndicator", CallingConvention = CallingConvention.StdCall)]
      public static int computeNNIndicator([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] double[] t1,
                                           [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] double[] t2,
                                           [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] double[] t3, 
                                           int len, 
                                           [In, Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 5)] double[] result,
                                           int rates_total)
      {
          INeuralData input = new BasicNeuralData(3 * len);
          
          int index = 0;
          for (int i = 0; i <len; i++)
          {
              input[index++] = neuralnet.stats[3].Normalize(t1[i]);
              input[index++] = neuralnet.stats[4].Normalize(t2[i]);
              input[index++] = neuralnet.stats[5].Normalize(t3[i]);
          }

          INeuralData output = neuralnet.network.Compute(input);
          double d = output[0];
          d = neuralnet.stats[6].DeNormalize(d);        
          result[rates_total-1]=d;

          return 0;
      }  
   }
}

Если вам требуется использование большего количества индикаторов, чем три, измените метод computeNNIndicator():

 [DllExport("computeNNIndicator", CallingConvention = CallingConvention.StdCall)]
      public static int computeNNIndicator([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] double[] t1,
                                         [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] double[] t2,
                                         [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] double[] t3, 
                                         int len, 
                                         [In, Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 5)] double[] result,
                                         int rates_total)

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

Значение SizeParamIndex = 3 указывает на длину входного окна, входные переменные нумеруются (индексируются) с 0.  Пятый параметр представляет собой таблицу, которая содержит результаты работы нейросети.

Для части индикатора, написанной на MQL5, требуется импорт C#-библиотеки EncogNNTrainDLL.dll и использование экспортированных функций initializeTrainedNN() и computeNNIndicator().

//+------------------------------------------------------------------+
//|                                         NeuralEncogIndicator.mq5 |
//|                                      Copyright 2011, Investeo.pl |
//|                                                http:/Investeo.pl |
//+------------------------------------------------------------------+
#property copyright "Copyright 2011, Investeo.pl"
#property link      "http:/Investeo.pl"
#property version   "1.00"
#property indicator_separate_window

#property indicator_plots 1
#property indicator_buffers 1
#property indicator_color1 Blue
#property indicator_type1 DRAW_LINE
#property indicator_style1 STYLE_SOLID
#property indicator_width1  2

#import "EncogNNTrainDLL.dll"
   int initializeTrainedNN(string nnFile);
   int computeNNIndicator(double& ind1[], double& ind2[],double& ind3[], int size, double& result[], int rates);  
#import


int INPUT_WINDOW = 6;
int PREDICT_WINDOW = 1;

double ind1Arr[], ind2Arr[], ind3Arr[]; 
double neuralArr[];

int hStochastic;
int hWilliamsR;

int hNeuralMA;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
    
   SetIndexBuffer(0, neuralArr, INDICATOR_DATA);
   
   PlotIndexSetInteger(0, PLOT_SHIFT, 1);

   ArrayResize(ind1Arr, INPUT_WINDOW);
   ArrayResize(ind2Arr, INPUT_WINDOW);
   ArrayResize(ind3Arr, INPUT_WINDOW);
     
   ArrayInitialize(neuralArr, 0.0);
   
   ArraySetAsSeries(ind1Arr, true);   
   ArraySetAsSeries(ind2Arr, true);  
   ArraySetAsSeries(ind3Arr, true);
  
   ArraySetAsSeries(neuralArr, true);   
   
   hStochastic = iStochastic(NULL, 0, 8, 5, 5, MODE_EMA, STO_LOWHIGH);
   hWilliamsR = iWPR(NULL, 0, 21);
 
   Print(TerminalInfoString(TERMINAL_DATA_PATH)+"\\MQL5\Files\step5_network.eg");
   initializeTrainedNN(TerminalInfoString(TERMINAL_DATA_PATH)+"\\MQL5\Files\step5_network.eg");
   
//---
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime& time[],
                const double& open[],
                const double& high[],
                const double& low[],
                const double& close[],
                const long& tick_volume[],
                const long& volume[],
                const int& spread[])
  {
//---
   int calc_limit;
   
   if(prev_calculated==0) // First execution of the OnCalculate() function after the indicator start
        calc_limit=rates_total-34; 
   else calc_limit=rates_total-prev_calculated;
    
   ArrayResize(neuralArr, rates_total);
   
   for (int i=0; i<calc_limit; i++)     
   {
      CopyBuffer(hStochastic, 0, i, INPUT_WINDOW, ind1Arr);
      CopyBuffer(hStochastic, 1, i, INPUT_WINDOW, ind2Arr);
      CopyBuffer(hWilliamsR,  0, i, INPUT_WINDOW, ind3Arr);    
      
      computeNNIndicator(ind1Arr, ind2Arr, ind3Arr, INPUT_WINDOW, neuralArr, rates_total-i); 
   }
     
  //Print("neuralArr[0] = " + neuralArr[0]);
   
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+

Результат работы индикатора, обученного на дневных данных пары USDCHF и данных индикаторов Stochastic и Williams %R приведен на рисунке:

 Figure 7. Neural Encog indicator

Рисунок 7. Нейросетевой индикатор на базе Encog

Индикатор показывает предсказанные приращения цены (returns on investment) для следующего бара.

Возможно, вы заметили что я сдвинул индикатор на 1 бар в будущее:

PlotIndexSetInteger(0, PLOT_SHIFT, 1);

Это сделано для того, чтобы подчеркнуть предсказательную способность индикатора. Нейросетевой индикатор готов, теперь мы готовы для создания советника на базе этого индикатора.


9. Советник, основанный на нейросетевом индикаторе

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

После некоторого тестирования выяснилось, что эффективность можно повысить, поэтому я ввел переменные "strong uptrend" and "strong downtrend", используемые для того чтобы не выходить с рынка в случаях сильных трендов, в соответствии с правилом "trend is your friend".

Кроме того, на форуме Heaton Research мне посоветовали использовать ATR для скользящих уровней stop-loss, поэтому я использовал индикатор Chandelier ATR, опубликованный на форуме по MQL5.  Код советника приведен ниже.

//+------------------------------------------------------------------+
//|                                           NeuralEncogAdvisor.mq5 |
//|                                      Copyright 2011, Investeo.pl |
//|                                                http:/Investeo.pl |
//+------------------------------------------------------------------+
#property copyright "Copyright 2011, Investeo.pl"
#property link      "http:/Investeo.pl"
#property version   "1.00"

double neuralArr[];

double trend;
double Lots=0.3;

int INPUT_WINDOW=8;

int hNeural,hChandelier;

//+------------------------------------------------------------------+
#include <Trade\Trade.mqh>
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   ArrayResize(neuralArr,INPUT_WINDOW);
   ArraySetAsSeries(neuralArr,true);
   ArrayInitialize(neuralArr,0.0);

   hNeural=iCustom(Symbol(),Period(),"NeuralEncogIndicator");
   Print("hNeural = ",hNeural,"  код ошибки= ",GetLastError());

   if(hNeural<0)
     {
      Print("Ошибка создания индикатора ENCOG: Код ошибки =",GetLastError());
      //--- принудительное завершение работы
      return(-1);
     }
   else  Print("Индикатор ENCOG инициализирован");

   hChandelier=iCustom(Symbol(),Period(),"Chandelier");
   Print("hChandelier = ",hChandelier,"  код ошибки = ",GetLastError());

   if(hChandelier<0)
     {
      Print("Ошибка создания индикатора Chandelier: Код ошибки =",GetLastError());
      //--- принудительное завершение работы
      return(-1);
     }
   else  Print("Индикатор Chandelier инициализирован");
//---
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   long tickCnt[1];
   int ticks=CopyTickVolume(Symbol(),0,0,1,tickCnt);
   if(tickCnt[0]==1)
     {
      if(!CopyBuffer(hNeural,0,0,INPUT_WINDOW,neuralArr)) { Print("Copy1 error"); return; }

      // Print("neuralArr[0] = "+neuralArr[0]+"neuralArr[1] = "+neuralArr[1]+"neuralArr[2] = "+neuralArr[2]);
      trend=0;

      if(neuralArr[0]<0 && neuralArr[1]>0) trend=-1;
      if(neuralArr[0]>0 && neuralArr[1]<0) trend=1;

      Trade();
     }
  }
//+------------------------------------------------------------------+
//| Tester function                                                  |
//+------------------------------------------------------------------+
double OnTester()
  {
//---

//---
   return(0.0);
  }
//+------------------------------------------------------------------+

void Trade()
  {
   double bufChandelierUP[2];
   double bufChandelierDN[2];

   double bufMA[2];

   ArraySetAsSeries(bufChandelierUP,true);
   ArraySetAsSeries(bufChandelierUP,true);

   ArraySetAsSeries(bufMA,true);

   CopyBuffer(hChandelier,0,0,2,bufChandelierUP);
   CopyBuffer(hChandelier,1,0,2,bufChandelierDN);

   MqlRates rates[];
   ArraySetAsSeries(rates,true);
   int copied=CopyRates(Symbol(),PERIOD_CURRENT,0,3,rates);

   bool strong_uptrend=neuralArr[0]>0 && neuralArr[1]>0 && neuralArr[2]>0 &&
                      neuralArr[3]>0 && neuralArr[4]>0 && neuralArr[5]>0 &&
                       neuralArr[6]>0 && neuralArr[7]>0;
   bool strong_downtrend=neuralArr[0]<0 && neuralArr[1]<0 && neuralArr[2]<0 &&
                        neuralArr[3]<0 && neuralArr[4]<0 && neuralArr[5]<0 &&
                        neuralArr[6]<0 && neuralArr[7]<0;

   if(PositionSelect(_Symbol))
     {
      long type=PositionGetInteger(POSITION_TYPE);
      bool close=false;

      if((type==POSITION_TYPE_BUY) && (trend==-1))

         if(!(strong_uptrend) || (bufChandelierUP[0]==EMPTY_VALUE)) close=true;
      if((type==POSITION_TYPE_SELL) && (trend==1))
         if(!(strong_downtrend) || (bufChandelierDN[0]==EMPTY_VALUE))
            close=true;
      if(close)
        {
         CTrade trade;
         trade.PositionClose(_Symbol);
        }
      else // adjust s/l
        {
         CTrade trade;

         if(copied>0)
           {
            if(type==POSITION_TYPE_BUY)
              {
               if(bufChandelierUP[0]!=EMPTY_VALUE)
                  trade.PositionModify(Symbol(),bufChandelierUP[0],0.0);
              }
            if(type==POSITION_TYPE_SELL)
              {
               if(bufChandelierDN[0]!=EMPTY_VALUE)
                  trade.PositionModify(Symbol(),bufChandelierDN[0],0.0);
              }
           }
        }
     }

   if((trend!=0) && (!PositionSelect(_Symbol)))
     {
      CTrade trade;
      MqlTick tick;
      MqlRates rates[];
      ArraySetAsSeries(rates,true);
      int copied=CopyRates(Symbol(),PERIOD_CURRENT,0,INPUT_WINDOW,rates);

      if(copied>0)
        {
         if(SymbolInfoTick(_Symbol,tick)==true)
           {
            if(trend>0)
              {
               trade.Buy(Lots,_Symbol,tick.ask);
               Print("Покупка по цене "+tick.ask+" trend = "+trend+" neuralArr = "+neuralArr[0]);
              }
            if(trend<0)
              {
               trade.Sell(Lots,_Symbol,tick.bid);
               Print("Продажа по цене "+tick.ask+" trend = "+trend+" neuralArr = "+neuralArr[0]);
              }
           }
        }
     }

  }
//+------------------------------------------------------------------+

Советник был протестирован на дневных барах пары USDCHF. Для обучения нейросети было использовано около 50% данных.


10. Результаты тестирования советника на истории


Ниже я приведу результаты тестирования на истории. Тест проводился с 2000.01.01 по 2011.03.26.

Рисунок 8. Результаты тестирования нейросетевого советника на исторических данных

Рисунок 8. Результаты тестирования нейросетевого советника на исторических данных

Figure 9. Neural Expert Advisor Balance/Equity backtesting graph

Рисунок 9. График Баланса/Средств нейросетевого советника

Имейте ввиду, что результаты могут различаться для других таймфреймов и других финансовых инструментов.

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


Выводы

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


Из-за реализации в виде "двойной DLL-обертки под .NET", файлы Cloo.dll, encog-core-cs.dll и log4net.dll нужно скопировать в каталог установки клиентского терминала.
Файл EncogNNTrainDLL.dll нужно скопировать в каталог папка_данных_клиентского_терминала\MQL5\Libraries\.


Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/252

Прикрепленные файлы |
encogcsharp.zip (2202.77 KB)
files.zip (270.14 KB)
libraries.zip (321.62 KB)
experts.zip (1.56 KB)
indicators.zip (2.24 KB)
scripts.zip (1.03 KB)
Последние комментарии | Перейти к обсуждению на форуме трейдеров (12)
Serge
Serge | 16 мая 2011 в 21:35
Automated-Trading:

В файле step2_future.csv, созданным на базе mt5export.csv отсутствуют необходимые столбцы с данными, что является следствием неправильной обработки mt5export.csv . Это происходит в случае, если в настройках ОС в качестве разделителя целой и дробной части чисел задана",".

Установите разделитель целой и дробной части "." в разделе "Язык и региональные стандарты".

После этих действий почти заработало, теперь повисает на тренировке, при этом ошибок не вылетает.

 

NET у меня 4й. Win 7 x64 sp1

 

NeuralEncogIndicator (EURUSD,M5) Access violation read to 0x00000000 продолжаются

 

Serge
Serge | 18 мая 2011 в 23:20
Graff:

После этих действий почти заработало, теперь повисает на тренировке, при этом ошибок не вылетает.

 

NET у меня 4й. Win 7 x64 sp1

 

NeuralEncogIndicator (EURUSD,M5) Access violation read to 0x00000000 продолжаются

 

Отвечаю на свой вопрос. NinjaIndicators удалось заставить работать путем использования оригинального кода от автора ЕНКОГ, ссылка выше. На удивление NeuralEncogIndicator успешно подхватил созданный им step5_network.eg и не умер с Access violation read to 0x00000000 (первый раз за все время).
imgoood
imgoood | 29 февр. 2012 в 16:42

Подскажите в каких других коммерческих торговых системах  используется  ENCOG  ?

Потенциал супер просто и хотелось бы увидеть что то типа трейдинг солюшенс 

Vedamir
Vedamir | 25 июн. 2013 в 16:03

Подскажите что такое RESULT_WINDOW . Правильно ли я понял, это бары которые подаются только при обучении сети ? Ведь при работе баров будущего взять негде 

/// Используемое количество баров будущего.
        /// </summary> 

        public const int RESULT_WINDOW = 5;

 

// Количество баров вперед, используемых для получения лучшего результата.

        /// </summary>
        public const int RESULT_WINDOW = 5;

Alexey Shevchenko
Alexey Shevchenko | 3 июл. 2014 в 11:53

что-то резко закончилось обсуждение...

Кто-нибудь работает с данной библиотекой? Стоит ли изучать её?

Статья очень понравилась. Респект автору!

Мастер MQL5: Новая версия Мастер MQL5: Новая версия
Статья описывает возможности, появившиеся в новой версии Мастера MQL5. Изменения в архитектуре сигналов позволяют теперь создавать торговые роботы на основе комбинации различных рыночных моделей. На конкретном примере рассматривается процедура интерактивного создания готового к торговле эксперта.
Индикаторы и торговые системы Уильяма Блау на MQL5. Часть 1: Индикаторы Индикаторы и торговые системы Уильяма Блау на MQL5. Часть 1: Индикаторы
В статье представлено описание разработанных на MQL5 индикаторов по книге Уильяма Блау (William Blau) "Моментум, направленность и расхождение". Подход Уильяма Блау позволяет достаточно точно и с минимальным запаздыванием аппроксимировать колебания ценовой кривой, выделять тенденцию ценового движения и поворотные точки и устранять ценовой шум. При этом мы можем также получать сигналы о перекупленности/перепроданности рынка, сигналы об окончании тренда и о развороте ценового движения.
Роль статистических распределений в работе трейдера Роль статистических распределений в работе трейдера
Данная статья является логическим продолжением моей статьи "Статистические распределения вероятностей в MQL5", в которой были представлены классы для работы с некоторыми статистическими теоретическими распределениями. Теперь, когда есть теоретическая база, я предлагаю непосредственно перейти к выборкам реальных данных и попробовать получить информационную пользу от этой базы.
Как заказать написание советника и получить желаемый результат Как заказать написание советника и получить желаемый результат
Как правильно написать Техническое Задание? Что можно и чего нельзя ожидать от программиста при заказе советника или индикатора? Как нужно вести диалог, на какие моменты обратить внимание? Статья дает ответы на эти и многие другие вопросы, которые зачастую неочевидны для многих без самостоятельного набивания шишек.