Aplicación práctica de las redes neuronales en el trading. Python (Parte I)
Introducción
En el artículo anterior "Aplicación práctica de las redes neuronales en el trading. Pasamos a la práctica", analizamos el uso práctico de un módulo de redes neuronales implementado en redes neuronales Matlab. Sin embargo, omitimos la preparación de los datos de entrada y el trabajo relacionado con en el entrenamiento de la red neuronal. En este artículo, plantearemos estas preguntas usando ejemplos concretos y las implementaremos en redes neuronales de bibliotecas que funcionan con Python. No obstante, el principio de la implementación del sistema comercial será algo distinto. Esta opción se describió brevemente en el párrafo 5 del artículo básico "Aplicación práctica de las redes neuronales en el comercio". Para hacer esto, utilizaremos la biblioteca de aprendizaje automático TensorFlow desarrollada por Google. Para describir las redes neuronales, en cambio, utilizaremos la biblioteca de Keras.
1. Preparando los datos
Veamos a analizar algunos puntos de la preparación para entrenar las redes neuronales.
- En este desarrollo, para tomar una decisión, utilizaremos dos redes neuronales para abrir las posiciones en una dirección.
- Basándonos en el punto anterior, también dividiremos los datos de entrenamiento en dos direcciones.
- Al igual que el sistema anterior, nuestra primera red neuronal estará capacitada para construir indicadores semejantes a los indicadores técnicos estándar. Utilizamos esta variante en el anterior sistema porque usábamos indicadores escritos por nosotros mismos, y no queríamos sobrecargar el funcionamiento del asesor experto. En Python, esto se debe a que desde el terminal solo podemos obtener cotizaciones y, ya después de ello, debemos construir estos indicadores en un script de Python para preparar los datos de la red neuronal. Sin embargo, enseñando a la red neuronal a construir indicadores de este tipo, nos ahorramos la necesidad de repetirlos en el script.
- La segunda red neuronal construye directamente el indicador de señal que utilizamos para realizar la estrategia comercial.
- Entrenar la red neuronal según el gráfico de la pareja EURUSD
- Como resultado, para construir el sistema, necesitaremos preparar dos RN para transacciones de compra y dos para transacciones de venta. En total, tendremos en nuestro sistema cuatro redes neuronales.
Para preparar los datos que nos permitirán entrenar las redes, utilizaremos dos scripts: PythonPrices.mq5 y 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("Writing the file 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("Writing the file 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("Files written"); } //+------------------------------------------------------------------+
//+------------------------------------------------------------------+ //| 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; //------ Daily Low 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("Writing the files InputNet2OutNet1Min and 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); } } } } //------ Daily High 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("Writing the files InputNet2OutNet1Max and 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("Files written"); } //+------------------------------------------------------------------+
Crearemos una muestra partiendo del inicio de la jornada laboral hasta que se alcance el primer mínimo del día, y una segunda que abarcará hasta que se alcance el primer máximo del día. Para ello, usaremos en los scripts dos indicadores DibMin1-1.mq5 y 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); } //+------------------------------------------------------------------+
Cuando el precio alcanza los extremos diarios, los indicadores adoptan valores iguales a -1.
Después de trabajar en estos scripts en el gráfico EURUSDH1 en la carpeta \Common\Files, obtendremos seis archivos en formato CSV.
- EURUSDInputNet1Max y EURUSDInputNet1Min son los archivos con los datos de precios. En el nombre del archivo, podemos ver que, por ejemplo, el archivo EURUSDInputNet1Max es el archivo de los datos de entrada para la red neuronal Net1Max.
- EURUSDInputNet2OutNet1Max y EURUSDInputNet2OutNet1Min son los archivos con los valores de los indicadores. Estos valores serán las entradas para Net2 y las salidas para Net1. Nos gustaría señalar que aquí debemos experimentar: podemos entrenar Net2 con los indicadores técnicos estándar o con las respuestas de Net1.
- EURUSDOutNet2Max y EURUSDOutNet2Min son las salidas para Net2: la diferencia de precio entre el precio de apertura de la hora y la apertura del día (o el cierre del día y la apertura de la hora).
- Vamos a entrenar las redes neuronales sobre la aproximación del precio hacia sus extremos, interpretando no el precio en sí, sino los valores del indicador.
- Para nosotros, los objetivos de la RN son la diferencia entre los precios de apertura de la hora y la apertura del día (el cierre del día y la apertura de la hora). Aquí también podemos experimentar, definiendo otros objetivos para la RN, digamos, la diferencia entre otros precios.
- Con este enfoque, suavizamos la probabilidad de que surjan respuestas erróneas por parte de los módulos de redes neuronales en su conjunto, ya que entrenamos redes neuronales no específicamente para encontrar los precios máximos o mínimos del día, sino también sobre la probabilidad de aproximarse a ellos considerando la amplitud de los precios hasta el extremo diario. Si decidimos concentrarnos en la posterior amplitud del precio, podemos usar la diferencia de precio entre el cierre del día y la apertura de la hora. Probablemente, la primera opción sea preferible, ya que en este caso estamos entrenando la red neuronal según los objetivos alcanzados, y no sobre los eventos que están a punto de suceder. Lo cual resulta más lógico, como el lector comprenderá. Después de todo, valorar eventos pasados resulta más sencillo que hacer predicciones.
2. Entrenando redes neuronales de Python
Lo primero que debemos hacer es usar el apartado "Integración" de la guía de ayuda de MQL5. Después de instalar Python 3.8 y conectar el módulo de integración de MetaTrader5, conectamos de la misma forma las bibliotecas TensorFlow, Keras, Numpy y Pandas.
Para entrenar las redes neuronales, utilizaremos el script de 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')
También ubicaremos este script en la carpeta \Common\Files.
Echemos un vistazo al script.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
Bloque para conectar las bibliotecas, paquetes y módulos de 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)
Creamos un dataframe a partir de los archivos de datos.
mean = InputNet1.mean(axis=0) std = InputNet1.std(axis=0) InputNet1 -= mean InputNet1 /= stdA continuación, normalizamos los datos.
Net1Min = Sequential() Net1Min.add(Dense(22, activation='relu', input_shape=(InputNet1.shape[1],))) Net1Min.add(Dense(60))
Modelo de red secuencial, capa de entrada 22 neuronas, capa de salida 60 neuronas.
Net1Min = Sequential() Net1Min.add(Dense(22, activation='relu', input_shape=(InputNet1.shape[1],))) Net1Min.add(Dense(11)) Net1Min.add(Dense(60))Podemos experimentar y añadir una capa oculta.
Net1Max.compile(optimizer='adam', loss='mse', metrics=['mse']) print(Net1Max.summary())
Compilamos la red e imprimimos sus parámetros.
Net1Min.fit(InputNet1, InputNet2OutNet1, epochs=10, batch_size=10,verbose=2,validation_split=0.3) Net1Min.save('net1Min.h5')
Entrenamos la red neuronal con 10 épocas y un tamaño de la mini-muestra de 10. El 30 por ciento de los datos de entrenamiento se asigna para la validación. También resulta necesario experimentar con estos hiperparámetros de red. "Verbose" es el parámetro para visualizar las épocas de entrenamiento. Guardamos la red neuronal entrenada.
NetTest=pd.read_csv('EURUSDTest.csv', delimiter=';',header=None) Date=pd.read_csv('EURUSDDate.csv', delimiter=';',header=None)
Creamos el dataframe para la prueba.
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)
Cargamos las redes neuronales guardadas y obtenemos el resultado de ellas.
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=';')
Guardamos en archivos los datos obtenidos.
input('Press ENTER to exit')
Esperamos a que se cierre la ventana. Para procesar los scripts de forma normal, también necesitamos preparar los datos para obtener las respuestas de las redes neuronales que usaremos para formar el indicador, y luego investigar si resulta aconsejable usarlas en la construcción de una estrategia comercial.
Para ello, usaremos el experto 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()); } //+------------------------------------------------------------------+
Iniciamos el asesor en el simulador de estrategias en H1 según los precios de apertura. Tomemos el intervalo desde principios de 2011 hasta la actualidad. Con la ayuda de este asesor experto, simulamos los datos que, en el trabajo real, el script de Python formará a partir de los precios entrantes de MT5.
En la carpeta \Common, este asesor experto creará dos archivos, EURUSDTest y EURUSDDate.
Iniciamos el script de Python EURUSDPyTren.py. (Si no funciona, es posible que debamos reinstalar los paquetes adicionales que instalamos anteriormente y reiniciar la computadora). Si lo hemos hecho todo correctamente, el script se ejecutará clicando dos veces.
Como resultado, en la carpeta \Common\Files, obtendremos los siguientes archivos:
- net1Max.h5, net1Min.h5, net2Max.h5, net2Min.h5 son las redes neuronales entrenadas que se usarán en el script de trabajo al comerciar en tiempo real.
- IndicatorMax e IndicatorMin son las dos respuestas de la RN para las pruebas independientes.
- Indicador es la respuesta combinada.
Iniciamos el indicador 1_MT5 en la terminal comercial.
//+------------------------------------------------------------------+ //| 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); } //+------------------------------------------------------------------+
No hemos puesto especial intención al entrenar las redes neuronales, pero ciertas dependencias ya resultan visibles.
3. Optimización de los resultados obtenidos.
Para optimizar el indicador resultante, utilizaremos el asesor experto 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); } //+------------------------------------------------------------------+
Tenemos variables que podemos optimizar
- Н1, Н2 son las horas del día entre las cuales se realizará la compra.
- Н3, H4 son las horas del día entre las cuales se realizará la venta.
- Compra, Compra1: en esta variante, los niveles de la línea roja del indicador Buf_0[] suponen la respuesta de la RN entrenada con los datos hasta el mínimo del día.
- Vender, Vender1: en esta variante, los niveles de la línea azul del indicador Buf_1[] suponen la respuesta de la RN entrenada con los datos hasta el máximo del día.
- LossBuy, ProfitBuy, LossSell, ProfitSell son los niveles de limitación.
Vamos a establecer los parámetros de optimización como se muestra en la imagen, es decir, solo optimizaremos los niveles del indicador.
Niveles de indicador optimizados
Parámetros de optimización
Resultados de la optimización
Resultados de la prueba. Hasta la línea roja en el gráfico de prueba, tenemos el periodo de optimización, y después la prueba con los parámetros optimizados.
Usando como base los parámetros obtenidos, realizaremos la posterior optimización según el tiempo y las órdenes stop
Ponemos a prueba todos los parámetros.
Obviamente, podemos optimizar cada dirección del comercio por separado.
Conclusión
El siguiente vídeo ayudará al lector a entender rápidamente cómo prepararse para iniciar un script de Python.
Traducción del ruso hecha por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/ru/articles/8502
- Aplicaciones de trading gratuitas
- 8 000+ señales para copiar
- Noticias económicas para analizar los mercados financieros
Usted acepta la política del sitio web y las condiciones de uso