English Русский 中文 Deutsch 日本語 Português 한국어 Français Italiano Türkçe
Usar Indicadores de MetaTrader 5 con la Estructura de Aprendizaje Automático ENCOG para Predicción de Series Cronológicas

Usar Indicadores de MetaTrader 5 con la Estructura de Aprendizaje Automático ENCOG para Predicción de Series Cronológicas

MetaTrader 5Ejemplos | 25 marzo 2014, 13:46
2 965 0
investeo
investeo

Introducción

Este artículo presentará MetaTrader 5 a ENCOG - red neuronal avanzada y estructura de aprendizaje automático desarrollada por Heaton Research. Ya existen métodos previamente descritos que permiten a MetaTrader usar técnicas de aprendizaje automático: FANN, NeuroSolutions, Matlab y NeuroShell. Espero que ENCOG sea una solución complementaria, puesto que se trata de un código robusto y bien diseñado.

¿Por qué elegí ENCOG? Por varias razones.

  1. ENCOG se usa en otros dos paquetes de software de trading comercial. Uno está basado en C#, y el segundo en JAVA. Esto significa que ya se ha comprobado su efectividad para predecir datos de series cronológicas financieras. 
  2. ENCOG es un software gratuito y de código abierto. Si desea ver qué hay dentro de una red neuronal, puede observar el código fuente. Esto es lo que yo hice realmente para entender partes del problema de prediccón de series cronológicas. C# es un lenguaje de programación claro y fácil de entender.
  3. ENCOG está muy bien documentado. Mr Heaton, fundador de Heaton Research, nos facilita un curso online gratuito en Redes Neuronales, Lenguaje Automático y uso de ENCOG para predecir datos futuros. Yo estudié varias de sus lecciones antes de escribir este artículo. Me fueron de gran ayuda para entender las Redes Neuronales Artificiales. Además, hay e-books sobre programación de ENCOG en JAVA y C# en la página web de Heaton Research. La documentación entera sobre ENCOG se puede encontrar online.
  4. ENCOG no es un proyecto muerto. En el momento en el que escribo este artículo, ENCOG 2.6 se encuentra en pleno desarrollo. El RoadMap ENCOG 3.0 se publicó recientemente.
  5. ENCOG es robusto. Está bien diseñado, puede usar múltiples núcleos CPU y tiene capacidad para multihilo, que acelera los cálculos de redes neuronales. Partes del código ya comienzan a exportarse a cálculos activados en OpenCL - GPU.
  6. Los elementos que ECNOG soporta actualmente: 

Tipos de Aprendizaje Automático

Arquitecturas de Red Neuronal

Técnicas de Formación Funciones de Activación Técnicas de Aleatoriedad
  • Margen de Aleatoriedad
  • Números Gaussianos Aleatorios
  • Fan-In
  • Nguyen-Widrow

Elementos planeados:

Como puede observar, la lista de elementos es bastante larga.

Este artículo introductorio se centra en la arquitectura de Redes Neuronales de feed-forward con formación de Propagación Resistente (RPROP). También cubre los elementos básicos de preparación de datos: timeboxing y normalización de predicciones de series cronológicas temporales.

El conocimiento que me permitió escribir este artículo se basa en tutoriales a los que puede acceder en la página web de Heaton Research y artículos muy recientes sobre predicción de series cronológicas financieras en NinjaTrader. Por favor, tenga en cuenta que ENCOG está basado en JAVA y C#. Y no habría podido escribir este artículo sin mi trabajo anterior: Exposing C# code to MQL5 using unmanaged exports (Exponer código C# a MQL5 usando exportaciones no gestionadas). Esta solución me permitió usar DLLs de C# como un puente entre un indicador de Metatrader 5 y un vaticinador de series cronológicas ENCOG.


1. Usar Valores de Indicadores Técnicos como Entradas para una Red Neuronal

La Red Neuronal Artificial es un algoritmo creado por la mano del hombre que trata de emular la red neuronal del cerebro humano.

Hay varios tipos de algoritmos neuronales disponibles, y existe una gran variedad de arquitecturas de red neuronal. El campo de investigación es tan amplio que hay libros enteros dedicados a cada uno de los tipos de red neuronal. Puesto que estos detalles van más allá del alcance de este artículo, solo puedo recomendar echar un vistazo a los tutoriales de Heaton Research o leer un libro sobre el tema. Aquí me centraré en entradas y salidas de la red neuronal de feed-forward y trataré de describir un ejemplo práctico de predicción de series cronológicas financieras.

Para comenzar a pronosticar series cronológicas financieras, debemos pensar en lo que tenemos que facilitar a la red neuronal, y lo que podemos esperar a cambio. En el pensamiento más abstracto de caja negra obtenemos beneficios o pérdidas tomando posiciones largas o cortas en el contrato de una seguridad especificada y completando la transacción tras pasar un tiempo.

Observando precios en el pasado de una seguridad y valores de los indicadores técnicos, intentamos predecir el sentimiento o dirección futura de los precios para comprar o vender un contrato y asegurarnos de que nuestra decisión no se toma al azar. La situación tiene un aspecto más o menos como el que se observa abajo:

Figura 1. Pronosticar series cronológicas financieras usando indicadores técnicos

Figura 1. Pronosticar series cronológicas financieras usando indicadores técnicos 

Trataremos de conseguir lo mismo con inteligencia artificial. La red neuronal intentará reconocer valores de indicador y decidir si hay una posibilidad de que el precio suba o baje. ¿Cómo conseguimos algo así? Puesto que pronosticaremos series cronológicas financieras usando la arquitectura de red neuronal de feed-forward, creo que debemos presentar su arquitectura debidamente.

La red neuronal de feed-forward consiste en neuronas agrupadas en capas. Debe haber un mínimo de 2 capas: una capa de entrada que contiene neuronas de entrada, y una capa de salida que contiene neuronas de salida. También puede haber capas ocultas entre las capas de entrada y de salida. La capa de entrada se puede considerar simplemente un array de valores dobles, y la capa de salida puede consistir en una o más neuronas que también forman un array de valores dobles. Observe la figura de abajo:

 Figura 2. Capas de red neuronal de feed-forward

Figura 2. Capas de red neuronal de feed-forward 

Las conexiones entre neuronas no se dibujaron en orden para simplificar el dibujo. Cada neurona de la capa de entrada está conectada a una neurona en la capa oculta. Cada neurona de la capa oculta está conectada a una neurona en la capa de salida.

