Conectando redes neuronales de NeuroSolutions

ds2 | 4 abril, 2014


Introducción

Supongo que todos los traders que están familiarizados con las redes neuronales piensan en lo genial que sería usarlas en el análisis del mercado. Hay muchos programas que le permiten crear de forma sencilla sus propias redes con cualquier configuración, entrenarlas y probarlas visualmente. Puede exportar los datos necesarios desde el terminal de cliente a un programa de red neuronal y analizarlos en el mismo.

¿Pero qué sucede si queremos usar la red neuronal que hemos creado con el trading automático? ¿Es posible conectar un Expert Advisor a una red neuronal y operar en tiempo real?

Sí, se puede. Varios programas de redes neuronales disponen de las interfaces que requiere el programa. Uno de estos programas se llama NeuroSolutions. La última versión es la 6, sin embargo, no todo el mundo la tiene y la versión más popular por ahora es la 5. Es por ello que en este artículo se describe la interacción con la versión 5. Necesita la versión completa del programa; ya que incluye el asistente de soluciones personalizadas (Custom Solution Wizard) necesario para nuestro propósito.


Pensar en una estrategia

La estrategia para el ejemplo de nuestra prueba será sencilla. La llamaremos WeekPattern. Proporcionará un pronóstico del precio de cierre de una barra a su apertura en el período de tiempo D1 mediante una red neuronal. En función de la información obtenida, realizará una transacción de Compra o Venta y la mantendrá durante todo el día. La predicción del precio será la base de los valores OHLC de las 5 barras anteriores. Para mejorar la precisión del funcionamiento de la red neuronal, solo le enviaremos los cambios de precio relativos al precio de apertura de la barra actual (cero), en lugar de los precios en sí.


Preparación de los datos para el entrenamiento

Antes de comenzar con la creación de la red neuronal, vamos a escribir primero un script en MQL5, que exportará todas las cotizaciones desde el terminal de cliente en el formato requerido. Estos datos son necesarios para el entrenamiento de la red neuronal. Se exportarán los datos a un archivo de texto. Se separan los nombres de los campos mediante comas en la primera lista del archivo. Se usarán las siguientes líneas para los datos separados por coma. Cada línea es una combinación de entradas y salidas de la red neuronal. En nuestro caso, se moverá el historial del precio hacia atrás de una barra en cada línea y escribirá los valores OHLC de 6 barras en la línea (las 5 barras anteriores son las entradas y la barra actual es la salida).

El script WeekPattern-Export.mq5 debe iniciarse con el período de tiempo requerido con el símbolo indicado (en nuestro ejemplo, es D1 EURUSD). En la configuración hay que especificar el nombre del archivo y el número de líneas necesarias (260 líneas con D1 equivale a aproximadamente 1 año del historial). El código completo del script:

#property script_show_inputs
//+------------------------------------------------------------------+
input string    Export_FileName = "NeuroSolutions\\data.csv"; // File for exporting (in the folder "MQL5\Files")
input int       Export_Bars     = 260; // Number of lines to be exported
//+------------------------------------------------------------------+
void OnStart() 
  {
  
   // Create the file
   int file = FileOpen(Export_FileName, FILE_WRITE|FILE_CSV|FILE_ANSI, ',');
   
   if (file != INVALID_HANDLE)
     {
      // Write the heading of data
      
      string row="";
      for (int i=0; i<=5; i++)
        {
         if (StringLen(row)) row += ",";
         row += "Open"+i+",High"+i+",Low"+i+",Close"+i;
        }
      FileWrite(file, row);
      
      // Copy all required information from the history
      
      MqlRates rates[], rate;
      int count = Export_Bars + 5;
      if (CopyRates(Symbol(), Period(), 1, count, rates) < count)
        {
         Print("Error! Not enough history for exporting of data.");
         return;
        }
      ArraySetAsSeries(rates, true);
      
      // Write data      
      
      for (int bar=0; bar<Export_Bars; bar++)
        {
         row="";
         double zlevel=0;
         for (int i=0; i<=5; i++)
           {
            if (StringLen(row)) row += ",";
            rate = rates[bar+i];
            if (i==0) zlevel = rate.open; // level for counting of prices
            row += NormalizeDouble(rate.open -zlevel, Digits()) + ","
                 + NormalizeDouble(rate.high -zlevel, Digits()) + ","
                 + NormalizeDouble(rate.low  -zlevel, Digits()) + ","
                 + NormalizeDouble(rate.close-zlevel, Digits());
           }
         FileWrite(file, row);
        }

      FileClose(file);
      Print("Export of data finished successfully.");
     }
   else Print("Error! Failed to create the file for data export. ", GetLastError());
  }
//+------------------------------------------------------------------+

