Aplicación práctica de las redes neuronales en el trading. Pasamos a la práctica

Andrey Dibrov | 29 septiembre, 2020

Introducción

En el artículo anterior, "Aplicación práctica de las redes neuronales en el trading", describimos los rasgos generales de la construcción de un sistema comercial basado en módulos de redes neuronales. En este artículo, proponemos al lector probar en la práctica qué supone un módulo de RN, y, usando este como base, construir un sistema comercial automático.

En el artículo, trabajaremos con la pareja de divisas EURUSD. No obstante, como programa, el propio módulo de RN es universal, y puede trabajar con diferentes herramientas, así como con combinaciones de estas. Es decir, como opción, podemos utilizar un módulo de RN en el que se integrarán redes neuronales entrenadas para diferentes parejas de divisas.

La tecnología de preparación de los datos históricos para el entrenamiento de las redes neuronales del módulo de RN excede el marco del presente artículo. Adjuntaremos al módulo de RN las redes neuronales ya entrenadas con los datos históricos temporalmente aproximados al momento de publicación del artículo.

Asimismo, destacaremos que el módulo de RN está totalmente preparado para realizar transacciones. Para que resulte más fácil familiarizarse con el complejo de elementos comprimidos para el presente artículo, hemos tenido que modernizarlo de forma que se puedan compatibilizar varias funciones del modelo de RN, y también trasladar a este mismo programa (módulo de RN) determinadas condiciones para la ejecución de las transacciones del experto comercial. No obstante, la transferencia de la condiciones se aplica a la parte del módulo de RN destinada al comercio real. En lo que respecta a la prueba de la red neuronal y la optimización de sus respuestas en el modo offline, claro está, hemos dejado estas funciones y condiciones para las transacciones a los expertos correspondientes. Aunque para el autor, resulta preferible un módulo de red neuronal en el que solo haya una función comercial. Eso sí, partimos de la idea de que, para operar, el módulo de RN deberá ser lo más simple posible, sin funciones adicionales. Por otra parte, deberemos sacar las propias funciones fuera del conjunto comercial. En esta variante, hablamos de las funciones de entrenamiento, simulación y optimización. Sin embargo, en lo que respecta a las condiciones para efectuar transacciones, resulta mejor tener dichas funciones en el módulo de RN, para recibir señales en forma binaria de este. Aunque todas las opciones para la implementación del módulo de RN en la práctica han confirmado su viabilidad.

Proponemos al lector exponer con más detalle la tecnología de preparación y formación del módulo de RN en la plataforma Matlab en el próximo artículo,

y también trasladar el sistema a Python en un futuro próximo. Al final del presente artículo, podrá ver un breve vídeo sobre este tema.

Los módulos de RN ofrecen resultados positivos durante un periodo de prueba más prolongado cuando son entrenados usando los datos históricos recibidos de los brókeres con los que se realiza el comercio online. Claro que podemos intentar unificar este punto, pero consideramos que no tiene sentido. 

El módulo de RN EURUSD_MT5

Más abajo, mostramos el aspecto del módulo de RN durante el inicio primario.

НСМ EURUSD_MT5

  1. El bloque "Online" ha sido pensado para iniciar y detener las RN en el trabajo real y en la simulación en el modo de visualización.
  2. Campos informativos de las condiciones de cruzamiento de la línea de respuesta de las RN por parte de la línea de señal al implicar al bloque "Online". 
  3. El bloque "Train" es un bloque demostrativo, diseñado para entrenar y perfeccionar la instrucción de las RN.
  4. Campos de edición de los valores de respuesta de las RN. Las de la izquierda muestran la respuesta de las RN; las de la derecha, la línea de señal. Las inferiores, la barra actual; las superiores, la anterior.
  5. El bloque "Offline" ha sido pensado para mostrar en el archivo la matriz de respuestas de las RN según la muestra de prueba.
  6. Ventana para introducir el valor de promediación de la línea de respuesta de las RN al implicar el bloque "Online". (Periodo de la línea de señal). Valor modificado.
  7. Los bloques "Net1,2,3" son los tres módulos de redes entrenados con diferentes intervalos de la serie temporal. Cada bloque incluye dos RN.
  8. Fecha de finalización del funcionamiento del módulo de RN al implicar el bloque "Online".
  9. Ventana para introducir el periodo de funcionamiento del módulo de RN en horas al implicar el bloque "Online". Valor modificado.
  10. Informe del tiempo transcurrido desde el inicio del funcionamiento del módulo de RN al implicar el bloque "Online".

Anexos

  1. MyAppInstaller_mcr.exe — archivo de instalación.
  2. EURUSD_MT5.exe — módulo de RN propiamente dicho.
  3. EURUSD_MT5var.exe — variante de módulo de RN.
  4. net1-net6.mat — redes neuronales de los tres módulos Net1-Net3. Vamos a utilizar como ejemplo su entrenamiento y simulación. 
  1. ExpertMatlabPodkach_MT5.mq5 y ExpertMatlab_MT5.mq5 son dos expertos imprescindibles para preparar los datos históricos para la simulación offline del módulo de RN.
  2. NWI.mq5 es el indicador para la representación visual de las respuestas del módulo de RN.
  3. Matlab_MT5.mq5 es un experto para simular y optimizar la respuesta del módulo de RN en el simulador de estrategias.
  4. ExpertMatlabReal_MT5.mq5 es un experto para trabajar online en cuentas reales o demo, y también para la simulación en el modo visual.
  5. EURUSDData.csv es un archivo con los datos de entrenamiento.

