Скачать MetaTrader 5

Подключение нейросетей от NeuroSolutions

19 января 2011, 12:10
Andrew
52
13 251

Введение

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

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

Да, это возможно. Некоторые нейросетевые программы имеют необходимые программные интерфейсы. Одна из таких программ называется NeuroSolutions. Последняя ее версия - 6-я, но она еще есть не у всех, а вот версией 5 пользуются многие. Поэтому в статье будет рассмотрено взаимодействие именно с 5-й версией. Нужен полный дистрибутив программы, туда входит Custom Solution Wizard, он нам понадобится.


Придумываем стратегию

Стратегия для нашего тестового примера будет простой. Назовем ее WeekPattern. На таймфрейме D1 с помощью нейросети она будет в начале текущего бара прогнозировать цену его закрытия. И в зависимости от этого будет открывать BUY или SELL и держать эту сделку весь день. Прогноз цены будет основываться на OHLC-значениях предыдущих 5-ти баров. Для повышения точности работы нейросети мы будем подавать в нее не сами цены, а лишь их изменения относительно цены открытия текущего (нулевого) бара.


Готовим обучающие данные

Прежде чем приступить к созданию сети, напишем MQL5-скрипт, который выгрузит из терминала котировки в нужном нам виде. Эти данные понадобятся чтобы обучить нейросеть. Выгрузка будет проводиться в текстовый файл. В первой его строке через запятую перечислим названия полей. А в следующих строках пойдут данные, разделенные запятой. Каждая строка - это одна комбинация входов и выходов нейросети. В нашем случае скрипт на каждой строке будет сдвигаться по ценовой истории в прошлое на один бар и записывать в строку OHLC-значения 6-ти баров (5 баров из прошлого - это входы, и один бар текущий - это выход).

Этот скрипт WeekPattern-Export.mq5 нужно запускать на нужном таймфрейме нужной валютной пары (в нашем примере это D1 EURUSD). В настройках указывается имя файла и сколько строк нужно (для D1 260 строк - это история примерно за 1 год). Полный код скрипта:

#property script_show_inputs
//+------------------------------------------------------------------+
input string    Export_FileName = "NeuroSolutions\\data.csv"; // Файл для экспорта (в папке "MQL5\Files")
input int       Export_Bars     = 260; // Кол-во строк данных для экспорта
//+------------------------------------------------------------------+
void OnStart() 
  {
  
   // Создадим файл
   int file = FileOpen(Export_FileName, FILE_WRITE|FILE_CSV|FILE_ANSI, ',');
   
   if (file != INVALID_HANDLE)
     {
      // Запишем заголовок данных
      
      string row="";
      for (int i=0; i<=5; i++)
        {
         if (StringLen(row)) row += ",";
         row += "Open"+i+",High"+i+",Low"+i+",Close"+i;
        }
      FileWrite(file, row);
      
      // Скопируем все нужные данные из истории
      
      MqlRates rates[], rate;
      int count = Export_Bars + 5;
      if (CopyRates(Symbol(), Period(), 1, count, rates) < count)
        {
         Print("Ошибка! Недостаточный размер истории для экспорта нужных данных.");
         return;
        }
      ArraySetAsSeries(rates, true);
      
      // Запишем данные      
      
      for (int bar=0; bar<Export_Bars; bar++)
        {
         row="";
         double zlevel=0;
         for (int i=0; i<=5; i++)
           {
            if (StringLen(row)) row += ",";
            rate = rates[bar+i];
            if (i==0) zlevel = rate.open; // уровень отсчета цен
            row += NormalizeDouble(rate.open -zlevel, Digits()) + ","
                 + NormalizeDouble(rate.high -zlevel, Digits()) + ","
                 + NormalizeDouble(rate.low  -zlevel, Digits()) + ","
                 + NormalizeDouble(rate.close-zlevel, Digits());
           }
         FileWrite(file, row);
        }

      FileClose(file);
      Print("Экспорт данных завершен успешно.");
     }
   else Print("Ошибка! Не удалось создать файл для экспорта данных. ", GetLastError());
  }
//+------------------------------------------------------------------+

