Практическое применение нейросетей в трейдинге. Python (Часть I)

27 октября 2020, 13:24
Andrey Dibrov
12
2 947

Введение

В предыдущей статье "Практическое применение нейросетей в трейдинге. Переходим к практике" мы рассмотрели практическое использование нейросетевого модуля, реализованного на нейронных сетях Matlab. Но в ней были опущены вопросы подготовки входных данных, работы над обучением НС. В этой статье эти вопросы будут подняты в конкретных примерах и реализованы на нейронных сетях библиотек, работающих с Python. Однако принцип реализации торговой системы будет несколько иным. Этот вариант был кратко описан в пункте 5 базовой статьи "Практическое применение нейросетей в трейдинге". Для этого мы используем библиотеку машинного обучения TensorFlow, разработанной компанией Google. А для описания нейронных сетей используем библиотеку Keras.


1. Подготовка данных

Остановимся на нескольких моментах подготовки к обучению нейронных сетей.

  • В данной разработке, для принятия решения, мы будем использовать по две НС для открытия позиций в одном направлении
  • Исходя из предыдущего пункта, данные для обучения мы также разделим на два направления.
  • Как и в предыдущей системе, первая нейросеть у нас будет обучаться на построение индикаторов подобных стандартным техническим индикаторам. Такой вариант в предыдущей системе был обусловлен тем, что мы использовали само писанные индикаторы и нам не хотелось перегружать рабочий эксперт. На Python же это обусловлено тем, что от терминала мы можем получить только котировки, и тогда нам необходимо для подготовки данных для НС строить эти индикаторы в скрипте Python. Но научив нейронную сеть строить подобные индикаторы, мы обходим необходимость их дублировать в скрипте. 
  • Вторая нейросеть строит уже непосредственно сигнальный индикатор, на основе которого мы делаем стратегию торговли.
  • Обучать НС для часового графике пары EURUSD.
  • В результате для построения системы нам необходимо подготовить две НС для сделок на покупку и две на продажу. Всего в системе будет работать четыре нейронные сети.

Для подготовки данных для обучения сетей мы будем использовать два скрипта — PythonPrices.mq5 и PythonIndicators.mq5.

//+------------------------------------------------------------------+
//|                                                 PythonPrices.mq5 |
//|                                   Copyright 2020, Andrey Dibrov. |
//|                           https://www.mql5.com/ru/users/tomcat66 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, Andrey Dibrov."
#property link      "https://www.mql5.com/ru/users/tomcat66"
#property version   "1.00"
#property strict
#property script_show_inputs

input string Date="2004.07.01 00:00";
input string DateOut="2010.12.31 23:00";
input int History=0;

double inB[22];
string Date1;

int HandleInpuNet1Min;
int HandleInpuNet1Max;

double DibMin1_1[];
double DibMax1_1 [];
int DibMin1_1Handle;
int DibMax1_1Handle;

//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
   int k=iBars(NULL,PERIOD_H1)-1;

   DibMin1_1Handle=iCustom(NULL,PERIOD_H1,"DibMin1-1",History);
   CopyBuffer(DibMin1_1Handle,0,0,k,DibMin1_1);
   ArraySetAsSeries(DibMin1_1,true);

   DibMax1_1Handle=iCustom(NULL,PERIOD_H1,"DibMax1-1",History);
   CopyBuffer(DibMax1_1Handle,0,0,k,DibMax1_1);
   ArraySetAsSeries(DibMax1_1,true);

   HandleInpuNet1Min=FileOpen(Symbol()+"InputNet1Min.csv",FILE_CSV|FILE_WRITE|FILE_SHARE_READ|FILE_ANSI|FILE_COMMON,";");
   HandleInpuNet1Max=FileOpen(Symbol()+"InputNet1Max.csv",FILE_CSV|FILE_WRITE|FILE_SHARE_READ|FILE_ANSI|FILE_COMMON,";");
   FileSeek(HandleInpuNet1Min,0,SEEK_END);
   FileSeek(HandleInpuNet1Max,0,SEEK_END);

   if(HandleInpuNet1Min>0)
     {
      Alert("Идет запись файлf InputNet1Min");

      for(int i=iBars(NULL,PERIOD_H1)-1; i>=0; i--)
        {

         Date1=TimeToString(iTime(NULL,PERIOD_H1,i));

         if(DateOut>=Date1 && Date<=Date1)
           {
            if((DibMin1_1[i]==-1 && DibMin1_1[i+1]==1 && DibMax1_1[i]==1) || (DibMin1_1[i]==1 && DibMax1_1[i]==1))
              {
               for(int m=0; m<=14; m++)
                 {
                  inB[m]=inB[m+5];
                 }

               inB[15]=(iOpen(NULL,PERIOD_D1,iBarShift(NULL,PERIOD_D1,iTime(NULL,PERIOD_H1,i)))-iLow(NULL,PERIOD_D1,iBarShift(NULL,PERIOD_D1,iTime(NULL,PERIOD_H1,i))))*100000;
               inB[16]=(iHigh(NULL,PERIOD_D1,iBarShift(NULL,PERIOD_D1,iTime(NULL,PERIOD_H1,i)))-iOpen(NULL,PERIOD_D1,iBarShift(NULL,PERIOD_D1,iTime(NULL,PERIOD_H1,i))))*100000;
               inB[17]=(iHigh(NULL,PERIOD_D1,iBarShift(NULL,PERIOD_D1,iTime(NULL,PERIOD_H1,i)))-iLow(NULL,PERIOD_D1,iBarShift(NULL,PERIOD_D1,iTime(NULL,PERIOD_H1,i))))*10000;
               inB[18]=(iHigh(NULL,PERIOD_D1,iBarShift(NULL,PERIOD_D1,iTime(NULL,PERIOD_H1,i)))-iOpen(NULL,PERIOD_H1,i+1))*10000;
               inB[19]=(iOpen(NULL,PERIOD_H1,i+1)-iLow(NULL,PERIOD_D1,iBarShift(NULL,PERIOD_D1,iTime(NULL,PERIOD_H1,i))))*10000;

               inB[20]=(iHigh(NULL,PERIOD_D1,iBarShift(NULL,PERIOD_D1,iTime(NULL,PERIOD_H1,i)))-iOpen(NULL,PERIOD_H1,i))*10000;
               inB[21]=(iOpen(NULL,PERIOD_H1,i)-iLow(NULL,PERIOD_D1,iBarShift(NULL,PERIOD_D1,iTime(NULL,PERIOD_H1,i))))*10000;

               FileWrite(HandleInpuNet1Min,

                         inB[0],inB[1],inB[2],inB[3],inB[4],inB[5],inB[6],inB[7],inB[8],inB[9],inB[10],inB[11],inB[12],inB[13],inB[14],inB[15],
                         inB[16],inB[17],inB[18],inB[19],inB[20],inB[21]);
              }
           }
        }

      FileClose(HandleInpuNet1Min);
     }