Instalación del programa



Antes de usar por primera vez las aplicaciones compiladas de Matlab, es necesario utilizar MyAppInstaller_mcr.exe. Con la ayuda de esta aplicación, instalaremos MATLAB Runtime y el módulo de red neuronal propiamente dicho.

Después de instalar el programa, colocaremos el acceso directo de EURUSD_MT5.exe en la carpeta ...\Common\Files del directorio de datos. Lo haremos así para que resulte más cómodo iniciar el sistema en su momento. Todos los expertos y el módulo de RN escriben los archivos en esta carpeta y, al darse el inicio, el módulo de RN propone buscar los archivos del directorio donde está ubicado el acceso directo. 

Archivo EURUSD_MT5

1. Acceso directo de EURUSD_MT5

Indicamos la carpeta de trabajo.

Escribimos la ruta

2. Escribimos la ruta


Uso práctico

A continuación, tenemos las cuatro variantes de uso del módulo de RN:

  1. Realización de transacciones en el modo online en cuentas demo o reales.
  2. Simulación del módulo de RN en el modo de visualización.
  3. Entrenamiento de redes neuronales.
  4. Obtención de las respuestas de las redes neuronales de los bloques para optimizar la estrategia comercial.

Aquí, usted podría decir que sería lógico analizar estas variantes en otro orden. Sin embargo, debemos destacar que, en su aspecto original, el módulo de RN fue pensado para ejecutar la primera variante de uso. Y el autor se inclina más por esta implementación. Las variantes segunda, tercera y cuarta han sido sacadas fuera del módulo de RN, dado que se pueden ejecutar en el periodo de ajuste general del sistema. En esta ejecución, hemos reunido todas estas etapas en un bloque único, para comprender mejor el proceso de preparación general del sistema para el funcionamiento real.

Echemos un vistazo más detallado a estas variantes.

1. En el modo online en cuentas demo o reales


Como podemos ver, el tiempo de inicio del sistema ocupa menos de cinco minutos.

Previamente, debemos configurar Excel. El ajuste consiste en anotar los datos de los scripts y los expertos en las celdas en formato numérico. De lo contrario, Matlab leerá los datos de forma incorrecta. Para ello, necesitaremos establecer un punto como separador de la parte entera y fraccionaria de las cifras. O bien con el "separador sistémico", o bien directamente.

Parámetros de Excel

3. Parámetros de Excel

Antes del primer inicio del módulo de RN, tenemos que crear el archivo de descarga de la historia con la ayuda del experto. En el simulador de estrategias, iniciamos el experto ExpertMatlabPodkach_MT5.ex5. 


    Gráfico

Iniciamos ExpertMatlabPodkach_MT5

4. Iniciamos ExpertMatlabPodkach_MT5.ex5

Como podemos ver, tenemos que seleccionar un tiempo de inicio tal que el periodo temporal hasta que comience el funcionamiento abarque tres días.

Obtenemos el archivo EURUSDTestPodkach.csv.


Archivo EURUSDPodkach_MT5

5. Archivo EURUSDTestPodkach.csv


Abrimos este archivo e introducimos cambios en el mismo, eliminando todas las líneas excepto las líneas con los datos sobre la hora de apertura de la última hora del día anterior al día de inicio del sistema.

Eliminamos las líneas

6. Eliminamos las líneas


Ahora, podemos iniciar el experto ExpertMatlabReal_MT5.ex5.

#include<Trade\Trade.mqh>
//--- objeto para realizar operaciones comerciales
CTrade  trade;

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

int BarMax;
int BarMin;
int handleInput;
int handleInputPodkach;
int handleBar;
int Con;
int Bar;

double DibMax;
double DibMin;

double in[32];

int Order01;
int Order1;

ulong TicketBuy1;
ulong TicketSell0;

bool send1;
bool send0;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---

   handleInputPodkach=FileOpen("EURUSDTestPodkach.csv",FILE_READ|FILE_CSV|FILE_ANSI|FILE_COMMON,";");
   if(handleInputPodkach==INVALID_HANDLE)
      Alert("Archivo EURUSDTestPodkach.csv ausente");

   in[0]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[1]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[2]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[3]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[4]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[5]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[6]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[7]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[8]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[9]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[10]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[11]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[12]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[13]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[14]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[15]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[16]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[17]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[18]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[19]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[20]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[21]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[22]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[23]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[24]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[25]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[26]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[27]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[28]=1/StringToDouble(FileReadString(handleInputPodkach))-1;
   in[29]=1/StringToDouble(FileReadString(handleInputPodkach))-1;

   FileClose(handleInputPodkach);

//--- establecemos el MagicNumber para identificar nuestras órdenes
   int MagicNumber=123456;
   trade.SetExpertMagicNumber(MagicNumber);
//--- establecemos el deslizamiento permitido en puntos al realizar compras/ventas
   int deviation=10;
   trade.SetDeviationInPoints(deviation);
//--- modo de rellenado de la orden; debemos utilizar el modo permitido por el servidor
   trade.SetTypeFilling(ORDER_FILLING_RETURN);
//--- qué función utilizar para el comercio: true - OrderSendAsync(), false - OrderSend()
   trade.SetAsyncMode(true);