Cada conexión tiene su peso, que es también un valor doble y función de activación con un umbral responsable de la activación de una neurona y de la transmisión de información a la siguiente neurona. Esta es la razón por la que se llama red de feed-forward: información basada en salidas de neuronas activadas se pasa de una capa de neuronas a otra para alimentarla. Puede encontrar vídeos introductorios sobre redes neuronales de feed-forward en los siguientes enlaces:

Después de aprender sobre arquitectura de red neuronal y sus mecanismos, es posible que todavía se sienta confuso.

Los principales problemas son:

  1. ¿Qué datos deberíamos introducir en una red neuronal?
  2. ¿Cómo deberíamos alimentarla?
  3. ¿Cómo preparamos datos de entrada para una red neuronal? 
  4. ¿Cómo elegir una arquitectura de red neuronal? ¿Cuántas neuronas de entrada, ocultas y de salida necesitamos?
  5. ¿Cómo formamos la red?
  6. ¿Qué debemos esperar de la salida?

 

2. Qué Datos Necesitamos para Alimentar la Red Neuronal

Puesto que estamos tratando predicciones financieras basadas en salidas de indicador, debemos alimentar la red con valores de salida de indicadores. Para este artículo, yo elegí Stochastic %K, Stochastic Slow %D, y Williams %R como entradas.

Figura 3. Indicadores técnicos usados para hacer predicciones

Figura 3. Indicadores técnicos usados para hacer predicciones

Para extraer valores de los indicadores, podemos usar las funciones de MQL5 iStochastic y iWPR:

double StochKArr[], StochDArr[], WilliamsRArr[];

ArraySetAsSeries(StochKArr, true);   
ArraySetAsSeries(StochDArr, true);   
ArraySetAsSeries(WilliamsRArr, true);

int hStochastic = iStochastic(Symbol(), Period(), 8, 5, 5, MODE_EMA, STO_LOWHIGH);
int hWilliamsR = iWPR(Symbol(), Period(), 21);
   
CopyBuffer(hStochastic, 0, 0, bufSize, StochKArr);
CopyBuffer(hStochastic, 1, 0, bufSize, StochDArr);
CopyBuffer(hWilliamsR, 0, 0, bufSize, WilliamsRArr);

Tras ejecutar este código, los tres arrays StochKArr, StochDArr y WilliamsRArr se deben llenar con valores de salida de indicadores. Dependiendo del tamaño de la muestra de formación, esto puede llevar a unos cuantos miles de valores. Por favor, tenga en cuenta que estos dos indicadores se eligieron solo por motivos educativos.

Le animamos a que experimente con cualquier indicador que le parezca adecuado para hacer predicciones. Quizás desee alimentar la red con precios de oro y petróleo para predecir los índices de bolsa, o quizá prefiera usar pares forex correlativos para predecir otro par de divisas. 

 

3. Datos de Entrada de Timeboxing

Tras recopilar datos de entrada de varios indicadores, debemos poner los datos en "timebox" antes de pasarlos a la red neuronal. Timeboxing es una técnica que permite presentar datos de entrada para la red como láminas de datos móviles. Imagínese una caja móvil de datos de entrada que se mueve hacia delante en el eje de tiempo. Básicamente se necesitan dos pasos en este procedimiento:

1. Recopilar datos de entrada de cada buffer del indicador. Debemos copiar el número de elementos INPUT_WINDOW desde la posición inicial hacia el futuro. La ventana de entrada de datos es el número de barras usadas para la predicción. 

 Figura 4. Recopilar datos de la ventana de entrada de datos del buffer del indicador

Figura 4. Recopilar datos de la ventana de entrada de datos del buffer del indicador 

Como puede ver en el ejemplo de arriba, INPUT_WINDOW es igual a 4 barras, y copiamos los elementos en el array I1. I1[0] es el primer elemento, I1[3] es el último. Del mismo modo, los datos se copiaron de otros indicadores a arrays de tamaño INPUT_WINDOW. Esta figura es válida para arrays de series cronológicas con flag AS_SERIES configurada como true. 

2. Combinar arrays INPUT_WINDOW en un array que se pasa a la capa de entrada de la red neuronal. 

Figura 5. Arrays en timeboxe de la ventana de entrada de datos 

Figura 5. Arrays en timebox de la ventana de entrada de datos

Puesto que hay 3 indicadores, al principio tomamos el primer valor de cada indicador, después el segundo valor de cada indicador, y continuamos así hasta que la ventana de entrada de datos se haya llenado, como en la figura de arriba. Este array combinado desde las salidas de indicadores se puede dar como alimento a la capa de entrada de nuestra red neuronal. Cuando llega una nueva barra, los datos se laminan por un elemento y se repite todo el procedimiento. Si está interesado en obtener más detalles sobre la preparación de datos para hacer predicciones, puede ver este vídeo sobre el tema.

 

4. Normalizar Datos de Entrada

Para hacer la red neuronal más efectiva, debemos normalizar los datos. Esto es necesario para el cálculo correcto de funciones de activación. La normalización es un proceso matemático que convierte datos en un intervalo de 0..1 o -1..1. Los datos normalizados se pueden desnormalizar, o en otras palabras, devolver a su intervalo original.

La desnormalización se necesita para descodificar la salida de la red neuronal y darle un formato legible para las personas. Afortunadamente, ENCOG se encarga de la normalización y desnormalización, y por tanto no es necesario implementarlas. Si tiene curiosidad por saber cómo funciona, puede analizar el siguiente código:

/**
         * Normalize the specified value.
         * @param value The value to normalize.
         * @return The normalized value.
         */
        public static double normalize(final int value) {
                return ((value - INPUT_LOW) 
                                / (INPUT_HIGH - INPUT_LOW))
                                * (OUTPUT_HIGH - OUTPUT_LOW) + OUTPUT_LOW;
        }
        
        /**
         * De-normalize the specified value.
         * @param value The value to denormalize.
         * @return The denormalized value.
         */
        public static double deNormalize(final double data) {
                double result = ((INPUT_LOW - INPUT_HIGH) * data - OUTPUT_HIGH
                                * INPUT_LOW + INPUT_HIGH * OUTPUT_LOW)
                                / (OUTPUT_LOW - OUTPUT_HIGH);
                return result;
        }

y puede leer un artículo sobre normalización para más información. 

 

5. Elegir una arquitectura de red y número de neuronas

Para un principiante en el tema, elegir la arquitectura de red correcta es difícil. En este artículo estoy limitando la arquitectura de red neuronal de feed-forward a tres capas: una capa de entrada, una oculta y una de salida. Usted es libre para experimentar con un mayor número de capas.