После выгрузки данных получим файл data.csv, первые строки (для примера) выглядят примерно так:

Open0,High0,Low0,Close0,Open1,High1,Low1,Close1,Open2,High2,Low2,Close2,Open3,High3,Low3,Close3,Open4,High4,Low4,Close4,Open5,High5,Low5,Close5
0,0.00463,-0.0041,0.00274,-0.00518,0.00182,-0.00721,-6e-005,0.00561,0.00749,-0.00413,-0.00402,0.02038,0.02242,0.00377,0.00565,0.03642,0.0379,0.01798,0.02028,0.0405,0.04873,0.03462,0.03647
0,0.007,-0.00203,0.00512,0.01079,0.01267,0.00105,0.00116,0.02556,0.0276,0.00895,0.01083,0.0416,0.04308,0.02316,0.02546,0.04568,0.05391,0.0398,0.04165,0.04504,0.05006,0.03562,0.0456
0,0.00188,-0.00974,-0.00963,0.01477,0.01681,-0.00184,4e-005,0.03081,0.03229,0.01237,0.01467,0.03489,0.04312,0.02901,0.03086,0.03425,0.03927,0.02483,0.03481,0.02883,0.04205,0.02845,0.03809

Это формат, который NeuroSolutions понимает. Теперь мы можем приступить к построению и обучению сети.


Создаем нейросеть

В NeuroSolutions можно быстро создать нейросеть, даже видя эту программу в первый раз и мало разбираясь в нейросетях. Для этого при старте программы выбираем визард для новичков - NeuralExpert (Beginner):

Укажем ему тип задачи, который должна решать наша сеть:

Дадим ему файл с обучающими данными, который мы создали в прошлой главе:

В качестве входов сети пометим все поля файла, кроме полей 0-го бара:

Текстовых полей у нас нет - ничего не отмечаем:

Снова даем наш файл с данными:

Помечаем один-единственный выход нашей сети:

По умолчанию визард предлагает построить наиболее простую сеть. Так и сделаем:

Визард завершил свою работу, создав нам сеть (еще не обученную, просто структуру):

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

Если кликнуть на кнопку Test, то можно посмотреть, как необученная сеть справится с нашей задачей. Отвечаем на вопросы визарда тестирования:

Тестируем на данных всё из того же файла:

Тестирование завершилось. В окошке "Output vs. Desired Plot" появились графики, показывающие, какие значения выдает на нашей истории сеть (красный цвет), и какие там были значения на самом деле (синий цвет). Видно, что они сильно различаются:

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


Теперь по графикам видно, что сеть выдает "что-то, похожее на правду". Можно теперь использовать ее для торговли. Сохраним сеть под именем WeekPattern.


Экспортируем нейросеть в DLL

Не выходя из NeuroSolutions, кликнем вверху кнопку CSW, которая запустит Custom Solution Wizard. Он нужен, чтобы сгенерировать из текущей нейросети DLL.

Визард может генерировать DLL для разных программ. Как я понял, для компиляции DLL ему в любом случае понадобится Visual C++ одной из версий: 5.0/6.0/7.0 (.NET 2002)/7.1 (.NET 2003)/8.0 (.NET 2005). Версии Express он почему-то не использует (я это проверял).

MetaTrader в списке целевых программ нет. Поэтому выберем Visual C++.

Куда сохранить результат:

Если всё прошло успешно, визард об этом сообщит:

И в папке, указанной при работе визарда, появится много файлов. Самые нужные нам: WeekPattern.dll, в нем находится наша нейросеть с программным интерфейсом к ней; и файл WeekPattern.nsw с настройками весов сети после обучения. Среди остальных файлов есть пример работы с этой DLL-нейросетью. В данном случае это проект на Visual C++ 6.


Подключаем DLL-нейросеть к MetaTrader

Созданная в предыдущей главе DLL-нейросеть предназначена для использования в проектах Visual C++. Она оперирует объектами сложной структуры, которые было бы тяжело или даже невозможно описать на MQL5. Поэтому подключать эту DLL напрямую к MetaTrader мы не будем. Вместо этого создадим небольшой DLL-переходник. В этом переходнике будет содержаться одна-единственная простая функция работы с нейросетью. Она будет создавать сеть, передавать ей данные на вход и возвращать данные с выходов.