//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   FileClose(handleInput);
   FileClose(handleBar);
  }

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

   if(stm.hour==1)
      DibMax=iHigh(NULL,PERIOD_H1,1);
   if(stm.hour>0)
     {
      if(iHigh(NULL,PERIOD_H1,1)>DibMax && iTime(NULL,PERIOD_H1,0)>1)
        {
         in[20]=iOpen(NULL,PERIOD_D1,0)-iLow(NULL,PERIOD_H1,1);
         in[21]=iHigh(NULL,PERIOD_H1,1)-iOpen(NULL,PERIOD_D1,0);
         in[22]=iHigh(NULL,PERIOD_D1,1)-iLow(NULL,PERIOD_D1,1);
         in[23]=iHigh(NULL,PERIOD_D1,1)-iOpen(NULL,PERIOD_H1,0);
         in[24]=iOpen(NULL,PERIOD_H1,0)-iLow(NULL,PERIOD_D1,1);
        }
     }
   if(iHigh(NULL,PERIOD_H1,1)>DibMax)
      DibMax=iHigh(NULL,PERIOD_H1,1);
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
   if(stm.hour==1)
      DibMin=iLow(NULL,PERIOD_H1,1);
   if(stm.hour>0)
     {
      if(iLow(NULL,PERIOD_H1,1)<DibMin && iTime(NULL,PERIOD_H1,0)>1)
        {
         in[25]=iOpen(NULL,PERIOD_D1,0)-iLow(NULL,PERIOD_H1,1);
         in[26]=iHigh(NULL,PERIOD_H1,1)-iOpen(NULL,PERIOD_D1,0);
         in[27]=iHigh(NULL,PERIOD_D1,1)-iLow(NULL,PERIOD_D1,1);
         in[28]=iHigh(NULL,PERIOD_D1,1)-iOpen(NULL,PERIOD_H1,0);
         in[29]=iOpen(NULL,PERIOD_H1,0)-iLow(NULL,PERIOD_D1,1);
        }
     }
   if(iLow(NULL,PERIOD_H1,1)<DibMin)
      DibMin=iLow(NULL,PERIOD_H1,1);

   in[30]=iHigh(NULL,PERIOD_D1,1)-iOpen(NULL,PERIOD_H1,0);
   in[31]=iOpen(NULL,PERIOD_H1,0)-iLow(NULL,PERIOD_D1,1);

   if(Bar<Bars(NULL,PERIOD_H1)&& stm.hour==0)
     {
      for(int i=19; i>=10; i--)
        {
         in[i-10]=in[i];
        }

      for(int i=29; i>=20; i--)
        {
         in[i-10]=in[i];
        }
     }


   handleInput=FileOpen("Input_mat.txt",FILE_TXT|FILE_WRITE|FILE_ANSI|FILE_SHARE_READ|FILE_COMMON,";");

   FileWrite(handleInput,

             1/(in[0]+1),1/(in[1]+1),1/(in[2]+1),1/(in[3]+1),1/(in[4]+1),1/(in[5]+1),1/(in[6]+1),1/(in[7]+1),1/(in[8]+1),1/(in[9]+1),1/(in[10]+1),1/(in[11]+1),1/(in[12]+1),1/(in[13]+1),1/(in[14]+1),1/(in[15]+1),
             1/(in[16]+1),1/(in[17]+1),1/(in[18]+1),1/(in[19]+1),1/(in[20]+1),1/(in[21]+1),1/(in[22]+1),1/(in[23]+1),1/(in[24]+1),1/(in[25]+1),1/(in[26]+1),1/(in[27]+1),1/(in[28]+1),1/(in[29]+1),1/(in[30]+1),1/(in[31]+1));

   FileClose(handleInput);

   handleBar=FileOpen("Bar.txt",FILE_TXT|FILE_WRITE|FILE_ANSI|FILE_SHARE_READ|FILE_COMMON,";");

   FileWrite(handleBar,stm.hour);

   FileClose(handleBar);

   Order01=FileOpen("Open1.txt",FILE_CSV|FILE_READ|FILE_ANSI|FILE_SHARE_READ|FILE_COMMON," ");

   Order1=StringToInteger(FileReadString(Order01));
   
   FileClose(Order01);

   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(Bar<Bars(NULL,PERIOD_H1))
      Con=0;

   Comment(Order1,"  ",Con);

   if(LossBuy==0)
      SL1=0;

   if(ProfitBuy==0)
      TP1=0;

   if(LossSell==0)
      SL0=0;

   if(ProfitSell==0)
      TP0=0;

   if(Order1==0 && Bar<Bars(NULL,PERIOD_H1) && Con==0)
      send0=true;

   if(Order1==1 && Bar<Bars(NULL,PERIOD_H1) && Con==0)
      send1=true;


//---------Buy0

   if(send1==false  &&  Bar==Bars(NULL,PERIOD_H1) && Order1==1 && Con>=1 && iLow(NULL,PERIOD_H1,1)<iLow(NULL,PERIOD_H1,2) && stm.hour>15 && stm.hour<20)
     {
      send1=trade.PositionOpen(_Symbol,ORDER_TYPE_BUY,1,PriceAsk,SL1,TP1);
      TicketBuy1 = trade.ResultDeal();
     }

   if(send1==true &&  Bar==Bars(NULL,PERIOD_H1) && Order1==0 && Con>=1 && iHigh(NULL,PERIOD_H1,1)>iHigh(NULL,PERIOD_H1,2))
     {
      trade.PositionClose(TicketBuy1);
      send1=false;
     }