//------------------------------------------------------------------------------------------------------------------------------------------------

   if(HandleInpuNet1Max>0)
     {
      Alert("Идет запись файлf InputNet1Max");

      for(int i=iBars(NULL,PERIOD_H1)-1; i>=0; i--)
        {

         Date1=TimeToString(iTime(NULL,PERIOD_H1,i));

         if(DateOut>=Date1 && Date<=Date1)
           {
            if((DibMax1_1[i]==-1 && DibMax1_1[i+1]==1 && DibMin1_1[i]==1)|| (DibMin1_1[i]==1 && DibMax1_1[i]==1))
              {
               for(int m=0; m<=14; m++)
                 {
                  inB[m]=inB[m+5];
                 }

               inB[15]=(iOpen(NULL,PERIOD_D1,iBarShift(NULL,PERIOD_D1,iTime(NULL,PERIOD_H1,i)))-iLow(NULL,PERIOD_D1,iBarShift(NULL,PERIOD_D1,iTime(NULL,PERIOD_H1,i))))*100000;
               inB[16]=(iHigh(NULL,PERIOD_D1,iBarShift(NULL,PERIOD_D1,iTime(NULL,PERIOD_H1,i)))-iOpen(NULL,PERIOD_D1,iBarShift(NULL,PERIOD_D1,iTime(NULL,PERIOD_H1,i))))*100000;
               inB[17]=(iHigh(NULL,PERIOD_D1,iBarShift(NULL,PERIOD_D1,iTime(NULL,PERIOD_H1,i)))-iLow(NULL,PERIOD_D1,iBarShift(NULL,PERIOD_D1,iTime(NULL,PERIOD_H1,i))))*10000;
               inB[18]=(iHigh(NULL,PERIOD_D1,iBarShift(NULL,PERIOD_D1,iTime(NULL,PERIOD_H1,i)))-iOpen(NULL,PERIOD_H1,i+1))*10000;
               inB[19]=(iOpen(NULL,PERIOD_H1,i+1)-iLow(NULL,PERIOD_D1,iBarShift(NULL,PERIOD_D1,iTime(NULL,PERIOD_H1,i))))*10000;

               inB[20]=(iHigh(NULL,PERIOD_D1,iBarShift(NULL,PERIOD_D1,iTime(NULL,PERIOD_H1,i)))-iOpen(NULL,PERIOD_H1,i))*10000;
               inB[21]=(iOpen(NULL,PERIOD_H1,i)-iLow(NULL,PERIOD_D1,iBarShift(NULL,PERIOD_D1,iTime(NULL,PERIOD_H1,i))))*10000;

               FileWrite(HandleInpuNet1Max,

                         inB[0],inB[1],inB[2],inB[3],inB[4],inB[5],inB[6],inB[7],inB[8],inB[9],inB[10],inB[11],inB[12],inB[13],inB[14],inB[15],
                         inB[16],inB[17],inB[18],inB[19],inB[20],inB[21]);
              }
           }
        }

      FileClose(HandleInpuNet1Max);
     }
   Alert("Файлы записаны");

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

//+------------------------------------------------------------------+
//|                                             PythonIndicators.mq5 |
//|                                   Copyright 2020, Andrey Dibrov. |
//|                           https://www.mql5.com/ru/users/tomcat66 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, Andrey Dibrov."
#property link      "https://www.mql5.com/ru/users/tomcat66"
#property version   "1.00"
#property strict
#property script_show_inputs

input string Date="2004.07.01 00:00";
input string DateOut="2010.12.31 23:00";
input int History=0;

double Stochastic0[];
double Stochastic1[];
double CCI_Open[];
double CCI_Low[];
double CCI_High[];
double Momentum_Open[];
double Momentum_Low[];
double Momentum_High[];
double RSI_Open[];
double RSI_Low[];
double RSI_High[];
double WPR[];
double MACD_Open[];
double MACD_Low[];
double MACD_High[];
double OsMA_Open[];
double OsMA_Low[];
double OsMA_High[];
double TriX_Open[];
double TriX_Low[];
double TriX_High[];
double BearsPower[];
double BullsPower[];
double ADX_MINUSDI[];
double ADX_PLUSDI[];
double StdDev_Open[];
double StdDev_Low[];
double StdDev_High[];

//--------------------------
double DibMin1_1[];
double DibMax1_1 [];

int DibMin1_1Handle;
int DibMax1_1Handle;
//--------------------------
double inB[60];
double inS[60];

string Date1;

int HandleInputNet2OutNet1Min;
int HandleOutNet2Min;
int HandleInputNet2OutNet1Max;
int HandleOutNet2Max;

//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
   int k=iBars(NULL,PERIOD_H1)-1;

//------ Дневной минимум

   DibMin1_1Handle=iCustom(NULL,PERIOD_H1,"DibMin1-1",History);
   CopyBuffer(DibMin1_1Handle,0,0,k,DibMin1_1);
   ArraySetAsSeries(DibMin1_1,true);

   DibMax1_1Handle=iCustom(NULL,PERIOD_H1,"DibMax1-1",History);
   CopyBuffer(DibMax1_1Handle,0,0,k,DibMax1_1);
   ArraySetAsSeries(DibMax1_1,true);

   int Stochastic_handle=iStochastic(NULL,PERIOD_H1,5,3,3,MODE_SMA,STO_LOWHIGH);
   CopyBuffer(Stochastic_handle,0,0,k,Stochastic0);
   CopyBuffer(Stochastic_handle,1,0,k,Stochastic1);
   ArraySetAsSeries(Stochastic0,true);
   ArraySetAsSeries(Stochastic1,true);

   int CCI_Open_handle=iCCI(NULL,PERIOD_H1,14,PRICE_OPEN);
   CopyBuffer(CCI_Open_handle,0,0,k,CCI_Open);
   ArraySetAsSeries(CCI_Open,true);

   int CCI_Low_handle=iCCI(NULL,PERIOD_H1,14,PRICE_LOW);
   CopyBuffer(CCI_Low_handle,0,0,k,CCI_Low);
   ArraySetAsSeries(CCI_Low,true);

   int Momentum_Open_handle=iMomentum(NULL,PERIOD_H1,14,PRICE_OPEN);
   CopyBuffer(Momentum_Open_handle,0,0,k,Momentum_Open);
   ArraySetAsSeries(Momentum_Open,true);

   int Momentum_Low_handle=iMomentum(NULL,PERIOD_H1,14,PRICE_LOW);
   CopyBuffer(Momentum_Low_handle,0,0,k,Momentum_Low);
   ArraySetAsSeries(Momentum_Low,true);

   int RSI_Open_handle=iRSI(NULL,PERIOD_H1,14,PRICE_OPEN);
   CopyBuffer(RSI_Open_handle,0,0,k,RSI_Open);
   ArraySetAsSeries(RSI_Open,true);

   int RSI_Low_handle=iRSI(NULL,PERIOD_H1,14,PRICE_LOW);
   CopyBuffer(RSI_Low_handle,0,0,k,RSI_Low);
   ArraySetAsSeries(RSI_Low,true);

   int WPR_handle=iWPR(NULL,PERIOD_H1,14);
   CopyBuffer(WPR_handle,0,0,k,WPR);
   ArraySetAsSeries(WPR,true);

   int MACD_Open_handle=iMACD(NULL,PERIOD_H1,12,26,9,PRICE_OPEN);
   CopyBuffer(MACD_Open_handle,0,0,k,MACD_Open);
   ArraySetAsSeries(MACD_Open,true);

   int MACD_Low_handle=iMACD(NULL,PERIOD_H1,12,26,9,PRICE_LOW);
   CopyBuffer(MACD_Low_handle,0,0,k,MACD_Low);
   ArraySetAsSeries(MACD_Low,true);

   int OsMA_Open_handle=iOsMA(NULL,PERIOD_H1,12,26,9,PRICE_OPEN);
   CopyBuffer(OsMA_Open_handle,0,0,k,OsMA_Open);
   ArraySetAsSeries(OsMA_Open,true);

   int OsMA_Low_handle=iOsMA(NULL,PERIOD_H1,12,26,9,PRICE_LOW);
   CopyBuffer(OsMA_Low_handle,0,0,k,OsMA_Low);
   ArraySetAsSeries(OsMA_Low,true);

   int TriX_Open_handle=iTriX(NULL,PERIOD_H1,14,PRICE_OPEN);
   CopyBuffer(TriX_Open_handle,0,0,k,TriX_Open);
   ArraySetAsSeries(TriX_Open,true);

   int TriX_Low_handle=iTriX(NULL,PERIOD_H1,14,PRICE_LOW);
   CopyBuffer(TriX_Low_handle,0,0,k,TriX_Low);
   ArraySetAsSeries(TriX_Low,true);

   int BearsPower_handle=iBearsPower(NULL,PERIOD_H1,13);
   CopyBuffer(BearsPower_handle,0,0,k,BearsPower);
   ArraySetAsSeries(BearsPower,true);

   int ADX_MINUSDI_handle=iADX(NULL,PERIOD_H1,14);
   CopyBuffer(ADX_MINUSDI_handle,2,0,k,ADX_MINUSDI);
   ArraySetAsSeries(ADX_MINUSDI,true);

   int StdDev_Open_handle=iStdDev(NULL,PERIOD_H1,20,0,MODE_SMA,PRICE_OPEN);
   CopyBuffer(StdDev_Open_handle,0,0,k,StdDev_Open);
   ArraySetAsSeries(StdDev_Open,true);

   int StdDev_Low_handle=iStdDev(NULL,PERIOD_H1,20,0,MODE_SMA,PRICE_LOW);
   CopyBuffer(StdDev_Low_handle,0,0,k,StdDev_Low);
   ArraySetAsSeries(StdDev_Low,true);