К этому переходнику легко можно будет обращаться из MetaTrader 5. А переходник уже будет обращаться к DLL-нейросети от NeuroSolutions. Так как переходник будет написан на Visual C++, у него не будет проблем с объектами этой DLL.




Вам нет нужды создавать DLL-переходник самим. К статье приложена готовая DLL. Переходник работает с любыми DLL-нейросетями от NeuroSolutions. Эту главу можно не читать дальше.

Ну а если вы имеете опыт программирования на C++ и вам интересно, как создать такой переходник, читайте главу до конца. Возможно, в будущем вы захотите его усовершенствовать - ведь из DLL-нейросети можно экспортировать еще какие-нибудь функции. Например, функцию обучения (чтобы советник мог  сам адаптироваться к меняющемуся рынку, автоматически переобучая сеть). Полный перечень функций вы можете узнать, изучив пример, который в предыдущей главе сгенерировал Custom Solution Wizard.

Нам пригодятся от этого примера некоторые файлы.

В Visual C++ (той же версии, которую использовал Custom Solution Wizard) создадим пустой проект DLL с именем NeuroSolutionsAdapter и скопируем в него из примера файлы NSNetwork.h, NSNetwork.cpp, StdAfx.h. Также создадим пустой файл main.cpp:


В main.cpp напишем следующий код:

#include "stdafx.h"
#include "NSNetwork.h"

extern "C" __declspec(dllexport) int __stdcall CalcNeuralNet(
                LPCWSTR dllPath_u, LPCWSTR weightsPath_u,
                double* inputs, double* outputs)
{       
    // Преобразуем строки из Unicode в обычные
    CString dllPath     (dllPath_u);
    CString weightsPath (weightsPath_u);

    // Создание сети
    NSRecallNetwork nn(dllPath);
    if (!nn.IsLoaded()) return (1);

    // Загрузка весов
    if (nn.LoadWeights(weightsPath) != 0) return (2);
        
    // Подача входных данных и расчет выходов
    if (nn.GetResponse(1, inputs, outputs) != 0) return (3);

    return 0;
}

Build. DLL-переходник готова!


Используем нейросеть в советнике

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

Файл
Описание
Куда положить (внутри папки терминала)
WeekPattern.dll
наша DLL-нейросеть от NeuroSolutions
MQL5\Files\NeuroSolutions\
WeekPattern.nswнастройки весов нашей нейросети
MQL5\Files\NeuroSolutions\
NeuroSolutionsAdapter.dll
универсальный DLL-переходник для любой DLL-нейросети
MQL5\Libraries\


Привожу полный код советника WeekPattern.mq5. Для удобства поиска и последующей модификации, я организовал в отдельный класс CNeuroSolutionsNeuralNet всё, что относится к нейросети.

input double    Lots = 0.1;
//+------------------------------------------------------------------+
// Подключаем DLL-переходник, через которую будем использовать DLL-нейросеть от NeuroSolutions
#import "NeuroSolutionsAdapter.dll"
int CalcNeuralNet(string dllPath, string weightsPath, double& inputs[], double& outputs[]);
#import 
//+------------------------------------------------------------------+
class CNeuroSolutionsNeuralNet
{
private:
   string dllPath;     // Путь к DLL-нейрости, созданной в NeuroSolutions
   string weightsPath; // Путь к файлу весов сети
public:
   double in[20]; // Входы сети - OHLC 5 баров
   double out[1]; // Выход сети - Close текущего бара