//---------Sell0
   if(send0==false  &&  Bar==Bars(NULL,PERIOD_H1) && Order1==0 && Con>=1 && iHigh(NULL,PERIOD_H1,1)>iHigh(NULL,PERIOD_H1,2) && stm.hour>
        11 && stm.hour<14)
     {
      send0=trade.PositionOpen(_Symbol,ORDER_TYPE_SELL,1,PriceBid,SL0,TP0);
      TicketSell0 = trade.ResultDeal();
     }

   if(send0==true &&  Bar==Bars(NULL,PERIOD_H1) && Order1==1 && Con>=1 && iLow(NULL,PERIOD_H1,1)<iLow(NULL,PERIOD_H1,2))
     {
      trade.PositionClose(TicketSell0);
      send0=false;
     }
//-----------------------------------------------------------------------
   Bar=Bars(NULL,PERIOD_H1);
   Con++;
  }
//------------------------------------------------------------------------

Queremos destacar que, en lo que respecta a las limitaciones temporales en un experto diseñado específicamente para realizar transacciones, el autor prefiere escribirlas en el propio código, tras la optimización. Esto se hace así para minimizar el riesgo de cometer un error y modificar casualmente (o bien no modificacar en absoluto) dichas limitaciones temporales en las variables externas.

ExpertMatlabReal_MT5

7. Iniciamos ExpertMatlabReal_MT5.ex5

Por el contrario, en un experto diseñado para la optimización, las limitaciones se escriben ya como variables externas.

Matlab_MT5.ex5

7.1 Matlab_MT5.ex5

Si nos olvidamos de crear el archivo de descarga, recibiremos una advertencia diciendo que el experto ha comenzado a generar señales falsas.

Advertencia

8. Advertencia


En la carpeta ...\Common\Files, el asesor registrará dos archivos. En el archivo Input_mat.txt, se encuentran los datos de entrada para el módulo de RN.

Respuesta del experto

9. Respuesta del experto

Iniciamos el módulo de red neuronal EURUSD_MT5.exe. Esperamos a que aparezca la zona de trabajo.

Zona de trabajo

10. Zona de trabajo del módulo de RN


Los parámetros modificables de los bloques Net2 y Net3 en esta variante del programa no pueden ser modificados.

Pulsamos el botón "Start" y seleccionamos el archivo net1.m (o bien otro archivo de la red neuronal).

Pulsamos el botón "Start"

11. Pulsamos el botón "Start"

Si prestamos atención a la figura superior, veremos que el módulo de RN ha cambiado un poco durante la preparación del artículo. Su funcionalidad, no obstante, permanece sin cambios.

El modelo de red neuronal comenzará su funcionamiento.

Modelo de RN comerciando

12. Modelo de RN en estado de realización de transacciones


Durante el funcionamiento del módulo de RN, no podremos cambiar ningún parámetro modificable.

En la esquina superior izquierda del gráfico, podemos ver los números que el experto ha recibido del módulo de RN: 1.0, -1.0 y 0.0. Esto significa que el experto ha recibido de Net1 una señal de compra (venta). De Net2, quedarnos fuera del mercado. Y de Net3, una señal de venta (compra). Dado que esta versión tiene fines informativos, no vamos a recibir señales modificadas de los bloques Net1 y Net2.

En este ejemplo, nuestro sistema usa la línea de señal de un suavizado de cinco horas de la respuesta del módulo de RN, y para evitar recibir una señal original falsa, el módulo deberá ser iniciado cinco horas antes de la hora de las transacciones, partiendo de las condiciones de apertura de posiciones. Y así, dependiendo del cambio del parámetro de suavizado.

Debemos indicar de inmediato que los momentos como la utilización del archivo de descarga, "el lanzamiento de información a través del disco" o la espera de la descarga de datos, se relacionan con la necesidad de controlar la información que llega en ambas direcciones. Los datos en la ventana del módulo de RN y en los archivos Open1,2,3 deberán ser idénticos.

Control de la información

13. Control de la información

En la figura, mostramos una variante de módulo de red neuronal que transmite a este experto solo la respuesta de net1, net2 y net3, mientras que las condiciones de apertura de posiciones están escritas en el experto. Debemos destacar que el autor prefiere esta variante. En nuestro caso, el módulo de RN transmite una señal ya preparada, mientras que el experto comercia partiendo solo de las limitaciones temporales en la realización de transacciones.

Este control resulta especialmente útil al depurar el sistema. También es necesario realizar el control visual durante las simulaciones y el trading.

Variante con el módulo de RN

14. Variante con el módulo de RN

En la figura de arriba, se muestra otra variante más de módulo de RN. En esta variante, resulta mejor integrar las redes neuronales directamente en un archivo ejecutable. Tras pulsar el botón verde, solo necesitamos seleccionar el archivo Input_mat.txt. Recomendamos utilizar este modelo a la hora de trabajar. En esta ejecución solo hemos dejado el bloque de realización de transacciones, excluyendo los bloques de entrenamiento y simulación. Queremos subrayar que la aparente complejidad del sistema en la etapa de preparación se hace muy sencilla en el periodo de trading. El principal análisis del mercado se lleva a cabo en el módulo de RN al instante (gracias a las redes neuronales), mientras que el robot comercial, si no usa otras condiciones de optimización, solo tendrá que interpretar dos números. 

 if(send1==false && Order1==1)
     {
      send1=trade.Buy(1);
      TicketBuy1 = trade.ResultDeal();
     }

 if(send1==true && Order1==0)
     {
      trade.PositionClose(TicketBuy1);
      send1=false;
     }

