![Usar Indicadores de MetaTrader 5 con la Estructura de Aprendizaje Automático ENCOG para Predicción de Series Cronológicas](https://c.mql5.com/i/articles/overlay.png)
Usar Indicadores de MetaTrader 5 con la Estructura de Aprendizaje Automático ENCOG para Predicción de Series Cronológicas
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.
- 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.
- 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.
- 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.
- 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.
- 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.
- Los elementos que ECNOG soporta actualmente:
Tipos de Aprendizaje Automático
- Feed-forward y Simple Recurrent (Recurrente Simple) (Elman/Jordan)
- Algoritmos Genéticos
- NEAT
- Probablistic Neural Network (Red Neuronal Probabilística)/ General Regression Neural Network (Red Neuronal de Regresión General) (PNN/GRNN)
- Self Organizing Map (Mapa Auto-Organizador) (SOM/Kohonen)
- Algoritmo de Recocido Simulado
- Máquina de Vectores de Soporte
Arquitecturas de Red Neuronal
Técnicas de Formación
- Red Neuronal ADALINE
- Adaptive Resonance Theory 1 (Teoría de Resonancia Adaptada 1) (ART1)
- Bidirectional Associative Memor (Memoria Asociativa Bidireccional) (BAM)
- Máquina Boltzmann
- Counterpropagation Neural Network (Red Neuronal de contrapropagación) (CPN)
- Red Neuronal Recurrente Elman
- Red Neuronal Feed-forward (Perceptron)
- Red Neuronal Hopfield
- Red Neuronal Recurrente Jordan
- Neuroevolution of Augmenting Topologies (Neuroevolución de Topologías Incrementadoras) (NEAT)
- Red de Función de Base Radial
- Recurrent Self Organizing Map (Mapa Auto-Organizador Recurrente) (RSOM)
- Mapa Auto-Organizador (Kohonen)
Funciones de Activación
- Contrapropagación
- Resilient Propagation (Propagación Resistente) (RPROP)
- Scaled Conjugate Gradient (Gradiente Conjugado en Escala) (SCG)
- Actualización de la Regla de Propagación Manhattan
- Aprendizaje Competitivo
- Aprendizaje Hopfield
- Levenberg-Marquardt Algorithm (Algoritmo de Levenberg-Marquardt) (LMA)
- Formación de Algoritmo Genético
- Formación Instar
- Formación Outstar
- Formación ADALINE
- Modelos de Formación de Datos
- Supervisado
- No supervisado
- Temporal (Predicción)
- Financiero (descargas desde Yahoo Finance)
- SQL
- XML
- CSV
- Downsampling de Imagen
Técnicas de Aleatoriedad
- Competitivo
- Sigmoid
- Tangente Hiperbólica
- Lineal
- SoftMax
- Tangencial
- Sinusoide
- Paso
- Bipolar
- Gaussiano
- Margen de Aleatoriedad
- Números Gaussianos Aleatorios
- Fan-In
- Nguyen-Widrow
Elementos planeados:
- HyperNEAT
- Máquina Boltzmann Restrictiva (RBN/Deep Belief)
- Redes Neuronales con Picos
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
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
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:
- Neural Network Calculation (Part 1): Feedforward Structure (Cálculo de Red Neuronal (Parte 1): Estructura de Feed-forward)
- Neural Network Calculation (Part 2): Activation Functions & Basic Calculation (Cálculo de Red Neuronal (Parte 2): Funciones de Activación y Cálculo Básico)
- Neural Network Calculation (Part 3): Feedforward Neural Network Calculatio (Cálculo de Red Neuronal (Parte 3): Cálculo de Red Neuronal de Feed-forward
Después de aprender sobre arquitectura de red neuronal y sus mecanismos, es posible que todavía se sienta confuso.
Los principales problemas son:
- ¿Qué datos deberíamos introducir en una red neuronal?
- ¿Cómo deberíamos alimentarla?
- ¿Cómo preparamos datos de entrada para una red neuronal?
- ¿Cómo elegir una arquitectura de red neuronal? ¿Cuántas neuronas de entrada, ocultas y de salida necesitamos?
- ¿Cómo formamos la red?
- ¿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
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
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 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
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
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 Asesor Experto 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
![La implementación del análisis automático de las Ondas de Elliott en MQL5](https://c.mql5.com/2/0/MQL5_Elliott_Waves_Automated.png)
![Modelo de Regresión Universal para la Predicción de Precio de Mercado](https://c.mql5.com/2/0/universal_regression.png)
![Usar Pseudo-Plantillas como Alternativa a Plantillas C++](https://c.mql5.com/2/0/MQL5_template.png)
![Exponer código C# a MQL5 usando exportaciones no gestionadas](https://c.mql5.com/2/0/logo__5.png)
![MQL5 - Lenguaje de estrategias comerciales para el terminal de cliente MetaTrader 5](https://c.mql5.com/i/registerlandings/logo-2.png)
- Aplicaciones de trading gratuitas
- 8 000+ señales para copiar
- Noticias económicas para analizar los mercados financieros
Usted acepta la política del sitio web y las condiciones de uso