   CNeuroSolutionsNeuralNet();
   bool Calc();
};
//+------------------------------------------------------------------+
void CNeuroSolutionsNeuralNet::CNeuroSolutionsNeuralNet()
{
   string terminal = TerminalInfoString(TERMINAL_PATH);
   dllPath     = terminal + "\\MQL5\\Files\\NeuroSolutions\\WeekPattern.dll";
   weightsPath = terminal + "\\MQL5\\Files\\NeuroSolutions\\WeekPattern.nsw";
}
//+------------------------------------------------------------------+
bool CNeuroSolutionsNeuralNet::Calc()
  {
   // Получим текущие котировки для нейросети
   MqlRates rates[], rate;
   CopyRates(Symbol(), Period(), 0, 6, rates);
   ArraySetAsSeries(rates, true);
      
   // Заполним массив входных данных нейросети
   double zlevel=0;   
   for (int bar=0; bar<=5; bar++)
     {
      rate = rates[bar];
      // 0-й бар на вход сети не идет
      if (bar==0) zlevel=rate.open; // уровень отсчета цен
      // 1-5 бары идут на вход сети
      else
        {
         int i=(bar-1)*4; // номер входа
         in[i  ] = rate.open -zlevel;
         in[i+1] = rate.high -zlevel;
         in[i+2] = rate.low  -zlevel;
         in[i+3] = rate.close-zlevel;
        }
     }
 
   // Проведем расчет сети в DLL NeuroSolutions (через DLL-переходник)
   int res = CalcNeuralNet(dllPath, weightsPath, in, out);
   switch (res)
     {
      case 1: Print("Ошибка создания нейросети из DLL \"", dllPath, "\""); return (false);
      case 2: Print("Ошибка загрузки весов в нейросеть из файла \"", weightsPath, "\""); return (false);
      case 3: Print("Ошибка расчетов в нейросети");  return (false);
     }
     
   // Выход нейрости появился в массиве out, с ним ничего делать не надо

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

CNeuroSolutionsNeuralNet NN;
double Prognoze;

//+------------------------------------------------------------------+
#include <Trade\Trade.mqh>
//+------------------------------------------------------------------+
void OnTick() 
  {
   // Получим ценовой прогноз от нейросети
   if (NN.Calc()) Prognoze = NN.out[0];
   else           Prognoze = 0;

   // Осуществим необходимые торговые действия
   Trade();
  }
//+------------------------------------------------------------------+
void Trade() 
  {

   // Закроем открытую позицию, если она против прогноза

   if(PositionSelect(_Symbol)) 
     {
      long type=PositionGetInteger(POSITION_TYPE);
      bool close=false;
      if((type == POSITION_TYPE_BUY)  && (Prognoze <= 0)) close = true;
      if((type == POSITION_TYPE_SELL) && (Prognoze >= 0)) close = true;
      if(close) 
        {
         CTrade trade;
         trade.PositionClose(_Symbol);
        }
     }

   // Если позиций нет, то откроем по прогнозу

   if((Prognoze!=0) && (!PositionSelect(_Symbol))) 
     {
      CTrade trade;
      if(Prognoze > 0) trade.Buy (Lots);
      if(Prognoze < 0) trade.Sell(Lots);
     }
  }
//+------------------------------------------------------------------+


Хороший способ проверить, правильно ли мы подключили нейросеть, это прогнать советник в тестере на том же участке истории, где сеть обучалась.

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

Проверим это. В нашем случае получился вот такой красивый график:

Значит, мы всё подключили правильно.

Ну и для статистики другие отчеты о тестировании советника:



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

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

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

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


Заключение

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


Прикрепленные файлы |
dll_nsw.zip (383.37 KB)
weekpattern.mq5 (3.69 KB)
Последние комментарии | Перейти к обсуждению на форуме трейдеров (52)
collnice
collnice | 2 апр 2015 в 04:05
Alex_Eliseev:

Надеюсь кто-то еще просматривает этот раздел форума...

Подскажите в чем может быть проблемка...

 2015.02.09 23:39:15 Core 1 2015.02.01 00:00:00   Cannot load 'D:\Program Files\Alpari Limited MT5\Tester\Agent-127.0.0.1-3000\MQL5\Libraries\NeuroSolutionsAdapter.dll'

но по указанному адресу есть эта библиотека, так же я ее размножил и по некоторым другим директориям указанным в руководстве по MQL5

:( непомогло, кто сталкивался с таким поведением тестера? 

Вроде так
Artem Evdokimov
Artem Evdokimov | 28 июл 2015 в 22:37
Alex_Eliseev:

Надеюсь кто-то еще просматривает этот раздел форума...

Подскажите в чем может быть проблемка...

 2015.02.09 23:39:15 Core 1 2015.02.01 00:00:00   Cannot load 'D:\Program Files\Alpari Limited MT5\Tester\Agent-127.0.0.1-3000\MQL5\Libraries\NeuroSolutionsAdapter.dll'

но по указанному адресу есть эта библиотека, так же я ее размножил и по некоторым другим директориям указанным в руководстве по MQL5

:( непомогло, кто сталкивался с таким поведением тестера? 

Скорее всего у вас МТ5 х64. А библиотеки написаны для х32.
Andrey Aseev
Andrey Aseev | 2 сен 2015 в 14:10

как я это  делал без dll переходника:


ns-unit.mqh

#include "my-net\\Globals.h"

#import "my-net.dll"
int createNetwork(int &pNeuralNetwork, int networkType);
int destroyNetwork(int pNeuralNetwork);
int loadWeights(int pNeuralNetwork, uchar &weightsPathName[]);
int getResponse(int pNeuralNetwork, int exemplars, double &inputData[], double &outputData[]);
int train(int pNeuralNetwork, int epochs, int exemplars, double &inputData[], double &desiredData[], int cvExemplars, double &cvInputData[], double &cvDesiredData[]);
int saveWeights(int pNeuralNetwork, uchar &weightsPathName[]);
#import

int pNeuralNetwork;

bool NSInit()
{
  if (createNetwork(pNeuralNetwork, 1)!=0) return false;
  uchar str[];
  StringToCharArray(BEST_WEIGHTS_PATH_NAME, str);
  if (loadWeights(pNeuralNetwork, str)!=0) return false;
  return true;
}

void NSDeinit()
{
  destroyNetwork(pNeuralNetwork);
}

где,

my-net.dll - библиотека, которую создаёт по вашей сети NeuroSolutions

Globals.h - файл, который прилагается к вашей библиотеке после создания (перед компиляцией MQL скрипта его положить в подпапку "my-net")


а это добавить в основную программу:

#include "ns-unit.mqh"
void init()
{
  if (!NSInit())
  {
    Print("NeuroSolutions ошибка инициации");
    return -1;
  }
} 

void deinit()
{
  NSDeinit();
}


Далее, можно успешно пользоваться процедурами getResponse для чтения отклика сети по заданному входу и train для дообучения сети в реальном режиме.

Первым параметром для этих процедур будет всегда параметр pNeuralNetwork, в который записан адрес структуры сети.

Для процедуры train последние три параметра можно передавать нулевыми, если не требуется кросс-проверка.


Вот и всё. Проверено - работает :)

bill123
bill123 | 9 янв 2016 в 18:09

Надеюсь кто-то еще просматривает этот раздел форума...

С MQL5 всё понятно, огромное спасибо автору.

А вот кто поможет подключить dll-сеть к NinjaTrader (C#) ?

Сам разбираюсь, но осилить не могу. Помогите, плизз.

Dunja
Dunja | 11 окт 2016 в 19:26
Добрый день! Подскажите получилось у кого запустить робота на МТ4?
Графики и диаграммы в формате HTML Графики и диаграммы в формате HTML

Сегодня трудно найти компьютер, на котором не был бы установлен web-браузер. Браузеры уже на протяжении длительного времени постоянно развиваются и совершенствуются. В статье рассматривается простой, безопасный способ использования браузера для отображения в виде графиков и диаграмм полученной в MetaTrader 5 информации.

Эконометрический подход к анализу графиков Эконометрический подход к анализу графиков

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

Мастер MQL5: Как написать свой модуль сопровождения открытых позиций Мастер MQL5: Как написать свой модуль сопровождения открытых позиций

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

Новый индикатор технического анализа Moving Mini-Max и его реализация в MQL5 Новый индикатор технического анализа Moving Mini-Max и его реализация в MQL5

В статье рассматривается новый индикатор технического анализа Moving Mini-Max, разработанный З.К. Силагадзе в 2008 году. Индикатор основан на модели туннельного эффекта, предложенного Г. Гамовым в теории альфа-распада. Описывается реализация индикатора на MQL5 и возможности его использования в торговле.