Como resultado, queremos detenernos en una cierta diferencia del inicio del experto ExpertMatlabReal_MT4.ex4 para trabajar a través del terminal MetaTrader 4. Esta se relaciona con las peculiaridades de los simuladores de estrategias, en concreto, con la forma en que definen los puntos finales de los tests. En MetaTrader 5, el final de la prueba es la barra final del día anterior, mientras que en MetaTrader 4 es la barra actual. Por eso, en el experto para MetaTrader 4, hemos introducido la variable externa "Hours".

Variable externa "Hours"

14.1 Variable externa "Hours"

Con la ayuda del experto ExpertMatlabPodkach_MT4.ex4, formamos el archivo de descarga con una línea en la barra actual, por eso, al realizar la primera inicialización, ponemos en la variable "Hours" la hora de la barra actual. Después de inicializar el experto, entramos en sus propiedades y retornamos la variable 0. Esto es necesario para que los posteriores desplazamientos de los datos se realicen a las 00:00 horas.

Hours-0

14.2 Hours -0

2. Simulación del modelo de RN en el modo de visualización


Con la ayuda de esta prueba, terminaremos la preparación, determinando finalmente que el modelo de red neuronal nos dé el resultado que hemos alcanzado, preparando asimismo los datos para el entrenamiento de la red neuronal, su entrenamiento propiamente dicho y la obtención de la matriz de respuestas, de forma que visualicemos estas y las optimicemos posteriormente. Para ello, repetiremos las acciones del primer punto, es decir, iniciaremos módulo de RN como para el trading, mientras que en el iniciamos simulador de estrategias el experto ExpertMatlabReal_MT5.ex5 con uso de visualización. En MetaTrader 5, activamos el modelado "OHLC en M1". En MetaTrader 4, activaremos los "Puntos de Control". Estos modelos se deben utilizar para obtener un resultado fiable en las simulaciones, dado que, en nuestro caso, al utilizar los modelos de RN, las transacciones se realizarán en el siguiente tick después de la apertura de la barra. Y si utilizamos el modelo "Solo precios de apertura", durante la simulación, la apertura de posiciones se retrasará una barra. En este modo, resulta cómodo analizar el retraso de la respuesta con la ayuda del módulo EURUSD_MT5var.exe. En el trabajo real, esto, por supuesto, queda descartado. Queremos destacar que este sistema muestra unos resultados prácticamente idénticos en todos los tipos de simulación. Y esto, una vez más, confirma su viabilidad.

Visualización

Visualización

15. Modo visual


3. Entrenamiento de redes neuronales


En la ejecución presentada, este modo del módulo de red neuronal se usa como demostración de la etapa de entrenamiento y preparación de las redes neuronales para el trabajo real. Solo lo llamamos demostrativo porque estas redes neuronales no podrán ser reentrenadas por el lector, ya que el módulo utiliza redes neuronales ya entrenadas. Pero no hay necesidad de introducir este submódulo en el programa de trabajo, ya que el entrenamiento lo realizamos en el modo offline, y resulta más cómodo y fiable de realizar directamente en el módulo MATLAB.

 Así, por ejemplo, para entrenar dos redes neuronales para el submódulo Net1, necesitaremos tener en el directorio ...\Common\Files las propias redes neuronales net1-2 y el archivo EURUSDData.csv con los datos de entrenamiento.

Data

16. Archivo con los datos

Los datos de entrenamiento son reales, y son propiamente aquellos que se utilizan para preparar el sistema comercial con la ayuda del bloque "Online". Aquí nos gustaría destacar de nuevo las ventajas del uso de redes neuronales para valorar la situación de mercado. En el recuadro EURUSDData.csv, tenemos 90 columnas, que suponen el conjunto de valores consecutivos de los datos de entrada de la red neuronal. Dicho de forma más simple: las entradas. De forma más simple, podemos imaginar que cada columna es un indicador aparte calculado previamente por el experto, y extraído después como valores para entrenar la red neuronal. Sí, pero esto lo hacemos en el modo offline al preparar el sistema comercial, y ahora, imagine que tenemos que analizar esta considerable masa de información directamente en el experto durante las transacciones...

Para comprender mejor el orden de las acciones, hemos cambiado los nombres de los botones.

Nombres modificados de los botones

17. Nombres nuevos de los botones


Es decir, pulsamos el botón "Train net1" y, tras abrir el archivo net1.mat, entrenamos las redes neuronales net1 y net2 para el bloque Net1, y así sucesivamente: net3,4 para Net2 y net5,6 para Net3.

Train net1

18. Train net1


Debemos subrayar de nuevo que resultará más cómodo ubicar el acceso directo en la carpeta donde se encuentran los archivos de trabajo, modificando en sus propiedades la ruta a la "carpeta de trabajo". A continuación, el módulo de RN entrenará la red neuronal.

4. Obtención de las respuestas de las redes neuronales de los bloques para optimizar la estrategia comercial