//---------------------------------------------------------------------------------------------------------------------------

   HandleInputNet2OutNet1Min=FileOpen(Symbol()+"InputNet2OutNet1Min.csv",FILE_CSV|FILE_WRITE|FILE_SHARE_READ|FILE_ANSI|FILE_COMMON,";");
   HandleOutNet2Min=FileOpen(Symbol()+"OutNet2Min.csv",FILE_CSV|FILE_WRITE|FILE_SHARE_READ|FILE_ANSI|FILE_COMMON,";");
   FileSeek(HandleInputNet2OutNet1Min,0,SEEK_END);
   FileSeek(HandleOutNet2Min,0,SEEK_END);

   if(HandleInputNet2OutNet1Min>0)
     {
      Alert("Идет запись файлов InputNet2OutNet1Min и OutNet2Min");

      for(int i=iBars(NULL,PERIOD_H1)-1; i>=0; i--)
        {
         Date1=TimeToString(iTime(NULL,PERIOD_H1,i));

         if(DateOut>=Date1 && Date<=Date1)
           {
            if(((DibMin1_1[i]==-1 && DibMin1_1[i+1]==1 && DibMax1_1[i]==1)) || (DibMin1_1[i]==1 && DibMax1_1[i]==1))

              {
               for(int m=0; m<=35; m++)
                 {
                  inB[m]=inB[m+12];
                 }

               inB[36]=Stochastic0[i];
               inB[37]=Stochastic1[i];
               inB[38]=CCI_Low[i];
               inB[39]=Momentum_Low[i];
               inB[40]=RSI_Low[i];;
               inB[41]=WPR[i+1];
               inB[42]=MACD_Low[i]*10000;
               inB[43]=OsMA_Low[i]*100000;
               inB[44]=TriX_Low[i]*100000;;
               inB[45]=BearsPower[i+1]*1000;
               inB[46]=ADX_MINUSDI[i+1];
               inB[47]=StdDev_Low[i]*10000;

               inB[48]=Stochastic0[i];
               inB[49]=Stochastic1[i];
               inB[50]=CCI_Open[i];
               inB[51]=Momentum_Open[i];
               inB[52]=RSI_Open[i];;
               inB[53]=WPR[i];
               inB[54]=MACD_Open[i]*10000;
               inB[55]=OsMA_Open[i]*100000;
               inB[56]=TriX_Open[i]*100000;;
               inB[57]=BearsPower[i]*1000;
               inB[58]=ADX_MINUSDI[i];
               inB[59]=StdDev_Open[i]*10000;

               FileWrite(HandleInputNet2OutNet1Min,
                         inB[0],inB[1],inB[2],inB[3],inB[4],inB[5],inB[6],inB[7],inB[8],inB[9],inB[10],inB[11],inB[12],inB[13],
                         inB[14],inB[15],inB[16],inB[17],inB[18],inB[19],inB[20],inB[21],inB[22],inB[23],inB[24],inB[25],inB[26],
                         inB[27],inB[28],inB[29],inB[30],inB[31],inB[32],inB[33],inB[34],inB[35],inB[36],inB[37],inB[38],inB[39],
                         inB[40],inB[41],inB[42],inB[43],inB[44],inB[45],inB[46],inB[47],inB[48],inB[49],inB[50],inB[51],inB[52],
                         inB[53],inB[54],inB[55],inB[56],inB[57],inB[58],inB[59]);

               FileWrite(HandleOutNet2Min,
                         (iOpen(NULL,PERIOD_D1,iBarShift(NULL,PERIOD_D1,iTime(NULL,PERIOD_H1,i)))-iOpen(NULL,PERIOD_H1,i))*10000);
              }
           }
        }
     }

   //------ Дневной максимум

   int CCI_High_handle=iCCI(NULL,PERIOD_H1,14,PRICE_HIGH);
   CopyBuffer(CCI_High_handle,0,0,k,CCI_High);
   ArraySetAsSeries(CCI_High,true);

   int Momentum_High_handle=iMomentum(NULL,PERIOD_H1,14,PRICE_HIGH);
   CopyBuffer(Momentum_High_handle,0,0,k,Momentum_High);
   ArraySetAsSeries(Momentum_High,true);

   int RSI_High_handle=iRSI(NULL,PERIOD_H1,14,PRICE_HIGH);
   CopyBuffer(RSI_High_handle,0,0,k,RSI_High);
   ArraySetAsSeries(RSI_High,true);

   int MACD_High_handle=iMACD(NULL,PERIOD_H1,12,26,9,PRICE_HIGH);
   CopyBuffer(MACD_High_handle,0,0,k,MACD_High);
   ArraySetAsSeries(MACD_High,true);

   int OsMA_High_handle=iOsMA(NULL,PERIOD_H1,12,26,9,PRICE_HIGH);
   CopyBuffer(OsMA_High_handle,0,0,k,OsMA_High);
   ArraySetAsSeries(OsMA_High,true);

   int TriX_High_handle=iTriX(NULL,PERIOD_H1,14,PRICE_HIGH);
   CopyBuffer(TriX_High_handle,0,0,k,TriX_High);
   ArraySetAsSeries(TriX_High,true);

   int BullsPower_handle=iBullsPower(NULL,PERIOD_H1,13);
   CopyBuffer(BullsPower_handle,0,0,k,BullsPower);
   ArraySetAsSeries(BullsPower,true);

   int ADX_PLUSDI_handle=iADX(NULL,PERIOD_H1,14);
   CopyBuffer(ADX_PLUSDI_handle,1,0,k,ADX_PLUSDI);
   ArraySetAsSeries(ADX_PLUSDI,true);

   int StdDev_High_handle=iStdDev(NULL,PERIOD_H1,20,0,MODE_SMA,PRICE_HIGH);
   CopyBuffer(StdDev_High_handle,0,0,k,StdDev_High);
   ArraySetAsSeries(StdDev_High,true);