Para una capa de entrada y de salida deberemos contar con precisión el número de neuronas necesario. Para una capa oculta, intentaremos minimizar los errores de la red neuronal usando un algoritmo de selección avanzado. Le animamos a que use otros métodos; puede que haya algunos algoritmos genéticos para calcular el número de neuronas.

Otro método usado por ENCOG se llama algoritmo de selección inversa, que básicamente consiste en evaluar las conexiones entre las capas y eliminar neuronas ocultas con conexiones de peso cero. Quizás esté interesado en probarlo, también.

5.1. Capa de neuronas de entrada

A causa del timeboxing, el número de neuronas en la capa de entrada debería ser igual al número de indicadores por el número de barras usadas para predecir la siguiente barra. Si usamos 3 indicadores como entradas y el tamaño de la ventana de entrada de datos es igual a 6 barras, la capa de entrada constará de 18 neuronas. La capa de entrada se alimenta de datos preparados por la timebox.

5.2. Capa de neuronas oculta

El número de neuronas ocultas debe calcularse en base al rendimiento de la red neuronal formada. No hay una ecuación matemática directa para saber el número de neuronas ocultas. Antes de escribir este artículo hice varios intentos de prueba y error, y encontré un algoritmo en la página web de Heaton Research que ayuda a entender el algoritmo de selección avanzado:

Figura 6. Algoritmo de selección avanzado para calcular el número de neuronas ocultas  

Figura 6. Algoritmo de selección avanzado para calcular el número de neuronas ocultas 

5.3. Capa de neuronas de salida

Para nuestro objetivo, el número de neuronas de salida es el número de barras que tratamos de predecir. Por favor, recuerde que cuanto más grande sea el número de neuronas ocultas y de salida, más tardará en formarse la red. En este artículo intento predecir una barra en el futuro, por tanto la capa de salida constará de una neurona.

 

6. Exportar Datos de Formación de MetaTrader 5 a ENCOG

Encog acepta archvos CSV para la formación de una red neuronal.

He mirado el formato de archivo exportado de otro software de trading a ENCOG y script de MQL5 implementado que prepare el mismo formato de archivo para su formación. Presentaré primero la exportacion de un indicador, y continuaré después con múltiples indicadores. 

La primera línea de datos es un encabezamiento separado por comas:

DATE,TIME,CLOSE,Indicator_Name1,Indicator_Name2,Indicator_Name3

Las primeras tres columnas contienen la fecha, hora y valores de cierre. La siguiente columna contiene los nombres de indicador. Las siguientes filas del archivo de formación contienen datos separados por comas; los valores de indicador se deberían escribir en formato científico:  

20110103,0000,0.93377000,-7.8970208860e-002

Por favor, observe el script ya hecho para un indicador que se muestra abajo.

//+------------------------------------------------------------------+
//|                                                ExportToEncog.mq5 |
//|                                      Copyright 2011, Investeo.pl |
//|                                                http:/Investeo.pl |
//+------------------------------------------------------------------+
#property copyright "Copyright 2011, Investeo.pl"
#property link      "http:/Investeo.pl"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+

// Export Indicator values for NN training by ENCOG
extern string IndExportFileName = "mt5export.csv";
extern int  trainSize = 400;
extern int  maPeriod = 210;

MqlRates srcArr[];
double expBullsArr[];

void OnStart()
  {
//---
   ArraySetAsSeries(srcArr, true);   
   ArraySetAsSeries(expBullsArr, true);      
         
   int copied = CopyRates(Symbol(), Period(), 0, trainSize, srcArr);
   
   if (copied!=trainSize) { Print("Not enough data for " + Symbol()); return; }
   
   int hBullsPower = iBullsPower(Symbol(), Period(), maPeriod);
   
   CopyBuffer(hBullsPower, 0, 0, trainSize, expBullsArr);
   
   int hFile = FileOpen(IndExportFileName, FILE_CSV | FILE_ANSI | FILE_WRITE | FILE_REWRITE, ",", CP_ACP);
   
   FileWriteString(hFile, "DATE,TIME,CLOSE,BullsPower\n");
   
   Print("Exporting indicator data to " + IndExportFileName);
   
   for (int i=trainSize-1; i>=0; i--)
      {
         string candleDate = TimeToString(srcArr[i].time, TIME_DATE);
         StringReplace(candleDate,".","");
         string candleTime = TimeToString(srcArr[i].time, TIME_MINUTES);
         StringReplace(candleTime,":","");
         FileWrite(hFile, candleDate, candleTime, DoubleToString(srcArr[i].close), DoubleToString(expBullsArr[i], -10));
      }
      
   FileClose(hFile);   
     
   Print("Indicator data exported."); 
  }
//+------------------------------------------------------------------+

 El archivo resultante que se puede usar para formación debería tener el siguiente aspecto: 

DATE,TIME,CLOSE,BullsPower
20110103,0000,0.93377000,-7.8970208860e-002
20110104,0000,0.94780000,-6.4962292188e-002
20110105,0000,0.96571000,-4.7640374727e-002
20110106,0000,0.96527000,-4.4878854587e-002
20110107,0000,0.96697000,-4.6178012364e-002
20110110,0000,0.96772000,-4.2078647318e-002
20110111,0000,0.97359000,-3.6029181466e-002
20110112,0000,0.96645000,-3.8335729509e-002
20110113,0000,0.96416000,-3.7054869514e-002
20110114,0000,0.96320000,-4.4259373120e-002
20110117,0000,0.96503000,-4.4835729773e-002
20110118,0000,0.96340000,-4.6420936126e-002
20110119,0000,0.95585000,-4.6868984125e-002
20110120,0000,0.96723000,-4.2709941621e-002
20110121,0000,0.95810000,-4.1918330800e-002
20110124,0000,0.94873000,-4.7722659418e-002
20110125,0000,0.94230000,-5.7111591557e-002
20110126,0000,0.94282000,-6.2231529077e-002
20110127,0000,0.94603000,-5.9997865295e-002
20110128,0000,0.94165000,-6.0378312069e-002
20110131,0000,0.94414000,-6.2038328069e-002
20110201,0000,0.93531000,-6.0710334438e-002
20110202,0000,0.94034000,-6.1446445012e-002
20110203,0000,0.94586000,-5.2580791504e-002
20110204,0000,0.95496000,-4.5246755566e-002
20110207,0000,0.95730000,-4.4439392954e-002

Volviendo al ejemplo original del artículo con los indicadores Stochastic y Williams' R, debemos exportar tres columnas separadas por comas. Cada columna debe contener valores de indicador separados, por tanto deberemos expandir el archivo y añadir buffers adicionales:

//+------------------------------------------------------------------+
//|                                                ExportToEncog.mq5 |
//|                                      Copyright 2011, Investeo.pl |
//|                                                http:/Investeo.pl |
//+------------------------------------------------------------------+
#property copyright "Copyright 2011, Investeo.pl"
#property link      "http:/Investeo.pl"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+

// Export Indicator values for NN training by ENCOG
extern string IndExportFileName = "mt5export.csv";
extern int  trainSize = 2000;

MqlRates srcArr[];
double StochKArr[], StochDArr[], WilliamsRArr[];

void OnStart()
  {
//---
   ArraySetAsSeries(srcArr, true);   
   ArraySetAsSeries(StochKArr, true);   
   ArraySetAsSeries(StochDArr, true);   
   ArraySetAsSeries(WilliamsRArr, true);
         
   int copied = CopyRates(Symbol(), Period(), 0, trainSize, srcArr);
   
   if (copied!=trainSize) { Print("Not enough data for " + Symbol()); return; }
   
   int hStochastic = iStochastic(Symbol(), Period(), 8, 5, 5, MODE_EMA, STO_LOWHIGH);
   int hWilliamsR = iWPR(Symbol(), Period(), 21);
   
   
   CopyBuffer(hStochastic, 0, 0, trainSize, StochKArr);
   CopyBuffer(hStochastic, 1, 0, trainSize, StochDArr);
   CopyBuffer(hWilliamsR, 0, 0, trainSize, WilliamsRArr);
    
   int hFile = FileOpen(IndExportFileName, FILE_CSV | FILE_ANSI | FILE_WRITE | FILE_REWRITE, ",", CP_ACP);
   
   FileWriteString(hFile, "DATE,TIME,CLOSE,StochK,StochD,WilliamsR\n");
   
   Print("Exporting indicator data to " + IndExportFileName);
   
   for (int i=trainSize-1; i>=0; i--)
      {
         string candleDate = TimeToString(srcArr[i].time, TIME_DATE);
         StringReplace(candleDate,".","");
         string candleTime = TimeToString(srcArr[i].time, TIME_MINUTES);
         StringReplace(candleTime,":","");
         FileWrite(hFile, candleDate, candleTime, DoubleToString(srcArr[i].close), 
                                                 DoubleToString(StochKArr[i], -10),
                                                 DoubleToString(StochDArr[i], -10),
                                                 DoubleToString(WilliamsRArr[i], -10)
                                                 );
      }
      
   FileClose(hFile);   
     
   Print("Indicator data exported."); 
  }
//+------------------------------------------------------------------+

El archivo resultante tendrá todos los valores de indicador:

DATE,TIME,CLOSE,StochK,StochD,WilliamsR
20030707,0000,1.37370000,7.1743119266e+001,7.2390220187e+001,-6.2189054726e-001
20030708,0000,1.36870000,7.5140977444e+001,7.3307139273e+001,-1.2500000000e+001
20030709,0000,1.35990000,7.3831775701e+001,7.3482018082e+001,-2.2780373832e+001
20030710,0000,1.36100000,7.1421933086e+001,7.2795323083e+001,-2.1495327103e+001
20030711,0000,1.37600000,7.5398313027e+001,7.3662986398e+001,-3.9719626168e+000
20030714,0000,1.37370000,7.0955352856e+001,7.2760441884e+001,-9.6153846154e+000
20030715,0000,1.38560000,7.4975891996e+001,7.3498925255e+001,-2.3890784983e+000
20030716,0000,1.37530000,7.5354107649e+001,7.4117319386e+001,-2.2322435175e+001
20030717,0000,1.36960000,7.1775345074e+001,7.3336661282e+001,-3.0429594272e+001
20030718,0000,1.36280000,5.8474576271e+001,6.8382632945e+001,-3.9778325123e+001
20030721,0000,1.35400000,4.3498596819e+001,6.0087954237e+001,-5.4946524064e+001
20030722,0000,1.36130000,2.9036761284e+001,4.9737556586e+001,-4.5187165775e+001
20030723,0000,1.34640000,1.6979405034e+001,3.8818172735e+001,-6.5989159892e+001
20030724,0000,1.34680000,1.0634573304e+001,2.9423639592e+001,-7.1555555556e+001
20030725,0000,1.34400000,9.0909090909e+000,2.2646062758e+001,-8.7500000000e+001
20030728,0000,1.34680000,1.2264922322e+001,1.9185682613e+001,-8.2705479452e+001
20030729,0000,1.35250000,1.4960629921e+001,1.7777331716e+001,-7.2945205479e+001
20030730,0000,1.36390000,2.7553336360e+001,2.1035999930e+001,-5.3979238754e+001
20030731,0000,1.36990000,4.3307839388e+001,2.8459946416e+001,-4.3598615917e+001
20030801,0000,1.36460000,5.6996412096e+001,3.7972101643e+001,-5.2768166090e+001
20030804,0000,1.34780000,5.7070193286e+001,4.4338132191e+001,-8.1833910035e+001
20030805,0000,1.34770000,5.3512705531e+001,4.7396323304e+001,-8.2006920415e+001
20030806,0000,1.35350000,4.4481132075e+001,4.6424592894e+001,-7.1972318339e+001
20030807,0000,1.35020000,3.3740028156e+001,4.2196404648e+001,-7.7681660900e+001
20030808,0000,1.35970000,3.0395426394e+001,3.8262745230e+001,-6.1245674740e+001
20030811,0000,1.35780000,3.4155781326e+001,3.6893757262e+001,-6.4532871972e+001
20030812,0000,1.36880000,4.3488943489e+001,3.9092152671e+001,-4.5501730104e+001
20030813,0000,1.36690000,5.1160443996e+001,4.3114916446e+001,-4.8788927336e+001
20030814,0000,1.36980000,6.2467599793e+001,4.9565810895e+001,-2.5629290618e+001
20030815,0000,1.37150000,6.9668246445e+001,5.6266622745e+001,-2.1739130435e+001
20030818,0000,1.38910000,7.9908906883e+001,6.4147384124e+001,-9.2819614711e+000

Puede modificar el segundo ejemplo para producir fácilmente un script que se adapte a sus necesidades.


7. Formación de Red Neuronal

La formación de la red ya se ha preparado en C# por Heaton Research. ENCOG 2.6 implementa el espacio de nombres Encog.App.Quant, que es una base para la predicción de series cronológicas financieras. El script de formación es muy flexible, y se puede ajustar a cualquier número de indicadores de entrada de datos. Solo debe cambiar la localización del directorio de MetaTrader 5 en la constante DIRECTORY.