Hemos añadido al módulo de red neuronal la posibilidad de simular redes neuronales en el modo offline. O más concretamente: la posibilidad de obtener la respuesta de las redes neuronales según los datos históricos para construir el indicador de señal del sistema y optimizarlo posteriormente. Como ejemplo, vamos a obtener las respuestas históricas de Net1.

Como hemos mencionado antes, en la carpeta ...\AppData\Roaming\MetaQuotes\Terminal\Common\Files, preparamos el archivo EURUSDTestPodkach_MT5.csv. Para ello, iniciamos en el simulador de estrategias el experto ExpertMatlabPodkach_MT5. Claro está, solo desde la fecha que antecede a la fecha de inicio de la simulación (preste atención a que el volumen necesario de la historia haya sido descargado).

Por ejemplo:

Podkach

19. Iniciamos ExpertMatlabPodkach_MT5.ex5


Y eliminamos en el archivo obtenido todas las líneas menos una.

EURUSDTestPodkach

20. Dejamos una línea


Para generar el archivo con los datos del periodo de prueba, iniciaremos en el simulador de estrategias el experto ExpertMatlab_MT5.ex5.

ExpertMatlab

21. Iniciamos ExpertMatlab_MT5.ex5

Fíjese en cómo se selecciona la fecha de inicio del periodo.


EURUSDTest, EURUSDDate

22. Obtenemos EURUSDTest.csv y EURUSDDate.csv


ExpertMatlab_MT5.ex5 genera dos archivos de prueba EURUSDDate.csv y EURUSDTest.csv. Iniciamos el módulo de red neuronal, pulsamos el botón "Test net1" y seleccionamos net1.mat.

Test net1

23. Pulsamos el botón "Test net1"

Necesitaremos esperar algún tiempo hasta que se genere el archivo con las respuestas Indicator1.csv.

Indicator1

24. Obtenemos el archivo de respuestas Indicator1.csv


Guardamos Indicator1 como Indicator. Además, si "Indicator1.csv" ha sido guardado por el bloque de red neuronal en el "Modo de compatibilidad", lo deberemos guardar en el formato "csv" a través de la pestaña "Guardar como". 

Indicator

25. Guardamos Indicator1.csv como Indicator.csv


Vamos a ver qué suponen las respuestas del módulo de RN en la representación visual en el gráfico EURUSD H1. Para ello, utilizaremos el indicador NWI.ex5.

NWI

26. Iniciamos el indicador NWI.ex5

Por defecto, el periodo tiene un valor de 5. Aclaramos de inmediato que, en estos momentos, este periodo de la línea de señal es el que ofrece mayor rendimiento para EURUSD H1, según nuestros experimentos. Pero el lector podrá experimentar por su cuenta.

NWI

27. Representación de NWI


Con la ayuda de Matlab_MT5.ex5, podemos poner a prueba y optimizar posteriormente las respuestas obtenidas.

#include<Trade\Trade.mqh>

CTrade  trade;

input int Periodo=5;
input int H1;
input int H2;
input int H3;
input int H4;

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

ulong TicketBuy1;
ulong TicketSell0;

datetime Count;

double Per;
double Buf_0[];
double Buf_1[];

bool send1;
bool send0;

int h=4;
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));
      h=Periodo-1;
      if(k>=h)
        {
         while(h>=0)
           {
            Buf_1[k]=Buf_1[k]+Buf_0[k-h];
            h--;
           }
         Buf_1[k]=Buf_1[k]/Periodo;
        }
      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-1]<Buf_1[K-1] && Buf_0[K]>Buf_1[K] && 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);
      TicketBuy1 = trade.ResultDeal();
     }

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

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

   if(send0==false && K>0 && Buf_0[K-1]>Buf_1[K-1] && Buf_0[K]<Buf_1[K] && 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);
      TicketSell0 = trade.ResultDeal();
     }

   if(send0==true && K>0 && Buf_0[K-1]<Buf_1[K-1] && Buf_0[K]>Buf_1[K] && 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);
  }
//+------------------------------------------------------------------+

Matlab_MT5

Matlab_MT5

28. Iniciamos Matlab_MT5.ex5

Balance

29. Balance

Recomendamos al lector no realizar pruebas en tiempo real. Después del backtest, el test forward comienza desde la fecha siguiente, mientras que el archivo se carga desde la inicial, es decir, desde la que se ha realizado el backtest. Y, claro está, obtendremos resultados incorrectos.

Vamos a realizar la optimización sobre la marcha. La prueba anterior la realizamos sin niveles de limitación y según el principio de preparación del sistema descrito en el libro. Para realizar la optimización, también hemos introducido los niveles.

Optim

Optim

Optim

30. Realizamos la optimización

Hasta la línea roja, 2011-2013, tenemos la optimización. Después de ella, 2013-2016, tenemos la simulación. Obviamente, no vamos a comerciar en un periodo tan largo después de la optimización, ya que debemos reentrenar la red neuronal periódicamente. La práctica nos indica que en un mes. En el gráfico, el periodo entre la línea roja y la azul es de 4 meses.

Vamos a simular este periodo por separado.

Test

Test

Test patrón Test patrón

Test patrón

31. Test patrón