Después de exportar los datos, obtenemos el archivo data.csv; sus primeras líneas (por ejemplo) tienen el siguiente formato:

Open0,High0,Low0,Close0,Open1,High1,Low1,Close1,Open2,High2,Low2,Close2,Open3,High3,Low3,Close3,Open4,High4,Low4,Close4,Open5,High5,Low5,Close5
0,0.00463,-0.0041,0.00274,-0.00518,0.00182,-0.00721,-6e-005,0.00561,0.00749,-0.00413,-0.00402,0.02038,0.02242,0.00377,0.00565,0.03642,0.0379,0.01798,0.02028,0.0405,0.04873,0.03462,0.03647
0,0.007,-0.00203,0.00512,0.01079,0.01267,0.00105,0.00116,0.02556,0.0276,0.00895,0.01083,0.0416,0.04308,0.02316,0.02546,0.04568,0.05391,0.0398,0.04165,0.04504,0.05006,0.03562,0.0456
0,0.00188,-0.00974,-0.00963,0.01477,0.01681,-0.00184,4e-005,0.03081,0.03229,0.01237,0.01467,0.03489,0.04312,0.02901,0.03086,0.03425,0.03927,0.02483,0.03481,0.02883,0.04205,0.02845,0.03809

Este es el formato que puede entender NeuroSolutions. Ahora podemos comenzar a crear y entrenar la red neuronal.


La creación de la red neuronal

En NeuroSolutions puede crear rápidamente una red neuronal, incluso si es su primer contacto con el software y sabe muy poco acerca de las redes neuronales. Para ello, seleccione el asistente para principiantes NeuralExpert (Beginner) al inicio del programa:

En el cual debe especificar el tipo de problema que tiene que resolver la red neuronal:

A continuación, especifique el archivo con los datos de entrenamiento que hemos creado en el capítulo anterior:

Como entradas de la red, seleccione todos los campos del archivo, excepto los campos de la barra cero.

Dado que no tenemos campos de texto, no seleccione nada:

Indique el archivo con los datos de nuevo:

Seleccione solamente una salida de nuestra red:

El asistente propone crear la red más sencilla por defecto: Aceptamos:

El asistente ha finalizado su trabajo creando una red neuronal para nosotros (no es una red entrenada, solo es un estructura sencilla):

Ahora podemos trabajar con ella. Podemos entrenarla, probarla y usarla para analizar los datos.

Si hace clic en el botón Test, podrá ver cómo la red sin entrenamiento resolverá nuestro problema. Responda a las preguntas del asistente de pruebas:

Lleve a cabo la prueba en base a los datos del mismo archivo:

La prueba ha finalizado. En la ventana "Output vs. Desired Plot", puede ver el gráfico que muestra los valores obtenidos a partir de la red (el color rojo) de nuestro historial y los valores reales (el color azul). Puede apreciar que son bastante distintos.

Ahora, vamos a entrenar la red. Para ello, haga clic en el botón Start de la barra de herramientas debajo del menú. El entrenamiento finalizará al cabo de unos segundos y el gráfico cambiará:


Puede observar ahora en el gráfico que la red ofrece unos resultados parecidos a los valores reales. Por tanto, la puede usar para el trading. Guarde esta red con el nombre WeekPattern.


Exportar la red neuronal a un archivo DLL

Sin salir de NeuroSolutions, haga clic en el botón CSW que inicia Custom Solution Wizard. Tenemos que generar una DLL a partir de la red neuronal actual.

El asistente puede generar archivos DLL para distintos programas. Por lo que tengo entendido, para la compilación de la DLL, hace falta una de las siguientes versiones de Visual C++: 5.0/6.0/7.0 (.NET 2002)/7.1 (.NET 2003)/8.0 (.NET 2005). Por alguna razón, no usa la versión Express (lo he comprobado).

MetaTrade no está en la lista de las aplicaciones de destino. Por eso elegimos Visual C++.

La ruta para guardar el resultado:

Si todo va bien, el asistente lo indica:

Aparecerán muchos archivos en el directorio indicado en el asistente. Los que más necesitamos son: WeekPattern.dll, contiene nuestra red neuronal con la interfaz del programa hacia la misma; y el archivo WeekPattern.nsw que contiene la configuración del balance de la red neuronal después de su entrenamiento. Entre los otros archivos, puede encontrar un ejemplo de funcionamiento con esta red neuronal DLL. En este caso, es el proyecto Visual C++ 6.


Conectar la red neuronal DLL a MetaTrader

