Практическое применение нейросетей в трейдинге. Python (Часть I)
Введение
В предыдущей статье "Практическое применение нейросетей в трейдинге. Переходим к практике" мы рассмотрели практическое использование нейросетевого модуля, реализованного на нейронных сетях 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: ценовая разница между ценой открытием часа и открытия дня (либо закрытия дня и и открытием часа).
- Нейронные сети мы обучаем на приближении цены к ее экстремумам, интерпретируя не саму цену, а индикаторные значения.
- Целями НС для нас является разница между ценами открытием часа и открытия дня (закрытия дня и открытия часа). Здесь также можно экспериментировать, ставя перед НС другие цели — допустим, разницу между другими ценами.
- При таком подходе мы сглаживаем вероятности ошибочных откликов в целом нейросетевых модулей, так как обучаем НС не конкретно на поиск максимальной либо минимальной цен дня, но и на вероятность приближения к ним, учитывая амплитуду цен до дневного экстремума. Если же мы решим ориентироваться на амплитуду цен после, то можно использовать разницу цен между закрытием дня и открытием часа. Думаю, что первый вариант предпочтительнее, так как в этом случае мы обучаем НС на достигнутых целях, а не на событиях, которые должны только произойти. Что, согласитесь, логичнее. Ведь оценивать прошедшие события легче, чем давать прогнозы.
2. Обучение нейронных сетей Python
Первое, что нам надо сделать — это воспользоваться справочником MQL5 разделом "Интеграция". После установки Python 3.8 и подключения модуля интеграции MetaTrader5 таким же образом подключим библиотеки TensorFlow, Keras, Numpy и Pandas.
Для обучения нейросетей будем использовать скрипт 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 — совмещенный отклик.
В торговом терминале запустим индикатор 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.
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
После запуска двух Скриптов - PythonIndicators .mq5 , PythonPrices.mq5 создаются пустые .csv файлы - в чем может быть причина?
Спасибо
А, истории хватает?
Статья полезная, спасибо. Вот только не могу понять, для чего обучаются последовательно две сети? Какая проблема таким образом решается. Если у кого есть время, не поленитесь, напишите пару предложений, проливающих свет на этот вопрос. Спасибо.
Для того, что бы не перегружать советник - первая нейросеть обучается на значениях индикаторов и при работе воспроизводит их не рассчитывая по формулам. Таким образом мы можем использовать сотни индикаторов...
Андрей здравствуйте,
1) попробовал сделать все по шагам, дошел до шага когда питон скрипт отработал и создал файлы, потом запускаю индикатор 1_MT5 а они ничего не отображает.
А файлы Indicator, IndicatorMin, IndicatorMax содержат только
03.01.2011 0:00
03.01.2011 1:00
03.01.2011 2:00
03.01.2011 0:00
03.01.2011 1:00
03.01.2011 2:00
так и надо? что я не так делаю?
2) что примерно нужно поменять если я просто хочу в нейронку передать бары и стандартные индикаторы то есть без логики " выборки от начала рабочего дня до достижения первым минимума дня, вторую до достижения первым максимума дня"