Debemos tener en cuenta que no hemos llevado a cabo ni ajustado estas pruebas anteriormente: todo se ha realizado a la par con la escritura del artículo. Claro que podemos utilizar otras variantes, y también tenemos que preparar las redes neuronales de cobertura. Pero queremos insistir de nuevo en cuánto nos ayudan las redes neuronales a preparar el sistema y comerciar.

Podemos decir que las transacciones emuladas durante la presente prueba tenían unas condiciones ideales. Por eso, tomaremos el resultado de esta prueba como patrón.

5. Solución de errores

Trabajando en este punto, hemos decidido regresar al inicio y aclarar por qué ha salido tan voluminoso. El motivo es que "Solución de errores" se ha realizado, por así decirlo, en tiempo real, mientras se escribía el presente artículo. Al igual por cierto, que el anterior. Para MetaTrader 4, ya hemos solucionado todo esto, pero para MetaTrader 5, hemos tenido que trabajar en tiempo real. Para el autor en particular, ha resultado bastante útil... Queremos recordar de nuevo al lector que la preparación del comercio se debe realizar de forma sistemática y escrupulosa.

Podemos y debemos regresar al punto 2 para simular el resultado obtenido (que hemos llamado patrón) al emular las transacciones con la ayuda del modo de visualización.

Obtendremos el resultado siguiente.

Informe

32. Prueba fallida

Aunque el resultado es positivo, se diferencia significativamente del anterior. Y esto significa que tenemos un error en algún lugar del código y debemos encontrarlo. Y en este caso, nos ayudará el hecho de que podamos monitorear todas las etapas de transmisión de la información.

Vamos a comparar las respuestas en los campos de representación de los valores(4) del submódulo Net1 y las respuestas del módulo de RN obtenidas con la ayuda del experto ExpertMtatlab_MT5.ex5. Naturalmente, en la misma barra temporal.

Comparando las respuestas del módulo de RN

33. Comparando las respuestas del módulo de RN

Como podemos ver, las respuestas del submódulo Net1 y las respuestas del módulo de RN no se corresponden. Partiendo de ello, sacamos la conclusión de que, como hemos utilizado el mismo bloque de redes neuronales, la información que llega a sus entradas al realizar estas dos pruebas es distinta. 

Vamos a comprobar si la información en los archivos EURUSDTest.csv y Input_mat.txt es idéntica, seleccionando alguna barra durante el funcionamiento del módulo de RN.

Input_mat.txt

34. Comparando si la información es idéntica


Teníamos razón: la información realmente se diferencia entre sí. Y esto significa que debemos comprobar el código programático de los expertos ExpertMtatlab_MT5.ex5 y ExpertMatlabReal_MT5.ex5. 

ExpertMtatlab_MT5.ex5
if(stm.hour==0)
     {
      for(int i=19; i>=10; i--)
        {
         in[i-10]=in[i];
        }

      for(int i=29; i>=20; i--)
        {
         in[i-10]=in[i];
        }
     }
ExpertMatlabReal_MT5.ex5
if(Bar<Bars(NULL,PERIOD_H1) && stm.hour==0)
     {
      for(int i=19; i>=10; i--)
        {
         in[i-10]=in[i];
        }

      for(int i=29; i>=20; i--)
        {
         in[i-10]=in[i];
        }
     }

Como resultado de nuestras acciones, hemos encontrando un error en el código del experto ExpertMatlabReal_MT5.ex5. No teníamos la condición principal de desplazamiento de los datos en 00 horas. Por eso, al darse el funcionamiento real, nuestro módulo de RN recibía una información del terminal que no se correspondía con la que debían recibir las redes. Como consecuencia de ello, estas daban una "respuesta falsa". Hemos puesto comillas porque, en realidad, la red neuronal en sí da una respuesta normal, pero para nosotros será falsa, ya que no le hemos suministrado la información que deberíamos, partiendo de nuestra lógica.

Vamos a comparar de nuevo las respuestas en los campos de representación de los valores(4) del submódulo Net1 y las respuestas del módulo de RN obtenidas con la ayuda del experto ExpertMtatlab_MT5.ex5. 

Comparando las respuestas del módulo de RN

35. Comparando las respuestas del módulo de RN

Podemos llegar a la conclusión de que ahora la información que llega al módulo de RN es correcta.

Corregiendo este error y realizando un nuevo test en el modo de visualización.


Test

36. La prueba se diferencia del patrón

Vemos que, aunque el resultado es ya más aproximado al resultado de la simulación según la matriz de respuestas, sigue diferenciándose. Nuestro módulo de red neuronal, además, ha dejado de funcionar por propia iniciativa.

Como resultado de la comprobación, hemos encontrado un error en las condiciones de cierre de la posición de venta directamente en el experto ExpertMatlabReal_MT5.ex5. Realizando una nueva simulación en el modo de visualización de OHLC en M1.

Sin esperar al tick

Sin esperar al tick Sin esperar al tick

Sin esperar al tick

37. Prueba sin esperar al tick

El resultado sigue sin corresponderse, por así decirlo, con el patrón.

Test patrón

38. Patrón