//---------------------------------------------------------------------------------------------------------------------------

   HandleInputNet2OutNet1Max=FileOpen(Symbol()+"InputNet2OutNet1Max.csv",FILE_CSV|FILE_WRITE|FILE_SHARE_READ|FILE_ANSI|FILE_COMMON,";");
   HandleOutNet2Max=FileOpen(Symbol()+"OutNet2Max.csv",FILE_CSV|FILE_WRITE|FILE_SHARE_READ|FILE_ANSI|FILE_COMMON,";");
   FileSeek(HandleInputNet2OutNet1Max,0,SEEK_END);
   FileSeek(HandleOutNet2Max,0,SEEK_END);

   if(HandleInputNet2OutNet1Max>0)
     {
      Alert("Идет запись файлов InputNet2OutNet1Max и OutNet2Max");

      for(int i=iBars(NULL,PERIOD_H1)-1; i>=0; i--)
        {
         Date1=TimeToString(iTime(NULL,PERIOD_H1,i));

         if(DateOut>=Date1 && Date<=Date1)
           {
            if(((DibMax1_1[i]==-1 && DibMax1_1[i+1]==1 && DibMin1_1[i]==1)) || (DibMin1_1[i]==1 && DibMax1_1[i]==1))

              {
               for(int m=0; m<=35; m++)
                 {
                  inS[m]=inS[m+12];
                 }

               inS[36]=Stochastic0[i];
               inS[37]=Stochastic1[i];
               inS[38]=CCI_High[i];
               inS[39]=Momentum_High[i];
               inS[40]=RSI_High[i];;
               inS[41]=WPR[i+1];
               inS[42]=MACD_High[i]*10000;
               inS[43]=OsMA_High[i]*100000;
               inS[44]=TriX_High[i]*100000;;
               inS[45]=BullsPower[i+1]*1000;
               inS[46]=ADX_PLUSDI[i+1];
               inS[47]=StdDev_High[i]*10000;

               inS[48]=Stochastic0[i];
               inS[49]=Stochastic1[i];
               inS[50]=CCI_Open[i];
               inS[51]=Momentum_Open[i];
               inS[52]=RSI_Open[i];;
               inS[53]=WPR[i];
               inS[54]=MACD_Open[i]*10000;
               inS[55]=OsMA_Open[i]*100000;
               inS[56]=TriX_Open[i]*100000;;
               inS[57]=BullsPower[i]*1000;
               inS[58]=ADX_PLUSDI[i];
               inS[59]=StdDev_Open[i]*10000;

               FileWrite(HandleInputNet2OutNet1Max,
                         inS[0],inS[1],inS[2],inS[3],inS[4],inS[5],inS[6],inS[7],inS[8],inS[9],inS[10],inS[11],inS[12],inS[13],
                         inS[14],inS[15],inS[16],inS[17],inS[18],inS[19],inS[20],inS[21],inS[22],inS[23],inS[24],inS[25],inS[26],
                         inS[27],inS[28],inS[29],inS[30],inS[31],inS[32],inS[33],inS[34],inS[35],inS[36],inS[37],inS[38],inS[39],
                         inS[40],inS[41],inS[42],inS[43],inS[44],inS[45],inS[46],inS[47],inS[48],inS[49],inS[50],inS[51],inS[52],
                         inS[53],inS[54],inS[55],inS[56],inS[57],inS[58],inS[59]);

               FileWrite(HandleOutNet2Max,
                         (iOpen(NULL,PERIOD_H1,i)-iOpen(NULL,PERIOD_D1,iBarShift(NULL,PERIOD_D1,iTime(NULL,PERIOD_H1,i))))*10000);
              }
           }
        }
     }

   Alert("Файлы записаны");
  }
//+------------------------------------------------------------------+

Одну выборку мы будем делать от начала рабочего дня до достижения первым минимума дня, вторую до достижения первым максимума дня. Для этого в скриптах мы будем использовать два индикатора DibMin1-1.mq5 и DibMax1-1.mq5

//+------------------------------------------------------------------+
//|                                                    DibMin1-1.mq5 |
//|                                   Copyright 2020, Andrey Dibrov. |
//|                           https://www.mql5.com/ru/users/tomcat66 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, Andrey Dibrov."
#property link      "https://www.mql5.com/ru/users/tomcat66"
#property version   "1.00"
#property indicator_separate_window
#property indicator_buffers 1
#property indicator_plots   1
#property indicator_type1   DRAW_LINE
#property indicator_minimum -2
#property indicator_maximum 2
#property indicator_color1 Red
#property indicator_label1  "DibMin1-1"
//---- input parameters
input int History=500;
double Buf[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0,Buf,INDICATOR_DATA);
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| 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    i,z,Calc;
   double price;

   i=iBars(NULL,PERIOD_H1)-1;
   if(i>History-1)
      i=History-1;
   if(History==0)
      i=iBars(NULL,PERIOD_H1)-1;
   ArraySetAsSeries(Buf,true);
   ArraySetAsSeries(time,true);

   while(i>=0)
     {
      int min=0;
      Calc=(int)time[i]%86400/3600;
      double min1=iLow(NULL,PERIOD_D1,iBarShift(NULL,PERIOD_D1,iTime(NULL,PERIOD_H1,i)));
      for(z=0;z<=Calc;z++)
        {
          price=iLow(NULL,PERIOD_H1,i+z);
          if(min1<price)
          {
           min=1;
          }else
          {
           min=-1;
          break;
          }
         }
      Buf[i]=min;
      i--;
     }
   return(rates_total);
  }
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//|                                                    DibMax1-1.mq5 |
//|                                   Copyright 2020, Andrey Dibrov. |
//|                           https://www.mql5.com/ru/users/tomcat66 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, Andrey Dibrov."
#property link      "https://www.mql5.com/ru/users/tomcat66"
#property version   "1.00"
#property indicator_separate_window
#property indicator_buffers 1
#property indicator_plots   1
#property indicator_type1   DRAW_LINE 
#property indicator_minimum -2
#property indicator_maximum 2
#property indicator_color1 LightSeaGreen
#property indicator_label1  "DibMax1-1"
//---- input parameters
input int History=500;
double Buf[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0,Buf,INDICATOR_DATA);
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| 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    i,z,Calc;
   double price;
   
   i=iBars(NULL,PERIOD_H1)-1;
   if (i>History-1)i=History-1;
   if (History==0) i=iBars(NULL,PERIOD_H1)-1;
   ArraySetAsSeries(Buf,true);
   ArraySetAsSeries(time,true);
   
   while(i>=0)
     {
      int max=0;
      Calc=(int)time[i]%86400/3600;
      double max1=iHigh(NULL,PERIOD_D1,iBarShift(NULL,PERIOD_D1,iTime(NULL,PERIOD_H1,i)));
      for(z=0;z<=Calc;z++)
        {
          price=iHigh(NULL,PERIOD_H1,i+z);//+1-1
          if(max1>price)
          {
           max=1;
          }else
          {
           max=-1;
           break;
          }
         }   
      Buf[i]=max;
      i--;
      } 
   return(rates_total);
  }