La red neuronal DLL creada en el capítulo anterior está destinada para su uso en los proyectos Visual C++. Funciona con los objetos de una estructura compleja que sería difícil o incluso imposible describir en MQL5. Es por eso que no vamos a conectar esta DLL a MetaTrader directamente. En su lugar vamos a crear un pequeño adaptador DLL. Este adaptador tendrá una función sencilla para trabajar con la red neuronal. Creará la red, le enviará los datos de entrada y devolverá los datos de salida.

Se puede llamar fácilmente a este adaptador desde MetaTrader 5. Y se conectará el adaptador a la red neuronal DLL creada en NeuroSolutions. Puesto que el adaptador se implementará en Visual C++, no tendrá ningún problema con los objetos de esta DLL.




No tiene que crear el adaptador DLL. Se adjunta el archivo ya hecho al artículo. El adaptador funciona con cualquier red neuronal DLL creada en NeuroSolutions. Puede saltarse el resto de este capítulo.

Pero si tiene experiencia en la programación C++ y le interesa saber cómo crear este adaptador, lea este capítulo hasta el final. Seguramente le interesaría mejorarlo, ya que se pueden exportar algunas funciones de la red neuronal DLL. Por ejemplo, la función de entrenamiento (para que un Expert Advisor se adapte a los cambios del mercado, vuelve a entrenar la red automáticamente). Puede obtener la lista completa de las funciones analizando el ejemplo generado mediante el Custom Solution Wizard, que se muestra en el capítulo anterior.

Solo necesitaremos algunos archivos de aquel ejemplo.

En Visual C++ (la misma versión utilizada con Custom Solution Wizard) cree un proyecto DLL vacío llamado NeuroSolutionsAdapter y copie los archivos NSNetwork.h, NSNetwork.cpp y StdAfx.h del ejemplo al proyecto. Además, cree un archivo vacío main.cpp:


Escriba el siguiente código en el archivo main.cpp:

#include "stdafx.h"
#include "NSNetwork.h"

extern "C" __declspec(dllexport) int __stdcall CalcNeuralNet(
                LPCWSTR dllPath_u, LPCWSTR weightsPath_u,
                double* inputs, double* outputs)
{       
    // Transform the lines from Unicode to normal ones
    CString dllPath     (dllPath_u);
    CString weightsPath (weightsPath_u);

    // Create neuronet
    NSRecallNetwork nn(dllPath);
    if (!nn.IsLoaded()) return (1);

    // Load balances
    if (nn.LoadWeights(weightsPath) != 0) return (2);
        
    // Pass input data and calculate the output
    if (nn.GetResponse(1, inputs, outputs) != 0) return (3);

    return 0;
}

Compile. ¡El adaptador DLL está listo!


El uso de redes neuronales en un Expert Advisor

Bien, hasta el momento hemos creado varios archivos. Permítame enumerar los archivos necesarios para el funcionamiento del Expert Advisor, y las carpetas dónde hay que ponerlos. Todos estos archivos están adjuntos al artículo

Archivo
Descripción
Ruta de almacenamiento (en la carpeta del terminal)
WeekPattern.dll
nuestra red neuronal DLL creada en NeuroSolutions
MQL5\Files\NeuroSolutions\
WeekPattern.nsw configuración del balance de nuestra red neuronal
MQL5\Files\NeuroSolutions\
NeuroSolutionsAdapter.dll
adaptador DLL genérico para cualquier red neuronal DLL
MQL5\Libraries\


A continuación, está el código completo del Expert Advisor WeekPattern.mq5. Para facilitar la búsqueda y las modificaciones posteriores, todo lo que está relacionado con la red neuronal se coloca en una clase independiente CNeuroSolutionsNeuralNet.

input double    Lots = 0.1;
//+------------------------------------------------------------------+
// Connect the DLL adapter, using which we are going to use the DLL neuronet created in NeuroSolutions
#import "NeuroSolutionsAdapter.dll"
int CalcNeuralNet(string dllPath, string weightsPath, double& inputs[], double& outputs[]);
#import 
//+------------------------------------------------------------------+
class CNeuroSolutionsNeuralNet
{
private:
   string dllPath;     // Path to a DLL neuronet created in NeuroSolutions
   string weightsPath; // Path to a file of the neuronet balances
public:
   double in[20]; // Neuronet inputs - OHLC of 5 bars
   double out[1]; // Neuronet outputs - Close of a current bar

