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

Andrey Dibrov | 27 октября, 2020

Введение

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


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

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

Для подготовки данных для обучения сетей мы будем использовать два скрипта — 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.

  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 мы получим такие файлы - 

Папка \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);
  }
//+------------------------------------------------------------------+

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

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

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

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

Оптимизация

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

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

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

Оптимизация

Оптимизация

Оптимизация


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

Тест Тест


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

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

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

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

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

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

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

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

Заключение

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