//+------------------------------------------------------------------+

Индикаторы для выборки

По достижению ценой дневных экстремумов индикаторы принимают значения равные -1.

После отработки на графике EURUSDH1 этих скриптов в папке \Common\Files мы получим шесть файлов в формате CSV.

  • EURUSDInputNet1Max и EURUSDInputNet1Min — файлы с ценовыми данными. В названии файла мы видим, что, например, файл EURUSDInputNet1Max является файлом входных данных для нейронной сети Net1Max.
  • EURUSDInputNet2OutNet1Max и EURUSDInputNet2OutNet1Min — файлы со значениями индикаторов. Эти значения будут входами для Net2 и выходами для Net1. Сразу же отмечу, что здесь надо экспериментировать — обучать Net2 можно либо на стандартных технических индикаторах, либо на откликах Net1.
  • EURUSDOutNet2Max и EURUSDOutNet2Min — выходы для Net2: ценовая разница между ценой открытием часа и открытия дня (либо закрытия дня и и открытием часа).

  1. Нейронные сети мы обучаем на приближении цены к ее экстремумам, интерпретируя не саму цену, а индикаторные значения.
  2. Целями НС для нас является разница между ценами открытием часа и открытия дня (закрытия дня и открытия часа). Здесь также можно экспериментировать, ставя перед НС другие цели — допустим, разницу между другими ценами. 
  3. При таком подходе мы сглаживаем вероятности ошибочных откликов в целом нейросетевых модулей, так как обучаем НС не конкретно на поиск максимальной либо минимальной цен дня, но и на вероятность приближения к ним, учитывая амплитуду цен до дневного экстремума. Если же мы решим ориентироваться на амплитуду цен после, то можно использовать разницу цен между закрытием дня и открытием часа. Думаю, что первый вариант предпочтительнее, так как в этом случае мы обучаем НС на достигнутых целях, а не на событиях, которые должны только произойти. Что, согласитесь, логичнее. Ведь оценивать прошедшие события легче, чем давать прогнозы.

2. Обучение нейронных сетей Python

Первое, что нам надо сделать — это воспользоваться справочником MQL5 разделом "Интеграция". После установки Python 3.8 и подключения модуля интеграции MetaTrader5 таким же образом подключим библиотеки TensorFlow, Keras, Numpy и Pandas.

Установка TensorFlow


Окно установки TensorFlow


Для обучения нейросетей будем использовать скрипт Python — EURUSDPyTren.py

import numpy as np
import pandas as pd
import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from tensorflow.keras.models import load_model

InputNet1=pd.read_csv('EURUSDInputNet1Min.csv', delimiter=';',header=None)
InputNet2OutNet1=pd.read_csv('EURUSDInputNet2OutNet1Min.csv', delimiter=';',header=None)
OutNet2=pd.read_csv('EURUSDOutNet2Min.csv', delimiter=';',header=None)

mean = InputNet1.mean(axis=0)
std = InputNet1.std(axis=0)
InputNet1 -= mean
InputNet1 /= std

mean = InputNet2OutNet1.mean(axis=0)
std = InputNet2OutNet1.std(axis=0)
InputNet2OutNet1 -= mean
InputNet2OutNet1 /= std

Net1Min = Sequential()
Net1Min.add(Dense(22, activation='relu', input_shape=(InputNet1.shape[1],)))
Net1Min.add(Dense(60))

Net1Min.compile(optimizer='adam', loss='mse', metrics=['mse'])
print(Net1Min.summary())

Net1Min.fit(InputNet1, InputNet2OutNet1, epochs=10, batch_size=10,verbose=2,validation_split=0.3)
Net1Min.save('net1Min.h5')

mean = OutNet2.mean(axis=0)
std = OutNet2.std(axis=0)
OutNet2 -= mean
OutNet2 /= std

Net2Min = Sequential()
Net2Min.add(Dense(60, activation='relu', input_shape=(InputNet2OutNet1.shape[1],)))
Net2Min.add(Dense(1))

Net2Min.compile(optimizer='adam', loss='mse', metrics=['mae'])
print(Net2Min.summary())

Net2Min.fit(InputNet2OutNet1, OutNet2, epochs=100, batch_size=10,verbose=2,validation_split=0.3)
Net2Min.save('net2Min.h5')

InputNet1=pd.read_csv('EURUSDInputNet1Max.csv', delimiter=';',header=None)
InputNet2OutNet1=pd.read_csv('EURUSDInputNet2OutNet1Max.csv', delimiter=';',header=None)
OutNet2=pd.read_csv('EURUSDOutNet2Max.csv', delimiter=';',header=None)

mean = InputNet1.mean(axis=0)
std = InputNet1.std(axis=0)
InputNet1 -= mean
InputNet1 /= std

mean = InputNet2OutNet1.mean(axis=0)
std = InputNet2OutNet1.std(axis=0)
InputNet2OutNet1 -= mean
InputNet2OutNet1 /= std

Net1Max = Sequential()
Net1Max.add(Dense(22, activation='relu', input_shape=(InputNet1.shape[1],)))
Net1Max.add(Dense(60))

Net1Max.compile(optimizer='adam', loss='mse', metrics=['mse'])
print(Net1Max.summary())

Net1Max.fit(InputNet1, InputNet2OutNet1, epochs=10, batch_size=10,verbose=2,validation_split=0.3)
Net1Max.save('net1Max.h5')

mean = OutNet2.mean(axis=0)
std = OutNet2.std(axis=0)
OutNet2 -= mean
OutNet2 /= std

Net2Max = Sequential()
Net2Max.add(Dense(60, activation='relu', input_shape=(InputNet2OutNet1.shape[1],)))
Net2Max.add(Dense(1))

Net2Max.compile(optimizer='adam', loss='mse', metrics=['mae'])
print(Net2Max.summary())