   CNeuroSolutionsNeuralNet();
   bool Calc();
};
//+------------------------------------------------------------------+
void CNeuroSolutionsNeuralNet::CNeuroSolutionsNeuralNet()
{
   string terminal = TerminalInfoString(TERMINAL_PATH);
   dllPath     = terminal + "\\MQL5\\Files\\NeuroSolutions\\WeekPattern.dll";
   weightsPath = terminal + "\\MQL5\\Files\\NeuroSolutions\\WeekPattern.nsw";
}
//+------------------------------------------------------------------+
bool CNeuroSolutionsNeuralNet::Calc()
  {
   // Get current quotes for the neuronet
   MqlRates rates[], rate;
   CopyRates(Symbol(), Period(), 0, 6, rates);
   ArraySetAsSeries(rates, true);
      
   // Fill the array of input data of the neuronet
   double zlevel=0;   
   for (int bar=0; bar<=5; bar++)
     {
      rate = rates[bar];
      // 0 bar is not taken for input
      if (bar==0) zlevel=rate.open; // level of price calculation
      // 1-5 bars are inputed
      else
        {
         int i=(bar-1)*4; // input number
         in[i  ] = rate.open -zlevel;
         in[i+1] = rate.high -zlevel;
         in[i+2] = rate.low  -zlevel;
         in[i+3] = rate.close-zlevel;
        }
     }
 
   // Calculate the neuronet in the NeuroSolutions DLL (though the DLL adapter)
   int res = CalcNeuralNet(dllPath, weightsPath, in, out);
   switch (res)
     {
      case 1: Print("Error of creating neuronet from DLL \"", dllPath, "\""); return (false);
      case 2: Print("Error of loading balances to neuronet from the file \"", weightsPath, "\""); return (false);
      case 3: Print("Error of calculation of neuronet");  return (false);
     }
     
   // Output of the neuronet has appeared in the array out, you shouldn't do anything with it

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

CNeuroSolutionsNeuralNet NN;
double Prognoze;

//+------------------------------------------------------------------+
#include <Trade\Trade.mqh>
//+------------------------------------------------------------------+
void OnTick() 
  {
   // Get the price prediction from the neuronet
   if (NN.Calc()) Prognoze = NN.out[0];
   else           Prognoze = 0;

   // Perform necessary trade actions
   Trade();
  }
//+------------------------------------------------------------------+
void Trade() 
  {

   // Close an open position if it is opposite to the prediction

   if(PositionSelect(_Symbol)) 
     {
      long type=PositionGetInteger(POSITION_TYPE);
      bool close=false;
      if((type == POSITION_TYPE_BUY)  && (Prognoze <= 0)) close = true;
      if((type == POSITION_TYPE_SELL) && (Prognoze >= 0)) close = true;
      if(close) 
        {
         CTrade trade;
         trade.PositionClose(_Symbol);
        }
     }

   // If there is no positions, open one according to the prediction

   if((Prognoze!=0) && (!PositionSelect(_Symbol))) 
     {
      CTrade trade;
      if(Prognoze > 0) trade.Buy (Lots);
      if(Prognoze < 0) trade.Sell(Lots);
     }
  }
//+------------------------------------------------------------------+


Un buen método para comprobar si se ha conectado la red neuronal correctamente, es la ejecución del Expert Advisor en el probador de estrategias con el mismo período de tiempo utilizado para el entrenamiento de la red neuronal.

Bueno, como dicen los traders experimentados, la red neuronal es un "adaptador" para este período. Por tanto, está entrenada para identificar e informar acerca de una señal rentable para estos patrones de datos exactos, que dominan en este período concreto. El gráfico de rentabilidad de un Expert Advisor dibujado para este período debe ser ascendente.

Vamos a comprobarlo. En nuestro caso, sería el siguiente gráfico:


Esto significa que todo se ha conectado correctamente.

Y para las estadísticas, se adjuntan a continuación otros informes de la prueba del Expert Advisor:




Por si acaso, permítame dar algunas explicaciones a los desarrolladores principiantes de estrategias de trading y redes neuronales.

La rentabilidad de un Expert Advisor en un período, que ha sido utilizado para su optimización (entrenamiento de su red neuronal), no dice nada sobre la rentabilidad total del EA. En otras palabras, no garantiza su rentabilidad en otros períodos. Pueden existir otros patrones dominantes.

La creación de estrategias de trading que puedan mantener su rentabilidad más allá del período de entrenamiento es una tarea compleja y complicada. No puede esperar que NeuroSolutions o cualquier otra aplicación de redes neuronales le vaya a resolver este problema. Solo crea una red neuronal para sus datos.

Estos son los motivos por los cuales no he proporcionado los resultados de las pruebas posteriores del Expert Advisor obtenido. El objetivo de este artículo no es la creación de una estrategia de trading rentable. El propósito es enseñarle cómo conectar una red neuronal a un Expert Advisor.


Conclusión

Los traders disponen ahora de otra herramienta potente y fácil para el análisis del trading automático y para el trading. Su uso junto a un profundo conocimiento de las redes neuronales, así como las reglas de su entrenamiento le permitirá continuar su camino en la creación de Expert Advisors rentables.