La arquitectura de red y parámetros de formación se pueden personalizar fácilmente cambiando las siguientes variables:

        /// <summary>
        /// The size of the input window.  This is the number of bars used to predict the next bar.
        /// </summary>
        public const int INPUT_WINDOW = 6;        

        /// <summary>
        /// The number of bars forward we are trying to predict.  This is usually just 1 bar.  The future indicator used in step 1 may
        /// well look more forward into the future. 
        /// </summary>
        public const int PREDICT_WINDOW = 1;

        /// <summary>
        /// The number of bars forward to look for the best result.
        /// </summary>
        public const int RESULT_WINDOW = 5;

        /// <summary>
        /// The number of neurons in the first hidden layer.
        /// </summary>
        public const int HIDDEN1_NEURONS = 12;

        /// <summary>
        /// The target error to train to.
        /// </summary>
        public const double TARGET_ERROR = 0.01;

El código se explica por sí mismo, por tanto lo mejor es leerlo con detenimiento:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Encog.App.Quant.Normalize;
using Encog.Util.CSV;
using Encog.App.Quant.Indicators;
using Encog.App.Quant.Indicators.Predictive;
using Encog.App.Quant.Temporal;
using Encog.Neural.NeuralData;
using Encog.Neural.Data.Basic;
using Encog.Util.Simple;
using Encog.Neural.Networks;
using Encog.Neural.Networks.Layers;
using Encog.Engine.Network.Activation;
using Encog.Persist;

namespace NetworkTrainer
{
    public class Program
    {
        /// <summary>
        /// The directory that all of the files will be stored in.
        /// </summary>
        public const String DIRECTORY = "d:\\mt5\\MQL5\\Files\\";

        /// <summary>
        /// The input file that starts the whole process.  This file should be downloaded from NinjaTrader using the EncogStreamWriter object.
        /// </summary>
        public const String STEP1_FILENAME = DIRECTORY + "mt5export.csv";

        /// <summary>
        /// We apply a predictive future indicator and generate a second file, with the additional predictive field added.
        /// </summary>
        public const String STEP2_FILENAME = DIRECTORY + "step2_future.csv";

        /// <summary>
        /// Next the entire file is normalized and stored into this file.
        /// </summary>
        public const String STEP3_FILENAME = DIRECTORY + "step3_norm.csv";

        /// <summary>
        /// The file is time-boxed to create training data.
        /// </summary>
        public const String STEP4_FILENAME = DIRECTORY + "step4_train.csv";

        /// <summary>
        /// Finally, the trained neural network is written to this file.
        /// </summary>
        public const String STEP5_FILENAME = DIRECTORY + "step5_network.eg";
       
        /// <summary>
        /// The size of the input window.  This is the number of bars used to predict the next bar.
        /// </summary>
        public const int INPUT_WINDOW = 6;        

        /// <summary>
        /// The number of bars forward we are trying to predict.  This is usually just 1 bar.  The future indicator used in step 1 may
        /// well look more forward into the future. 
        /// </summary>
        public const int PREDICT_WINDOW = 1;

        /// <summary>
        /// The number of bars forward to look for the best result.
        /// </summary>
        public const int RESULT_WINDOW = 5;

        /// <summary>
        /// The number of neurons in the first hidden layer.
        /// </summary>
        public const int HIDDEN1_NEURONS = 12;

        /// <summary>
        /// The target error to train to.
        /// </summary>
        public const double TARGET_ERROR = 0.01;

        static void Main(string[] args)
        {
            // Step 1: Create future indicators
            Console.WriteLine("Step 1: Analyze MT5 Export & Create Future Indicators");
            ProcessIndicators ind = new ProcessIndicators();
            ind.Analyze(STEP1_FILENAME, true, CSVFormat.DECIMAL_POINT);
            int externalIndicatorCount = ind.Columns.Count - 3;
            ind.AddColumn(new BestReturn(RESULT_WINDOW,true)); 
            ind.Process(STEP2_FILENAME);          
            Console.WriteLine("External indicators found: " + externalIndicatorCount);
            //Console.ReadKey();

            // Step 2: Normalize
            Console.WriteLine("Step 2: Create Future Indicators");
            EncogNormalize norm = new EncogNormalize();
            norm.Analyze(STEP2_FILENAME, true, CSVFormat.ENGLISH);
            norm.Stats[0].Action = NormalizationDesired.PassThrough; // Date
            norm.Stats[1].Action = NormalizationDesired.PassThrough; // Time
            
            norm.Stats[2].Action = NormalizationDesired.Normalize; // Close
            norm.Stats[3].Action = NormalizationDesired.Normalize; // Stoch K
            norm.Stats[4].Action = NormalizationDesired.Normalize; // Stoch Dd
            norm.Stats[5].Action = NormalizationDesired.Normalize; // WilliamsR
       
            norm.Stats[6].Action = NormalizationDesired.Normalize; // best return [RESULT_WINDOW]

            norm.Normalize(STEP3_FILENAME);

            // neuron counts
            int inputNeurons = INPUT_WINDOW * externalIndicatorCount;
            int outputNeurons = PREDICT_WINDOW;

            // Step 3: Time-box
            Console.WriteLine("Step 3: Timebox");
            //Console.ReadKey();
            TemporalWindow window = new TemporalWindow();
            window.Analyze(STEP3_FILENAME, true, CSVFormat.ENGLISH);
            window.InputWindow = INPUT_WINDOW;
            window.PredictWindow = PREDICT_WINDOW;
            int index = 0;
            window.Fields[index++].Action = TemporalType.Ignore; // date
            window.Fields[index++].Action = TemporalType.Ignore; // time
            window.Fields[index++].Action = TemporalType.Ignore; // close
            for(int i=0;i<externalIndicatorCount;i++)
                window.Fields[index++].Action = TemporalType.Input; // external indicators
            window.Fields[index++].Action = TemporalType.Predict; // PredictBestReturn

            window.Process(STEP4_FILENAME);

            // Step 4: Train neural network
            Console.WriteLine("Step 4: Train");
            Console.ReadKey();
            INeuralDataSet training = (BasicNeuralDataSet)EncogUtility.LoadCSV2Memory(STEP4_FILENAME, inputNeurons, 
                                                                                      outputNeurons, true, CSVFormat.ENGLISH);

            BasicNetwork network = new BasicNetwork();
            network.AddLayer(new BasicLayer(new ActivationTANH(), true, inputNeurons));
            network.AddLayer(new BasicLayer(new ActivationTANH(), true, HIDDEN1_NEURONS));
            network.AddLayer(new BasicLayer(new ActivationLinear(), true, outputNeurons));
            network.Structure.FinalizeStructure();
            network.Reset();

            //EncogUtility.TrainToError(network, training, TARGET_ERROR);
            EncogUtility.TrainConsole(network, training, 3);

            // Step 5: Save neural network and stats
            EncogMemoryCollection encog = new EncogMemoryCollection();
            encog.Add("network", network);
            encog.Add("stat", norm.Stats);
            encog.Save(STEP5_FILENAME);
            Console.ReadKey();
        }
    }
}