Net2Max.fit(InputNet2OutNet1, OutNet2, epochs=100, batch_size=10,verbose=2,validation_split=0.3)
Net2Max.save('net2Max.h5')

NetTest=pd.read_csv('EURUSDTest.csv', delimiter=';',header=None)
Date=pd.read_csv('EURUSDDate.csv', delimiter=';',header=None)

Net1Min = load_model('net1Min.h5')
Net2Min=  load_model('net2Min.h5')
Net1Max = load_model('net1Max.h5')
Net2Max=  load_model('net2Max.h5')
Net1Min = Net1Min.predict(NetTest)
Net2Min = Net2Min.predict(Net1Min)
Net1Max = Net1Max.predict(NetTest)
Net2Max = Net2Max.predict(Net1Max)

Date=pd.DataFrame(Date)
Date['0'] = Net2Min
Date.to_csv('IndicatorMin.csv',index=False, header=False,sep=';')
Date['0'] = Net2Max
Date.to_csv('IndicatorMax.csv',index=False, header=False,sep=';')

Date['0'] = Net2Min
Date['1'] = Net2Max
Date.to_csv('Indicator.csv',index=False, header=False,sep=';')

input('Press ENTER to exit') 

Данный скрипт мы так же поместим в папку \Common\Files .

Посмотрим на скрипт повнимательнее.
import numpy as np
import pandas as pd
import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from tensorflow.keras.models import load_model

Блок подключения библиотек, пакетов и модулей из Keras.

InputNet1=pd.read_csv('EURUSDInputNet1Min.csv', delimiter=';',header=None)
InputNet2OutNet1=pd.read_csv('EURUSDInputNet2OutNet1Min.csv', delimiter=';',header=None)
OutNet2=pd.read_csv('EURUSDOutNet2Min.csv', delimiter=';',header=None)

Формируем из файлов данных dataframe.

mean = InputNet1.mean(axis=0)
std = InputNet1.std(axis=0)
InputNet1 -= mean
InputNet1 /= std
Стандартизируем данные.
Net1Min = Sequential()
Net1Min.add(Dense(22, activation='relu', input_shape=(InputNet1.shape[1],)))
Net1Min.add(Dense(60))

Последовательная модель сети, входной слой 22 нейрона, выходной - 60.

Net1Min = Sequential()
Net1Min.add(Dense(22, activation='relu', input_shape=(InputNet1.shape[1],)))
Net1Min.add(Dense(11))
Net1Min.add(Dense(60))
Можно поэкспериментировать и добавить скрытый слой.
Net1Max.compile(optimizer='adam', loss='mse', metrics=['mse'])
print(Net1Max.summary())

Компилируем сеть и напечатаем ее параметры.

Net1Min.fit(InputNet1, InputNet2OutNet1, epochs=10, batch_size=10,verbose=2,validation_split=0.3)
Net1Min.save('net1Min.h5')

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

NetTest=pd.read_csv('EURUSDTest.csv', delimiter=';',header=None)
Date=pd.read_csv('EURUSDDate.csv', delimiter=';',header=None)

Сформируем dataframe для тестирования.

Net1Min = load_model('net1Min.h5')
Net2Min=  load_model('net2Min.h5')
Net1Max = load_model('net1Max.h5')
Net2Max=  load_model('net2Max.h5')
Net1Min = Net1Min.predict(NetTest)
Net2Min = Net2Min.predict(Net1Min)
Net1Max = Net1Max.predict(NetTest)
Net2Max = Net2Max.predict(Net1Max)

Загрузим сохраненные нейронные сети и получим от них результат.

Date=pd.DataFrame(Date)
Date['0'] = Net2Min
Date.to_csv('IndicatorMin.csv',index=False, header=False,sep=';')
Date['0'] = Net2Max
Date.to_csv('IndicatorMax.csv',index=False, header=False,sep=';')

Date['0'] = Net2Min
Date['1'] = Net2Max
Date.to_csv('Indicator.csv',index=False, header=False,sep=';')

Сохраним полученные данные в файлы.

input('Press ENTER to exit') 
Ожидание закрытие окна.

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

С этой целью мы используем эксперт PythonTestExpert.

//+------------------------------------------------------------------+
//|                                             PythonTestExpert.mq5 |
//|                                   Copyright 2020, Andrey Dibrov. |
//|                           https://www.mql5.com/ru/users/tomcat66 |
//+------------------------------------------------------------------+
#property copyright " Copyright © 2019, Andrey Dibrov."
#property link      "https://www.mql5.com/ru/users/tomcat66"
#property version   "1.00"
#property strict

int handleInput;
int HandleDate;

double in[22];
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   handleInput=FileOpen(Symbol()+"Test.csv",FILE_CSV|FILE_WRITE|FILE_SHARE_READ|FILE_ANSI|FILE_COMMON,";");
   HandleDate=FileOpen(Symbol()+"Date.csv",FILE_CSV|FILE_READ|FILE_WRITE|FILE_ANSI|FILE_COMMON,";");
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   FileClose(handleInput);
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   for(int i=0; i<=14; i++)
     {
      in[i]=in[i+5];
     }

   in[15]=((iOpen(NULL,PERIOD_D1,0)-iLow(NULL,PERIOD_D1,0))*100000);
   in[16]=((iHigh(NULL,PERIOD_D1,0)-iOpen(NULL,PERIOD_D1,0))*100000);
   in[17]=((iHigh(NULL,PERIOD_D1,0)-iLow(NULL,PERIOD_D1,0))*100000);
   in[18]=((iHigh(NULL,PERIOD_D1,0)-iOpen(NULL,PERIOD_H1,1))*10000);
   in[19]=((iOpen(NULL,PERIOD_H1,1)-iLow(NULL,PERIOD_D1,0))*10000);


   in[20]=((iHigh(NULL,PERIOD_D1,0)-iOpen(NULL,PERIOD_H1,0))*10000);
   in[21]=((iOpen(NULL,PERIOD_H1,0)-iLow(NULL,PERIOD_D1,0))*10000);


   FileWrite(handleInput,

             in[0],in[1],in[2],in[3],in[4],in[5],in[6],in[7],in[8],in[9],in[10],in[11],in[12],in[13],in[14],in[15],
             in[16],in[17],in[18],in[19],in[20],in[21]);

   FileWrite(HandleDate,TimeCurrent());

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

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

Запуск эксперта для формирования тестовых данных

В папке \Common этот эксперт создаст нам два файла EURUSDTest и EURUSDDate.

Запустим скрипт Python EURUSDPyTren.py. (Если он не будет работать, то может понадобиться переустановка дополнительных пакетов, которые мы устанавливали ранее и перезагрузка компьютера). Если мы все сделали правильно, то скрипт будет запускаться двойным щелчком.

Работа скрипта

В результате в папке \Common\Files мы получим такие файлы - 

  • net1Max.h5, net1Min.h5, net2Max.h5, net2Min.h5 — обученные нейронные сети, которые будут использоваться в рабочем скрипте при ведении торговли в реальном времени.
  • IndicatorMax и IndicatorMin — два отклика НС для раздельного тестирования.
  • Indicator — совмещенный отклик.