Tras analizar esta prueba, podemos decir que hemos obtenido el resultado de la emulación del comercio en condiciones desfavorables. Esto se muestra en el aumento del número de señales falsas, y como resultado, de transacciones falsas. Surgen situaciones en las que en la barra anterior hay una señal de apertura de posición, y en la apertura de una nueva barra, el módulo de RN nos da la señal de, o bien realizar la transacción opuesta, o bien quedarse fuera del mercado. No obstante, como estamos realizando las pruebas en el modo acelerado, la información del módulo de RN puede llegar tarde, y el asesor realizará la transacción de acuerdo con la señal anterior. Pero, en este caso, la prueba resulta útil, dado que nos ofrece la oportunidad de ver cómo se comportará el sistema en condiciones desfavorables de nerviosismo del mercado.

Vamos a ver qué resultado obtendremos si escribimos limitaciones a la apertura de posiciones en el asesor en la situación descrita en el párrafo anterior.

 if(Order1==0 && Bar<Bars(NULL,PERIOD_H1) && Con==0)
      send0=true;
   
 if(Order1==1 && Bar<Bars(NULL,PERIOD_H1) && Con==0)
      send1=true;

//---------Buy

Realizaremos la simulación con todos los ticks y con la máxima velocidad de visualización. Podemos ver el proceso en el vídeo...

Prueba con condiciones

Prueba con condiciones Prueba con condiciones

Prueba con condiciones

39. Nos hemos acercado a la prueba patrón


Como podemos ver, el resultado se acerca al patrón. Aunque, en opinión del autor, la prueba anterior se encontraría próxima al patrón si hubiéramos reducido la velocidad de simulación. El lector podrá comprobar este punto por sí mismo.


Veamos ahora por qué se ha detenido el propio módulo de RN. Podríamos dejar esta cuestión sin respuesta, pero queremos destacar que el hecho de que este bug fuera detectado en el modo de simulación tiene un carácter positivo. Porque podríamos encontrarnos con este problema durante el comercio. El problema es que si las redes neuronales en el módulo de RN no están entrenadas, o bien si iniciamos el módulo antes de iniciar el asesor experto, y no hemos generado el archivo Input_mat.txt, al pulsar el botón "Start", el módulo de RN no nos ofrecerá respuestas. Y, en nuestro caso, la aparición de la ventana de advertencia ha sido programada con la salida forzosa del temporizador interno. Ya hemos eliminado este error lógico, pero no la advertencia. Sin embargo, si la ventana aparece durante el funcionamiento, no pasada nada. Solo tenemos que pulsar "OK" para que esta desaparezca. En este caso, el programa continuará funcionando sin interrupciones.

Ventana de error

40. Ventana de error

También tenemos otro problema al que debemos prestar atención. En MetaTrader 5, al registrar los datos con la ayuda del simulador de estrategias, el número de barras mostradas es superior al representado en el gráfico. Esto conlleva que el indicador resulte, digamos, "más largo". No obstante, esto no influye en la calidad de la simulación, ya que, al realizar una prueba, la barra sobrante se tiene en cuenta, pero no se representa en el gráfico. Esto lo podemos comprobar con la ayuda de una pasada paso a paso.

Indicador МТ5

41. Indicador NWI en МТ5

Indicador МТ5

42. Observamos el desplazamiento temporal

Para MetaTrader 4, este problema no existe.

Indicador МТ4

43. Indicador 1_MT4 en MetaTrader 4

Indicador МТ4

44. No hay desplazamiento

En figura de abajo, se muestra por qué sucede esto.

23:59

45. Encontramos el motivo del desplazamiento

Conclusión

Querríamos incidir de nuevo en el siguiente aspecto: ¿por qué utilizamos redes neuronales?

  1. Las redes neuronales nos permiten procesar grandes volúmenes de información fuera del mercado.
  2. Debido a que procesamos la información offline, esto nos ofrece la posibilidad de adelantarnos al mercado, en lugar de correr tras él. O, por lo menos, nos permite ir a su paso.
  3. Y, como resultado, podemos considerar de forma operativa los cambios en la situación del mercado no solo en el periodo de comercio, sino también en el estadio de preparación para las transacciones. Es decir, podremos evitar grandes pérdidas durante los cambios de tendencia, o bien cuando los mercados se vean influidos por diversos factores.
  4. En lo que respecta a la red neuronal específica presentada en el artículo y al método de entrenamiento de la misma, existe una ventaja indudable en esta simbiosis, a saber, la posibilidad de realizar la optimización en función de las respuestas obtenidas en el intervalo temporal en el que se ha realizado el entrenamiento. Mientras que algunas redes neuronales de otras arquitecturas ofrecen excelentes resultados durante el periodo de entrenamiento, y estos difieren significativamente en el segmento de prueba, aquí los resultados son aproximadamente los mismos. Esto nos da la posibilidad de entrenar intensamente la red hasta la fecha, además de tener en cuenta todos los factores del mercado disponibles en la historia. No hemos hablado de este punto en el artículo, pero el lector podrá investigarlo por sí mismo.

Inicialmente, la intención del autor era integrar en el módulo de RN solo las redes neuronales para el bloque Net1 entrenadas hasta el momento en que se publicó el artículo, sin embargo, al final, decidió integrar para Net2 las redes neuronales entrenadas hasta el 31.12.2019, y para Net3, hasta el 31.12.2010. Será interesante ponerlas a prueba en las condiciones de mercado actuales. Para todos los demás tipos de trabajo, en el módulo de RN solo se utilizarán las redes neuronales para Net1.

Después de descargar los archivos

El autor ofrece sus disculpas por crear un vídeo tan "lento": el proceso se filmó prácticamente en una "única toma".


Python