Puede que note que comenté una línea y cambié la función de formación de EncogUtility.TrainToError() a EncogUtility.TrainConsole()

EncogUtility.TrainConsole(network, training, 3);

El método TrainConsole especifica un número de minutos para formar la red. En el ejemplo, formo la red durante tres minutos. Dependiendo de la complejidad de la red y tamaño de los datos de formación, formar la red puede llevar unos pocos minutos, horas, o incluso días. Le recomiendo que lea más sobre cálculo de error y algoritmos de formación en la página web de Heaton Research, o en cualquier otro libro sobre el tema.

Los métodos EncogUtility.TrainToError() detienen la formación de la red después de encontrarse con un error de red de objetivo. Puede comentar EncongUtiliy.TrainConsole() y eliminar el comentario de EncogUtility.TrainToError() para formar la red hasta el error deseado como en el ejemplo original 

EncogUtility.TrainToError(network, training, TARGET_ERROR);

Por favor, tenga en cuenta que a veces la red no se puede formar hasta un determinado error porque el número de neuronas puede ser demasiado pequeño.


8. Usar la Red Neuronal Formada para Construir un Indicador Neuronal de MetaTrader 5

La red formada se puede usar por un indicador de red neuronal que intentará predecir el mejor retorno de las inversiones.

El indicador neuronal ENCOG para MetaTrader 5 consta de dos partes. Una parte se escribe en MQL5, y básicamente toma los mismos indicadores con los que se formó la red y alimenta la red con los valores de indicador de la ventana de entrada de datos. La segunda parte se escribe en C#, pone datos de entrada en timebox y devuelve los datos extraídos de la red neuronal a MQL5. La parte del indicador C# se basa en mi artículo anterior Exposing C# code to MQL5 (Exponer código C# a MQL5).

using System;
using System.Collections.Generic;
using System.Text;
using RGiesecke.DllExport;
using System.Runtime.InteropServices;
using Encog.Neural.Networks;
using Encog.Persist;
using Encog.App.Quant.Normalize;
using Encog.Neural.Data;
using Encog.Neural.Data.Basic;

namespace EncogNeuralIndicatorMT5DLL
{

    public class NeuralNET
    {
        private EncogMemoryCollection encog;
        public BasicNetwork network;
        public NormalizationStats stats;

        public NeuralNET(string nnPath)
        {
            initializeNN(nnPath);
        }

        public void initializeNN(string nnPath)
        {
            try
            {
                encog = new EncogMemoryCollection();
                encog.Load(nnPath);
                network = (BasicNetwork)encog.Find("network");
                stats = (NormalizationStats)encog.Find("stat");
            }
            catch (Exception e)
            {
                Console.WriteLine(e.StackTrace);
            }
        }
    };

   class UnmanagedExports
   {

      static NeuralNET neuralnet; 

      [DllExport("initializeTrainedNN", CallingConvention = CallingConvention.StdCall)]
      static int initializeTrainedNN([MarshalAs(UnmanagedType.LPWStr)]string nnPath)
      {
          neuralnet = new NeuralNET(nnPath);

          if (neuralnet.network != null) return 0;
          else return -1;
      }

      [DllExport("computeNNIndicator", CallingConvention = CallingConvention.StdCall)]
      public static int computeNNIndicator([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] double[] t1,
                                           [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] double[] t2,
                                           [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] double[] t3, 
                                           int len, 
                                           [In, Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 5)] double[] result,
                                           int rates_total)
      {
          INeuralData input = new BasicNeuralData(3 * len);
          
          int index = 0;
          for (int i = 0; i <len; i++)
          {
              input[index++] = neuralnet.stats[3].Normalize(t1[i]);
              input[index++] = neuralnet.stats[4].Normalize(t2[i]);
              input[index++] = neuralnet.stats[5].Normalize(t3[i]);
          }

          INeuralData output = neuralnet.network.Compute(input);
          double d = output[0];
          d = neuralnet.stats[6].DeNormalize(d);        
          result[rates_total-1]=d;

          return 0;
      }  
   }
}

Si desea usar cualquier otro número de indicadores que no sea tres, debe cambiar el método computeNNIndicator() para que se adapte a sus necesidades. 

 [DllExport("computeNNIndicator", CallingConvention = CallingConvention.StdCall)]
      public static int computeNNIndicator([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] double[] t1,
                                         [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] double[] t2,
                                         [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] double[] t3, 
                                         int len, 
                                         [In, Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 5)] double[] result,
                                         int rates_total)

En este caso, los primeros tres parámetros de entrada son tablas que contienen valores de indicador de entrada, y el cuarto parámetro es la longitud de la ventana de entrada de datos.

SizeParamIndex = 3 puntos para la variable de longitud de la ventana de entrada de datos, mientras que la cuenta de variables de entrada aumenta de 0 hacia adelante. El quinto parámetro es una tabla que contiene resultados de red neuronal. 

La parte del indicador MQL5 debe importarse a C# EncogNNTrainDLL.dll y usar las funciones initializeTrainedNN() y computeNNIndicator() exportadas del dll.

//+------------------------------------------------------------------+
//|                                         NeuralEncogIndicator.mq5 |
//|                                      Copyright 2011, Investeo.pl |
//|                                                http:/Investeo.pl |
//+------------------------------------------------------------------+
#property copyright "Copyright 2011, Investeo.pl"
#property link      "http:/Investeo.pl"
#property version   "1.00"
#property indicator_separate_window

#property indicator_plots 1
#property indicator_buffers 1
#property indicator_color1 Blue
#property indicator_type1 DRAW_LINE
#property indicator_style1 STYLE_SOLID
#property indicator_width1  2

#import "EncogNNTrainDLL.dll"
   int initializeTrainedNN(string nnFile);
   int computeNNIndicator(double& ind1[], double& ind2[],double& ind3[], int size, double& result[], int rates);  
#import


int INPUT_WINDOW = 6;
int PREDICT_WINDOW = 1;

double ind1Arr[], ind2Arr[], ind3Arr[]; 
double neuralArr[];

int hStochastic;
int hWilliamsR;