Папка \Common\Files


В торговом терминале запустим индикатор 1_MT5.

//+------------------------------------------------------------------+
//|                                                        1_MT5.mq5 |
//|                                 Copyright © 2019, Andrey Dibrov. |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2019, Andrey Dibrov."
//--- indicator settings
#property indicator_separate_window
#property indicator_buffers 2
#property indicator_plots   2
#property indicator_type1   DRAW_LINE
#property indicator_type2   DRAW_LINE
#property indicator_color1  Red
#property indicator_color2  DodgerBlue

int Handle;
int i;

double    ExtBuffer[];
double    SignBuffer[];

datetime Date1;
datetime Date0;

string File_Name="Indicator.csv";

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
void OnInit()
  {
   SetIndexBuffer(0,ExtBuffer,INDICATOR_DATA);
   SetIndexBuffer(1,SignBuffer,INDICATOR_DATA);

   IndicatorSetInteger(INDICATOR_DIGITS,5);

  }
//+------------------------------------------------------------------+
//| Relative Strength Index                                          |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const int begin,
                const double &price[])
  {

   Handle=FileOpen(File_Name,FILE_CSV|FILE_SHARE_READ|FILE_ANSI|FILE_COMMON,";");

   Date0=StringToTime(FileReadString(Handle));

   FileClose(Handle);

   i=iBarShift(NULL,PERIOD_H1,Date0,false);
   
   Handle=FileOpen(File_Name,FILE_CSV|FILE_SHARE_READ|FILE_ANSI|FILE_COMMON,";");
  
   ArraySetAsSeries(ExtBuffer,true);
   ArraySetAsSeries(SignBuffer,true);

   while(!FileIsEnding(Handle) && !IsStopped())
     {
      Date1=StringToTime(FileReadString(Handle));
      ExtBuffer[i]=StringToDouble(FileReadString(Handle));
      SignBuffer[i]=StringToDouble(FileReadString(Handle));
      i--;
     }
  
   FileClose(Handle);

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

Индикатор

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

3. Оптимизация полученных результатов.

Для оптимизации полученного индикатора воспользуемся экспертом PythonOptimizExpert. 

//+------------------------------------------------------------------+
//|                                          PythonOptimizExpert.mq5 |
//|                                   Copyright 2020, Andrey Dibrov. |
//|                           https://www.mql5.com/ru/users/tomcat66 |
//+------------------------------------------------------------------+
#property copyright " Copyright © 2019, Andrey Dibrov."
#property link      "https://www.mql5.com/ru/users/tomcat66"
#property version   "1.00"
#property strict

#include<Trade\Trade.mqh>

CTrade  trade;

input int H1;
input int H2;
input int H3;
input int H4;

input double Buy;
input double Buy1;
input double Sell;
input double Sell1;

input int LossBuy;
input int ProfitBuy;
input int LossSell;
input int ProfitSell;

ulong TicketBuy1;
ulong TicketSell0;

datetime Count;

double Buf_0[];
double Buf_1[];

bool send1;
bool send0;

int k;
int K;
int bars;
int Handle;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---

   Handle=FileOpen("Indicator.csv",FILE_CSV|FILE_SHARE_READ|FILE_ANSI|FILE_COMMON,";");

   while(!FileIsEnding(Handle)&& !IsStopped())
     {
      StringToTime(FileReadString(Handle));
      bars++;
     }
   FileClose(Handle);

   ArrayResize(Buf_0,bars);
   ArrayResize(Buf_1,bars);

   Handle=FileOpen("Indicator.csv",FILE_CSV|FILE_SHARE_READ|FILE_ANSI|FILE_COMMON,";");

   while(!FileIsEnding(Handle)&& !IsStopped())
     {
      Count=StringToTime(FileReadString(Handle));
      Buf_0[k]=StringToDouble(FileReadString(Handle));
      Buf_1[k]=StringToDouble(FileReadString(Handle));
      k++;
     }
   FileClose(Handle);

   int deviation=10;
   trade.SetDeviationInPoints(deviation);
   trade.SetTypeFilling(ORDER_FILLING_RETURN);
   trade.SetAsyncMode(true);
//---
   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---

  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   MqlDateTime stm;
   TimeToStruct(TimeCurrent(),stm);

   int    digits=(int)SymbolInfoInteger(_Symbol,SYMBOL_DIGITS);
   double point=SymbolInfoDouble(_Symbol,SYMBOL_POINT);
   double PriceAsk=SymbolInfoDouble(_Symbol,SYMBOL_ASK);
   double PriceBid=SymbolInfoDouble(_Symbol,SYMBOL_BID);

   double SL1=NormalizeDouble(PriceBid-LossBuy*point,digits);
   double TP1=NormalizeDouble(PriceAsk+ProfitBuy*point,digits);
   double SL0=NormalizeDouble(PriceAsk+LossSell*point,digits);
   double TP0=NormalizeDouble(PriceBid-ProfitSell*point,digits);

   if(LossBuy==0)
      SL1=0;

   if(ProfitBuy==0)
      TP1=0;

   if(LossSell==0)
      SL0=0;

   if(ProfitSell==0)
      TP0=0;

//---------Buy1
   if(send1==false && K>0 &&  Buf_0[K]<Buy && Buy<Buy1 && iLow(NULL,PERIOD_H1,1)<iLow(NULL,PERIOD_H1,2) && stm.hour>H1 && stm.hour<H2 && H1<H2)
     {
      send1=trade.PositionOpen(_Symbol,ORDER_TYPE_BUY,1,PriceAsk,SL1,TP1);//SL1,TP1
      TicketBuy1 = trade.ResultDeal();
     }

   if(send1==true && K>0 &&  Buf_0[K]>Buy1 &&  Buy<Buy1 && iHigh(NULL,PERIOD_H1,1)>iHigh(NULL,PERIOD_H1,2) )
     {
      trade.PositionClose(TicketBuy1);
      send1=false;
     }

//---------Sell0

   if(send0==false && K>0 &&  Buf_1[K]<Sell && Sell<Sell1 && iHigh(NULL,PERIOD_H1,1)>iHigh(NULL,PERIOD_H1,2) && stm.hour>H3 && stm.hour<H4 && H3<H4)
     {
      send0=trade.PositionOpen(_Symbol,ORDER_TYPE_SELL,1,PriceBid,SL0,TP0);//SL0,TP0
      TicketSell0 = trade.ResultDeal();
     }

   if(send0==true && K>0 &&  Buf_1[K]>Sell1 && Sell<Sell1 && iLow(NULL,PERIOD_H1,1)<iLow(NULL,PERIOD_H1,2) )
     {
      trade.PositionClose(TicketSell0);
      send0=false;
     }
   K++;
  }

//+------------------------------------------------------------------+
//| Tester function                                                  |
//+------------------------------------------------------------------+
double OnTester()
  {
//---
   double ret=0.0;
//---

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

У нас есть такие переменные, которые мы можем оптимизировать

  • Н1, Н2 — часы дня, между которыми будет происходить покупка.
  • Н3 ,H4 — часы дня, между которыми будет происходить продажа.
  • Buy, Buy1 — в данном варианте уровни красной линии индикатора Buf_0[] — отклик НС обученной на данных до минимума дня.
  • Sell, Sell1 — в данном варианте, уровни синей линии индикатора Buf_1[] — отклик НС обученной на данных до максимума дня.
  • LossBuy, ProfitBuy, LossSell, ProfitSell — ограничительные уровни.

Выставим параметры оптимизации, как показано на рисунке. То есть будем оптимизировать только уровни индикатора.

Оптимизируемые уровни

Оптимизируемые индикаторные уровни

Оптимизация

Параметры оптимизации

Параметры оптимизации

Результаты оптимизации

Оптимизация

Оптимизация

Оптимизация


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

Тест Тест


По полученным параметрам проведем дальнейшую оптимизацию по времени и стоп приказам.

Оптимизация по полученным параметрам

Оптимизация по полученным параметрам

Оптимизация по полученным параметрам

Протестируем по всем параметрам.

Тест по полученным параметрам

Тест по полученным параметрам

Конечно можно оптимизировать каждое направление торговли отдельно.

Заключение

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



Прикрепленные файлы |
EURUSDPyTren.py (3.47 KB)
PythonPrices.mq5 (11.47 KB)
DibMax1-1.mq5 (5.11 KB)
DibMin1-1.mq5 (5.08 KB)
Последние комментарии | Перейти к обсуждению на форуме трейдеров (12)
Vladimir Perervenko
Vladimir Perervenko | 2 ноя 2020 в 11:48

4. По скрипту Python - да может я, хотел слишком упростить... Но перед собой я ставил в данной статье цель - показать простоту практического применения нейронных сетей с помощью интеграции Python. На данной стадии - получение входных данных, обучение и тестирование. " Нажми на кнопку и получи результат". Не знаю, раскрыта ли эта тема в таком виде? Не мною. Другими. Но я хотел этим поделиться...

5. И в качестве шутки по вопросу абсурда - не абсурд ли смотреть в ящик на набор формул, которые обозвали техническими индикаторами и пытаться заработать денег!!!))).

 "показать простоту практического применения нейронных сетей с помощью интеграции Python"  Вам не удалось. Ту процедуру которую Вы предлагаете нельзя назвать простой. А интеграции так вообще нет. 

"получение входных данных, обучение и тестирование" - это все можно и нужно выполнять в Python. пакет MetaTrader5 для этого собственно и написан. 

Без оптимизации гиперпараметров нейросети  и качественной подготовки входных данных ни о каком серьезном результате говорить не приходится. В Python есть все для выполнения этих архиважных и не простых этапов. В вашей статье этого нет.

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

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

Удачи

Andrey Dibrov
Andrey Dibrov | 3 ноя 2020 в 09:46
Vladimir Perervenko:

 "показать простоту практического применения нейронных сетей с помощью интеграции Python"  Вам не удалось. Ту процедуру которую Вы предлагаете нельзя назвать простой. А интеграции так вообще нет. 

"получение входных данных, обучение и тестирование" - это все можно и нужно выполнять в Python. пакет MetaTrader5 для этого собственно и написан. 

Без оптимизации гиперпараметров нейросети  и качественной подготовки входных данных ни о каком серьезном результате говорить не приходится. В Python есть все для выполнения этих архиважных и не простых этапов. В вашей статье этого нет.

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

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

Удачи

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

По вопросу интеграции... Весь творческий процесс происходит на этапах описанных в данной статье, особенно на получении входных данных и выборках этих данных. Лично я использую для этого собственные индикаторы. И сейчас вас немного напрягу))) - на данном этапе развития нейронных сетей гиперпараметры для анализа чистого временного ряда особого значения не имеют. В основном НС сейчас "заточены" под робототехнику(в широком понимании). Для классификации. То есть они работают отлично на законченных образах. Но если мы обучим НС на кошечках и собачках, а покажем ей только ухо - то, утрированно, можем получить ответ, что это пионер в пилотке. А, в нашем деле законченные образы есть только в прошлом, а в настоящем их нет... Поэтому так важен данный этап подготовки к обучению НС. А интеграция... - это уже чисто технический процесс. Python его значительно упрощает и переводит в плоскость практического применения в трейдинге. 

В машинном обучении развивается целое направление - автоматизация машинного обучения. Там да, собрал данные, передал программе и она сама определит способы и методы препроцессинга, подберет модель или модели, которые для этих данных позволяют получить наилучшие результаты, оптимизирует гиперпараметры и выдаст готовый результат для использования.
Опять таки это подходит для классификации законченных образов. Где качество обучения можно определять в процессе обучения....  Нам же надо все время возвращаться к тестированию, оптимизации в MT5 и т.д. И вот здесь интегрировать значительно сложнее, но как перспектива для дальнейшей работы - да...
В статье показана неверная последовательность этапов создания и использования нейросети - это главный недостаток по моему мнению. То, что не используется интеграция в полном объеме - печально, но не смертельно. А с названием статьи конечно нужно быть скромней. 
Какова верная последовательность???
grin4k
grin4k | 12 ноя 2020 в 23:16

После запуска двух Скриптов - PythonIndicators .mq5 , PythonPrices.mq5 создаются пустые .csv файлы - в чем может быть причина?

Спасибо

Andrey Dibrov
Andrey Dibrov | 13 ноя 2020 в 07:09
grin4k:

После запуска двух Скриптов - PythonIndicators .mq5 , PythonPrices.mq5 создаются пустые .csv файлы - в чем может быть причина?

Спасибо

А, истории хватает?

Alexander Kraus
Alexander Kraus | 3 янв 2021 в 11:27
Большое спасибо за эту статью, я сам долго собирал кусочки по кусочкам чтобы подобное зделать, но слаб в мкл 5. Пришлось бы Пару месяцев потерять на свою версию. 

Заголовок статьи ( часть 1 ) говорит о ( част2 ) , жду не дождусь !!
Оптимальный подход к разработке и анализу торговых систем Оптимальный подход к разработке и анализу торговых систем

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

Работа с таймсериями в библиотеке DoEasy (Часть 55): Класс-коллекция индикаторов Работа с таймсериями в библиотеке DoEasy (Часть 55): Класс-коллекция индикаторов

В статье продолжим развитие классов объектов-индикаторов и их коллекции. Создадим для каждого объекта-индикатора его описание и скорректируем класс-коллекцию для безошибочного хранения и получения объектов-индикаторов из списка-коллекции.

Примеры анализа графиков с использованием Секвенты Демарка и уровней Мюррея-Ганна Примеры анализа графиков с использованием Секвенты Демарка и уровней Мюррея-Ганна

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

Градиентный бустинг (CatBoost) в задачах построения торговых систем. Наивный подход Градиентный бустинг (CatBoost) в задачах построения торговых систем. Наивный подход

Обучение классификатора CatBoost на языке Python и экспорт модели в mql5 формат, а также разбор параметров модели и кастомный тестер стратегий. Для подготовки данных и обучения модели используется язык программирования Python и библиотека MetaTrader5.