int hNeuralMA;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0, neuralArr, INDICATOR_DATA);
   
   PlotIndexSetInteger(0, PLOT_SHIFT, 1);

   ArrayResize(ind1Arr, INPUT_WINDOW);
   ArrayResize(ind2Arr, INPUT_WINDOW);
   ArrayResize(ind3Arr, INPUT_WINDOW);
     
   ArrayInitialize(neuralArr, 0.0);
   
   ArraySetAsSeries(ind1Arr, true);   
   ArraySetAsSeries(ind2Arr, true);  
   ArraySetAsSeries(ind3Arr, true);
  
   ArraySetAsSeries(neuralArr, true);   
               
   hStochastic = iStochastic(NULL, 0, 8, 5, 5, MODE_EMA, STO_LOWHIGH);
   hWilliamsR = iWPR(NULL, 0, 21);
 
   Print(TerminalInfoString(TERMINAL_DATA_PATH)+"\\MQL5\Files\step5_network.eg");
   initializeTrainedNN(TerminalInfoString(TERMINAL_DATA_PATH)+"\\MQL5\Files\step5_network.eg");
      
//---
   return(0);
  }
//+------------------------------------------------------------------+
//| 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 calc_limit;
   
   if(prev_calculated==0) // First execution of the OnCalculate() function after the indicator start
        calc_limit=rates_total-34; 
   else calc_limit=rates_total-prev_calculated;
    
   ArrayResize(neuralArr, rates_total);
  
   for (int i=0; i<calc_limit; i++)     
   {
      CopyBuffer(hStochastic, 0, i, INPUT_WINDOW, ind1Arr);
      CopyBuffer(hStochastic, 1, i, INPUT_WINDOW, ind2Arr);
      CopyBuffer(hWilliamsR,  0, i, INPUT_WINDOW, ind3Arr);    
      
      computeNNIndicator(ind1Arr, ind2Arr, ind3Arr, INPUT_WINDOW, neuralArr, rates_total-i); 
   }
     
  //Print("neuralArr[0] = " + neuralArr[0]);
  
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+

Por favor, vea los datos diarios del indicador de salida formado en USDCHF y los indicadores Stochastic y Williams %R:

 Figura 7. Indicador neuronal Encog

Figura 7. Indicador neuronal Encog

El indicador muestra el mejor resultado de inversión pronosticado en la siguiente barra.

Puede que haya notado que cambié el indicador a una barra en el futuro:

PlotIndexSetInteger(0, PLOT_SHIFT, 1);

Esto es para indicar que el indicador es un vaticinador. Puesto que creamos un indicador neuronal, estamos listos para construir un Asesor Experto (EA, por sus siglas en inglés) basado en el indicador.


9. Asesor Experto Basado en un Indicador Neuronal

El Asesor Experto toma los datos extraídos del indicador neuronal y decide si debe comprar o vender una seguridad. Mi primera impresión fue que debería comprar cada vez que el indicador esté por encima de cero, y vender si está por debajo de cero; es decir, comprar cuando la predicción del mejor resultado en un determinado intervalo de tiempo sea positiva, y vender cuando la predicción del mejor resultado sea negativa.

Tras algunas comprobaciones iniciales, resultó que el rendimiento podía ser mejor, de modo que introduje variables de "tendencia ascendente fuerte" y "tendencia descendente fuerte", que siguen la regla de que no hay motivo para salir de la operación cuando nos encontramos en plena tendencia fuerte.

Además, en el foro de Heaton Research me aconsejaron usar ATR para mover stop losses, de modo que usé el indicador Chandelier ATR que encontré en el foro de MQL5. Y sí, aumentó mi beneficio durante la simulación. Aquí he pegado el código fuente del Asesor Experto.

//+------------------------------------------------------------------+
//|                                           NeuralEncogAdvisor.mq5 |
//|                                      Copyright 2011, Investeo.pl |
//|                                                http:/Investeo.pl |
//+------------------------------------------------------------------+
#property copyright "Copyright 2011, Investeo.pl"
#property link      "http:/Investeo.pl"
#property version   "1.00"

double neuralArr[];

double trend;
double Lots=0.3;

int INPUT_WINDOW=8;

int hNeural,hChandelier;

//+------------------------------------------------------------------+
#include <Trade\Trade.mqh>
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   ArrayResize(neuralArr,INPUT_WINDOW);
   ArraySetAsSeries(neuralArr,true);
   ArrayInitialize(neuralArr,0.0);

   hNeural=iCustom(Symbol(),Period(),"NeuralEncogIndicator");
   Print("hNeural = ",hNeural,"  error = ",GetLastError());

   if(hNeural<0)
     {
      Print("The creation of ENCOG indicator has failed: Runtime error =",GetLastError());
      //--- forced program termination
      return(-1);
     }
   else  Print("ENCOG indicator initialized");

   hChandelier=iCustom(Symbol(),Period(),"Chandelier");
   Print("hChandelier = ",hChandelier,"  error = ",GetLastError());

   if(hChandelier<0)
     {
      Print("The creation of Chandelier indicator has failed: Runtime error =",GetLastError());
      //--- forced program termination
      return(-1);
     }
   else  Print("Chandelier indicator initialized");
//---
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   long tickCnt[1];
   int ticks=CopyTickVolume(Symbol(),0,0,1,tickCnt);
   if(tickCnt[0]==1)
     {
      if(!CopyBuffer(hNeural,0,0,INPUT_WINDOW,neuralArr)) { Print("Copy1 error"); return; }

      // Print("neuralArr[0] = "+neuralArr[0]+"neuralArr[1] = "+neuralArr[1]+"neuralArr[2] = "+neuralArr[2]);
      trend=0;

      if(neuralArr[0]<0 && neuralArr[1]>0) trend=-1;
      if(neuralArr[0]>0 && neuralArr[1]<0) trend=1;

      Trade();
     }
  }
//+------------------------------------------------------------------+
//| Tester function                                                  |
//+------------------------------------------------------------------+
double OnTester()
  {
//---

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

void Trade()
  {
   double bufChandelierUP[2];
   double bufChandelierDN[2];

   double bufMA[2];

   ArraySetAsSeries(bufChandelierUP,true);
   ArraySetAsSeries(bufChandelierUP,true);

   ArraySetAsSeries(bufMA,true);

   CopyBuffer(hChandelier,0,0,2,bufChandelierUP);
   CopyBuffer(hChandelier,1,0,2,bufChandelierDN);

   MqlRates rates[];
   ArraySetAsSeries(rates,true);
   int copied=CopyRates(Symbol(),PERIOD_CURRENT,0,3,rates);

   bool strong_uptrend=neuralArr[0]>0 && neuralArr[1]>0 && neuralArr[2]>0 &&
                      neuralArr[3]>0 && neuralArr[4]>0 && neuralArr[5]>0 &&
                       neuralArr[6]>0 && neuralArr[7]>0;
   bool strong_downtrend=neuralArr[0]<0 && neuralArr[1]<0 && neuralArr[2]<0 &&
                        neuralArr[3]<0 && neuralArr[4]<0 && neuralArr[5]<0 &&
                        neuralArr[6]<0 && neuralArr[7]<0;

   if(PositionSelect(_Symbol))
     {
      long type=PositionGetInteger(POSITION_TYPE);
      bool close=false;

      if((type==POSITION_TYPE_BUY) && (trend==-1))

         if(!(strong_uptrend) || (bufChandelierUP[0]==EMPTY_VALUE)) close=true;
      if((type==POSITION_TYPE_SELL) && (trend==1))
         if(!(strong_downtrend) || (bufChandelierDN[0]==EMPTY_VALUE))
            close=true;
      if(close)
        {
         CTrade trade;
         trade.PositionClose(_Symbol);
        }
      else // adjust s/l
        {
         CTrade trade;

         if(copied>0)
           {
            if(type==POSITION_TYPE_BUY)
              {
               if(bufChandelierUP[0]!=EMPTY_VALUE)
                  trade.PositionModify(Symbol(),bufChandelierUP[0],0.0);
              }
            if(type==POSITION_TYPE_SELL)
              {
               if(bufChandelierDN[0]!=EMPTY_VALUE)
                  trade.PositionModify(Symbol(),bufChandelierDN[0],0.0);
              }
           }
        }
     }

   if((trend!=0) && (!PositionSelect(_Symbol)))
     {
      CTrade trade;
      MqlTick tick;
      MqlRates rates[];
      ArraySetAsSeries(rates,true);
      int copied=CopyRates(Symbol(),PERIOD_CURRENT,0,INPUT_WINDOW,rates);

      if(copied>0)
        {
         if(SymbolInfoTick(_Symbol,tick)==true)
           {
            if(trend>0)
              {
               trade.Buy(Lots,_Symbol,tick.ask);
               Print("Buy at "+tick.ask+" trend = "+trend+" neuralArr = "+neuralArr[0]);
              }
            if(trend<0)
              {
               trade.Sell(Lots,_Symbol,tick.bid);
               Print("Sell at "+tick.ask+" trend = "+trend+" neuralArr = "+neuralArr[0]);
              }
           }
        }
     }

  }
//+------------------------------------------------------------------+

El Asesor Experto se ejecutó en datos D1 de divisas USDCHF. Alrededor del 50% de los datos se tomaron de una muestra de la formación.


10. Resultados de la Simulación del Asesor Experto

Aquí he pegado los resultados de la simulación. La simulación se ejecutó desde 2000.01.01 hasta 2011.03.26.

Figura 8. Resultados de la simulación del Expert Advisor neuronal

Figura 8. Resultados de la simulación del Asesor Experto neuronal

Figura 9. Gráfico de Saldo/Beneficio de la simulación del Expert Advisor neuronal

Figura 9. Gráfico de Saldo/Beneficio de la simulación del Asesor Experto neuronal

Por favor, tenga en cuenta que este rendimiento podría ser totalmente diferente en otro intervalo temporal y con otras seguridades.

Por favor, trate este EA como un recurso educativo, y utilícelo como base para futuras investigaciones. En mi punto de vista, la red se puede formar de nuevo cada cierto período de tiempo para hacerla más robusta. Quizás alguien encontrará una buena forma de conseguir esto, o quizás ya lo ha hecho. Quizás haya una manera mejor de hacer predicciones de compra o venta basadas en un indicador neuronal. Animo a los lectores a que hagan sus propios experimentos.


Conclusión

En este artículo he presentado una forma de construir un indicador neuronal para hacer predicciones y un Asesor Experto basado en este indicador con la ayuda de la estructura de aprendizaje automático ENCOG. Todos los códigos fuente, binarios combinados, DLLs y un ejemplo de red formada se pueden encontrar como archivos adjuntos a este artículo.


A causa de "double DLL wrapping in .NET" ("doble envoltura DLL en .NET"), los archivos Cloo.dll, encog-core-cs.dll y log4net.dll se deberían encontrar en la carpeta del terminal de cliente.
El archivo EncogNNTrainDLL.dll debería estar localizado en la carpeta \Terminal Data folder\MQL5\Libraries\.


Traducción del inglés realizada por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/en/articles/252

Archivos adjuntos |
encogcsharp.zip (2202.77 KB)
files.zip (270.14 KB)
libraries.zip (321.62 KB)
experts.zip (1.56 KB)
scripts.zip (1.03 KB)
indicators.zip (2.24 KB)
La implementación del análisis automático de las Ondas de Elliott en MQL5 La implementación del análisis automático de las Ondas de Elliott en MQL5
Uno de los métodos más populares del análisis del mercado es el análisis de las ondas. Sin embargo, este proceso es bastante complejo lo que comporta el uso de herramientas adicionales. Una de estas herramientas es el marcador automático. En este artículo se describe el proceso de creación del analizador automático de las Ondas de Elliott en el lenguaje MQL5.
Modelo de Regresión Universal para la Predicción de Precio de Mercado Modelo de Regresión Universal para la Predicción de Precio de Mercado
El precio de mercado se forma mediante un equilibrio estable entre oferta y demanda, que a su vez depende de una variedad de factores económicos, políticos y psicológicos. Las diferencias en su naturaleza, así como las causas de influencia de estos factores, hacen que sea difícil considerar directamente todos los componentes. Este artículo llevará a cabo un intento de predecir el precio de mercado basándose en un elaborado modelo de regresión.
Usar Pseudo-Plantillas como Alternativa a Plantillas C++ Usar Pseudo-Plantillas como Alternativa a Plantillas C++
Este artículo describe una forma de programas sin usar plantillas, pero manteniendo el estilo de programación inherente a ellas. Trata sobre la implementación de plantillas usando métodos personalizados y tiene un archivo adjunto con un script ya hecho para crear un código basado en las plantillas especificadas.
Exponer código C# a MQL5 usando exportaciones no gestionadas Exponer código C# a MQL5 usando exportaciones no gestionadas
En este artículo presento diferentes métodos de interacción entre código MQL5 y código gestionado C#. También facilito varios ejemplos sobre cómo ordenar estructuras MQL5 en contraposición a C#, y cómo invocar funciones DLL exportadas en scripts MQL5. Creo que los ejemplos que proporciono podrán servir como base para estudios futuros sobre escritura de DLLs en código gestionado. Este artículo también abre puertas para MetaTrader para usar varias bibliotecas que ya están implementadas en C#.