English Русский 中文 Español Deutsch 日本語 Português 한국어 Italiano Türkçe
Utilisation des Indicateurs MetaTrader 5 avec le Cadre d'Apprentissage Automatique ENCOG pour la Prédiction de Séries Chronologiques

Utilisation des Indicateurs MetaTrader 5 avec le Cadre d'Apprentissage Automatique ENCOG pour la Prédiction de Séries Chronologiques

MetaTrader 5Exemples | 12 janvier 2022, 14:36
425 0
investeo
investeo

Introduction

Cet article présentera MetaTrader 5 vers ENCOG - Réseau avancé neuronal et cadre d’apprentissage automatique élaboré par Heaton Research. Il existe des méthodes décrites précédemment que je connais qui permettent à MetaTrader d'utiliser des techniques d'apprentissage automatique : FANN, NeuroSolutions, Matlab et NeuroShell. J'espère qu ENCOG sera une solution complémentaire puisqu'il s'agit d'un code robuste et bien conçu.

Pourquoi j'ai choisi ENCOG ? Il y a quelques motifs.

  1. ENCOG est utilisé dans deux autres progiciels de trading commerciaux. L'un est basé sur C#, le second sur JAVA. Cela indique qu'il a déjà été testé pour prédire les données de séries chronologiques financières. 
  2. ENCOG est un logiciel gratuit et de source publique Si vous souhaitez voir ce qui se passe à l'intérieur d'un réseau de neurones, vous pouvez parcourir le code source. C'est ce que j'ai fait pour comprendre certaines parties du problème de prédiction des séries chronologiques. C# est un langage de programmation propre et facile à comprendre.
  3. ENCOG est très bien documenté. M. Heaton, fondateur de Heaton Research, propose un cours en ligne gratuit sur les réseaux neuronaux, l'apprentissage automatique et l'utilisation d' ENCOG pour prédire les données futures. J'ai parcouru plusieurs de ses cours avant d'écrire cet article. Ils m'ont beaucoup aidé à comprendre les réseaux de neurones artificiels. De plus, il existe des livres électroniques sur la programmation d' ENCOG en JAVA et C# sur le site Web de Heaton Research. Documentation entière d’ ENCOG est disponible en ligne.
  4. ENCOG n'est pas un projet mort. Au moment de la rédaction de cet article, ENCOG 2.6 est toujours en cours d’élaboration. La feuille de route ENCOG 3.0 a été récemment publiée.
  5. ENCOG est robuste. Il est bien conçu, peut utiliser plusieurs noyaux de processeur et le multithreading pour accélérer les calculs du réseau neuronal. Des parties du code commencent à être transférées pour les calculs compatibles OpenCL - GPU.
  6. Fonctionnalités actuellement prises en charge par ECNOG : 

Types d'Apprentissage Automatique

Architectures de Réseaux de Neurones

Techniques de FormationFonctions d'ActivationTechniques de Randomisation
  • Randomisation de la plage
  • Nombres aléatoires gaussiens
  • Fan-In
  • Nguyen-Widrow

Fonctionnalités prévues :

Comme vous pouvez le constater, la liste des fonctionnalités est assez longue.

Cet article préliminaire se concentre sur l'architecture de réseau neuronal à réaction anticipative avec la formation Propagation Résiliente (RPROP) . Il couvre également les bases de la préparation des données - le timeboxing et la normalisation pour la prévision des séries chronologiques.

Les connaissances qui m'ont permis d'écrire cet article sont axées sur des tutoriels disponibles sur le site de Heaton Research et des articles très récents sur la prédiction de séries chronologiques financières dans NinjaTrader. Veuillez noter qu 'ENCOG est basé sur JAVA et C#. Sans mon précédent travail, l’écriture de cet article ne serait pas possible Exposer le code C# à MQL5 à l'aide d'exportations non gérées. Cette solution a permis d'utiliser la DLL C# comme pont entre l'indicateur Metatrader 5 et le prédicteur de séries chronologiques ENCOG.


1. Utilisation de valeurs d'indicateurs techniques comme entrées pour un réseau de neurones

Le Réseau de Neurones Artificiels est un algorithme conçu par l'homme qui tente d'émuler le réseau de neurones du cerveau.

Il existe différents types d'algorithmes neuronaux disponibles ainsi qu’une variété d'architectures de réseaux neuronaux. Le domaine de recherche est si vaste qu'il existe des livres entiers consacrés à un seul type de réseau de neurones. Vu que de tels détails sortent du cadre de cet article, je ne peux que recommander de parcourir les didacticiels de Heaton Research ou de lire un livre sur le sujet. Je me concentrerai sur les entrées et les sorties du réseau de neurones à action directe et j'essaierai de décrire l'exemple pratique de prédiction de séries chronologiques financières.

Afin de commencer à prévoir des séries chronologiques financières, nous devons réfléchir à ce que nous devrions fournir au réseau de neurones et à ce que nous pourrions attendre en retour. Dans la plupart des pensées abstraites de la boîte noire, nous réalisons un bénéfice ou une perte en prenant des positions longues ou courtes sur le contrat d'un titre donné et en concluant le deal après un certain temps.

Par l'observation des prix passés d'un titre et des valeurs des indicateurs techniques, nous essayons de prédire le sentiment futur ou la direction des prix afin d'acheter ou de vendre un contrat et de nous assurer que notre décision n'est pas prise en lançant une pièce. La situation ressemble plus moins à la figure ci-dessous :

Figure 1. Prévision de séries chronologiques financières à l'aide d'indicateurs techniques

Figure 1. Prévision de séries chronologiques financières à l'aide d'indicateurs techniques 

Nous allons tenter d'obtenir la même chose avec l'intelligence artificielle. Le réseau neuronal tentera de reconnaître les valeurs des indicateurs et décidera s'il y a une chance que le prix monte ou baisse. Comment y parvenir ? Étant donné que nous prévoyons des séries chronologiques financières en utilisant l'architecture de réseau de neurones feed forward,je pense que nous devons faire une introduction à son architecture.

Le réseau de neurones à réaction anticipée est constitué de neurones regroupés en couches. Il doit y avoir au minimum 2 couches : une couche d'entrée qui comporte les neurones d'entrée et une couche de sortie qui comporte les neurones de sortie. Il peut également y avoir des couches cachées entre les couches d'entrée et de sortie. La couche d'entrée peut être simplement considérée comme un tableau de valeurs doubles et la couche de sortie peut être constituée d'un ou plusieurs neurones qui forment également un tableau de valeurs doubles. Veuillez consulter la figure ci-dessous :

 Figure 2. Couches de réseau de neurones à Réaction Anticipative

Figure 2. Couches de réseau de neurones à réaction anticipative 

Les connexions entre les neurones n'ont pas été dessinées afin de simplifier le dessin. Chaque neurone de la couche d'entrée est connecté à un neurone de la couche cachée. Chaque neurone de la couche cachée est connecté à un neurone de la couche de sortie.

Chaque connexion a son poids, qui est aussi une double valeur et une fonction d'activation avec un seuil, qui est responsable de l'activation d'un neurone et de la transmission de l'information au neurone suivant. C'est pourquoi on l'appelle un réseau « Réaction anticipative » - les informations axées sur les sorties de neurones activés sont transmises d'une couche à une autre couche de neurones. Pour des vidéos d'introduction détaillées sur les réseaux de neurones à réaction anticipative, vous pouvez visiter les liens suivants :

Une fois que vous aurez appris davantage sur l'architecture des réseaux neuronaux et ses mécanismes, vous serez peut-être encore perplexe.

Les principaux problèmes sont :

  1. Quelles données devons-nous fournir à un réseau de neurones ?
  2. Comment le nourrir ?
  3. Comment préparer les données d'entrée pour un réseau de neurones ? 
  4. Comment choisir l'architecture de réseau de neurones ? De combien de neurones d'entrée, de neurones cachés et de neurones de sortie avons-nous besoin ?
  5. Comment former le réseau ?
  6. Qu'attendez-vous du résultat ?

 

2. Avec quelles données alimenter le réseau de neurones

Puisque nous avons affaire à des prévisions financières basées sur les sorties d'indicateurs, nous devons alimenter le réseau avec des valeurs de sortie d'indicateurs. Pour cet article j'ai choisi Stochastic %K, Stochastic Slow %D, and Williams %Rcomme entrées.

Figure 3. Indicateurs techniques utilisés pour la prédiction

Figure 3. Indicateurs techniques utilisés pour la prédiction

Afin d'extraire les valeurs des indicateurs, nous pouvons utiliser les fonctionsiStochastic et iWPR MQL5:

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);

Une fois ce code exécuté, trois tableaux StochKArr, StochDArr et WilliamsRArr doivent être remplis avec les valeurs de sortie des indicateurs. En fonction de la taille de l'échantillon d'apprentissage, cela peut aller jusqu'à quelques milliers de valeurs. Veuillez garder à l'esprit que ces deux indicateurs ont été choisis uniquement à des fins éducatives.

Nous vous encourageons à expérimenter avec tous les indicateurs que vous jugez appropriés pour la prédiction. Vous voudrez peut-être alimenter le réseau avec les prix de l'or et du pétrole pour prédire les indices boursiers ou vous pouvez utiliser des paires de devises forex corrélées pour prédire une autre paire de devises. 

 

3. Données d'entrée de timeboxing

Après avoir collecté les données d'entrée de plusieurs indicateurs, nous devons appliquer «timeboxing» l'entrée avant de l'alimenter dans le réseau de neurones. Le timeboxing est une technique qui permet de présenter les entrées pour le réseau sous forme de tranches de données mobiles. Vous pouvez imaginer une boîte en mouvement de données d'entrée avançant sur l'axe du temps. Il y a essentiellement deux étapes impliquées dans cette procédure:

1. Rassembler les données d'entrée de chaque tampon d'indicateur. Nous devons copier le nombre d'éléments INPUT_WINDOW de la position de départ vers le futur. La fenêtre d'entrée est le nombre de barres utilisées pour la prédiction. 

 Figure 4. Collecte des données de la fenêtre d'entrée à partir du tampon d'indicateur

Figure 4. Collecte des données de la fenêtre d'entrée à partir du tampon indicateur 

Comme vous pouvez le constater dans l'exemple ci-dessus, INPUT_WINDOW équivaut à 4 barres et nous avons copié des éléments dans le tableau I1. I1[0] est le premier élément I1[3] est le dernier. De même, les données doivent être copiées à partir d'autres indicateurs dans des tableaux de taille INPUT_WINDOW. Ce chiffre est valable pour séries chronologiques tableaux avec AS_SERIES flag fixés à vrai. 

2. Combinaison de tableaux INPUT_WINDOW en un seul tableau qui alimente la couche d'entrée du réseau neuronal. 

Figure 5. Tableaux de fenêtres d'entrée ayant fait l’objet de timeboxing 

Figure 5. Tableaux de fenêtres d'entrée ayant fait l’objet de timeboxing

Il y a 3 indicateurs, d'abord nous prenons la première valeur de chaque indicateur, puis la deuxième valeur de chaque indicateur, et nous continuons jusqu'à ce que la fenêtre de saisie soit remplie comme sur la figure ci-dessus. Un tel tableau combiné à partir de sorties d'indicateurs peut être transmis à la couche d'entrée de notre réseau de neurones. Lorsqu'une nouvelle barre arrive, les données sont découpées par un élément et toute la procédure est répétée. Si vous souhaitez obtenir plus de détails sur la préparation des données pour la prédiction, vous pouvez également voir une vidéosur le thème.

 

4. Normalisation des données d'entrée

Afin de rendre le réseau de neurones efficace, nous devons normaliser les données. Ceci est nécessaire pour un bon calcul des fonctions d'activation. La normalisation est un processus mathématique qui convertit les données dans la plage 0..1 ou -1..1. Les données normalisées peuvent faire l’objet de dénormalisation, c'est-à-dire reconverties dans la plage d'origine.

La dénormalisation est nécessaire pour décoder la sortie du réseau neuronal sous une forme lisible par l'homme. Heureusement, ENCOG s'occupe de la normalisation et de la dénormalisation, il n'est donc pas nécessaire de l'implémenter. Si vous êtes curieux de savoir comment cela fonctionne, vous pouvez analyser le code suivant :

/**
         * 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;
        }

et lire un article sur la normalisationpour plus de détails. 

 

5. Choix de l'architecture du réseau et du nombre de neurones

Pour un débutant sur le sujet, choisir une architecture de réseau correcte est une partie difficile. Dans cet article, je limite l'architecture du réseau de neurones à réaction anticipative à trois couches : une couche d'entrée, une couche cachée et une couche de sortie. Vous êtes libre d'expérimenter avec un plus grand nombre de couches.

Pour les couches d'entrée et de sortie, nous pourrons compter avec précision le nombre de neurones nécessaires. Pour une couche cachée, nous tenterons de minimiser les erreurs de réseau neuronal en utilisant un algorithme de sélection directe. Vous êtes encouragé à utiliser d'autres méthodes ; il peut y avoir des algorithmes génétiques pour calculer le nombre de neurones.

Une autre méthode utilisée par ENCOG est appelée algorithme de sélection en arrière ou élagage. Il s'agit essentiellement d'évaluer les connexions entre les couches et de supprimer les neurones cachés avec des connexions à pondération nulle. Vous pouvez également l'essayer.

5.1. Couche de neurones d'entrée

En raison du timeboxing, le nombre de neurones dans la couche d'entrée devra être égal au nombre d'indicateurs multiplié par le nombre de barres utilisées pour prédire la barre suivante. Si nous utilisons 3 indicateurs comme entrées et que la taille de la fenêtre d'entrée est égale à 6 barres, la couche d'entrée sera constituée de 18 neurones. La couche d'entrée est alimentée en données préparées par timeboxing.

5.2. Couche de neurones cachés

Le nombre de réseaux cachés doit être estimé en fonction des performances du réseau neuronal entraîné. Il n'y a pas d'équation mathématique simple pour un certain nombre de neurones cachés. Avant d'écrire l'article, j'ai utilisé plusieurs approches d'essais et d'erreurs et j'ai trouvé un algorithme sur le site Web de Heaton Research qui aide à comprendre l'algorithme de sélection directe :

Figure 6. Algorithme de sélection directe pour le nombre de neurones cachés 

Figure 6. Algorithme de sélection directe pour le nombre de neurones cachés 

5.3. Couche de neurones de sortie

Pour nos besoins, le nombre de neurones de sortie est le nombre de barres que nous essayons de prédire. N'oubliez pas que plus le nombre de neurones cachés et de sortie est plus élevé, plus le réseau prend du temps à se former. Dans cet article, je tente de prédire une barre dans le futur, donc la couche de sortie se compose d'un neurone.

 

6. Exportation des données d'entraînement de MetaTrader 5 vers ENCOG

Encog accepte les fichiers CSV pour la formation sur les réseaux neuronaux.

J'ai examiné le format de fichier exporté d'un autre logiciel de trading vers ENCOG et implémenté le script MQL5 qui prépare le même format de fichier pour la formation. Je présenterai d'abord l'exportation d'un indicateur et poursuivrai plus tard avec plusieurs indicateurs. 

La première ligne de données est un en-tête séparé par des virgules :

DATE,TIME,CLOSE,Indicator_Name1,Indicator_Name2,Indicator_Name3

Les trois premières colonnes comportent les valeurs de date, d'heure et de fermeture, les colonnes suivantes comportent les noms des indicateurs. Les prochaines lignes du fichier de formation doivent comprendre des données séparées par des virgules, les valeurs des indicateurs doivent être écrites au format scientifique :  

20110103,0000,0.93377000,-7.8970208860e-002

Veuillez observer le script prêt à l'emploi pour un indicateur ci-dessous.

//+------------------------------------------------------------------+
//|                                                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."); 
  }
//+------------------------------------------------------------------+

 Le fichier de résultats pouvant être utilisé pour la formation doit ressembler à la sortie suivante : 

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

Revenir à l'exemple d'article d'origine avec Stochastic and Williams' R, nous devons exporter trois colonnes séparées par des virgules, chaque colonne comporte des valeurs d'indicateur distinctes, nous devons donc développer le fichier et ajouter des tampons supplémentaires :

//+------------------------------------------------------------------+
//|                                                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."); 
  }
//+------------------------------------------------------------------+

Le fichier de résultats doit comporter toutes les valeurs d'indicateur :

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

Vous pouvez modifier le deuxième exemple pour produire facilement un script qui répondra à vos besoins.


7. Formation en réseau neuronal

La formation du réseau a déjà été préparée en C# par Heaton Research. ENCOG 2.6 implémente l'espace de noms Encog.App.Quant qui est une base pour la prédiction de séries chronologiques financières. Le script de formation est très flexible et peut être facilement ajusté à n'importe quel nombre d'indicateurs d'entrée. Vous ne devez modifier l'emplacement du répertoire MetaTrader 5 que dans la constante DIRECTORY.

L'architecture du réseau et les paramètres de formation peuvent être facilement personnalisés en modifiant les variables suivantes :

        /// <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;

Le code est très explicite, donc le mieux sera de le lire attentivement :

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();
        }
    }
}

Vous remarquerez peut-être que j'ai commenté une ligne et changé la fonction de formation de EncogUtility.TrainToError() en EncogUtility.TrainConsole()

EncogUtility.TrainConsole(network, training, 3);

La méthode TrainConsole indique un nombre de minutes pour former le réseau. Dans l'exemple, j'entraîne le réseau pendant trois minutes. En fonction de la complexité du réseau et la taille des données de formation, la formation du réseau peut prendre quelques minutes, heures ou même jours. Je recommande de lire plus sur le calcul d’erreur and algorithmes de formation sur le site web de Heaton Research ou tout autre livre sur le thème..

Les méthodes EncogUtility.TrainToError() interrompent d'entraîner le réseau une fois qu'une erreur de réseau cible est atteinte. Vous pouvez commenter EncongUtiliy.TrainConsole() et décommenter EncogUtility.TrainToError() pour entraîner le réseau jusqu'à une erreur souhaitée comme dans l'exemple original 

EncogUtility.TrainToError(network, training, TARGET_ERROR);

Veuillez noter que parfois le réseau ne peut pas être entraîné à une certaine erreur car le nombre de neurones peut être trop petit.


8. Utilisation d'un réseau neuronal formé pour créer un indicateur neuronal MetaTrader 5

Un réseau formé peut être utilisé par un indicateur de réseau neuronal qui tentera de prédire le meilleur rendement sur investissement.

L'indicateur neuronal ENCOG pour MetaTrader 5 se compose de deux parties. Une partie est écrite en MQL5 et prend essentiellement les mêmes indicateurs que ceux avec lesquels le réseau a été formé et alimente le réseau avec des valeurs d'indicateur de fenêtre d'entrée. La deuxième partie est écrite en C# et elle applique le timeboxing aux données d'entrée et renvoie la sortie du réseau neuronal à MQL5. La partie indicateur C# est axée sur mon article précédent sur l’Exposition du C# code to 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 vous souhaitez utiliser un autre nombre d'indicateurs que trois, vous devez modifier la méthode computeNNIndicator() en fonction de vos besoins. 

 [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)

Dans ce cas, trois premiers paramètres d'entrée sont des tableaux qui comportent des valeurs d'entrée d'indicateur, le quatrième paramètre est la longueur de la fenêtre d'entrée.

SizeParamIndex = 3 points sur la variable de longueur de fenêtre d'entrée, car le nombre de variables d'entrée est augmenté à partir de 0. Le cinquième paramètre est un tableau qui comporte les résultats du réseau neuronal. 

La partie indicateur MQL5 doit importer un C# EncogNNTrainDLL.dll et utiliser les fonctions initializeTrainedNN() et computeNNIndicator() exportées à partir de la 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);
  }
//+------------------------------------------------------------------+

Veuillez consulter la sortie de l'indicateur formé sur les données quotidiennes de l' USDCHF etStochastic et Williams %R indicateurs:

 Figure 7. Indicateur Neuronal Encog

Figure 7. Indicateur d’ Encog neuronal

L'indicateur indique le meilleur rendement sur investissement prévu sur la barre suivante.

Vous avez peut-être remarqué que j'ai déplacé l'indicateur d'une barre à l'avenir :

PlotIndexSetInteger(0, PLOT_SHIFT, 1);

Ceci pour indiquer que l'indicateur est prédictif. Puisque nous avons élaboré un indicateur neuronal, nous sommes prêts à créer un Expert Advisor axé sur l'indicateur.


9. Expert Advisor basé sur un indicateur neuronal

L'Expert Advisor prend la sortie de l'indicateur neuronal et décide d'acheter ou de vendre un titre. Ma première impression était qu'il devrait acheter chaque fois que l'indicateur est supérieur à zéro et vendre lorsqu'il est inférieur à zéro, ce qui indique acheter lorsque la meilleure prédiction de rendement sur une fenêtre de temps donnée est positive et vendre lorsque la meilleure prédiction de rendement est négative.

Après quelques tests initiaux, il s'est avéré que les performances pourraient être meilleures. Donc, j’ai présenté les variables «forte tendance à la hausse» et «forte tendance à la baisse» indiquant qu’il y a aucune raison de quitter le trade quand nous nous retrouvons dans une tendance forte selon me fameuse règle «la tendance est ton ami».

De plus, on m'a conseillé sur le forum Heaton Research d'utiliser l 'ATR pour déplacer les stop loss, j'ai donc utilisé l'indicateur Chandelier ATR que j'ai trouvé sur leMQL5 forum Il a en effet augmenté le gain de fonds propres lors de la vérification a posteriori. Je colle le code source de l'Expert Advisor ci-dessous.

//+------------------------------------------------------------------+
//|                                           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]);
              }
           }
        }
     }

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

L'Expert Advisor a été exécuté sur les données USDCHF de la devise D1. Environ 50% des données étaient hors de l'échantillon de la formation.


10. Expert Advisor Résultats du Test Renversé.

Je colle les résultats de la vérification a posteriori ci-dessous. La vérification a posteriori a été exécutée du 2000.01.01 au 2011.03.26.

Figure 8. Résultats de la vérification a posteriori de Neural Expert Advisor

Figure 8. Résultats de la vérification a posteriori de Neural Expert Advisor

Figure 9. Graphique de la  vérification a posteriori solde/fonds propres de Neural Expert Advisor

Figure 9. Graphique de la vérification a posteriori solde/fonds propres de Neural Expert Advisor

Veuillez noter que cette performance peut être totalement différente pour d'autres délais et d'autres titres.

Veuillez considérer cette EA comme une évaluation éducative et en faire un point de départ pour des recherches ultérieures. Mon point de vue personnel est que le réseau pourrait être recyclé à chaque période de temps pour le rendre plus robuste, peut-être que quelqu'un le fera ou a déjà trouvé un bon moyen d'y parvenir. Il existe peut-être un meilleur moyen de faire des prédictions d'achat/vente axées sur un indicateur neuronal. J'encourage les lecteurs à expérimenter.


Conclusion

Dans l'article suivant, j'ai présenté un moyen d’élaborer un indicateur prédictif neuronal et un conseiller expert basé sur cet indicateur à l'aide du cadre d'apprentissage automatique ENCOG. Tout le code source, les binaires compilés, les DLL et un réseau formé exemplaire sont joints à l'article.


En raison du "double emballage de DLL dans .NET", les fichiers Cloo.dll, encog-core-cs.dll and log4net.dlldoivent se trouver dans le dossier du terminal client.
Le fichierEncogNNTrainDLL.dll doit se trouver dans le dossier \Terminal Data\MQL5\Libraries\.


Traduit de l’anglais par MetaQuotes Ltd.
Article original : https://www.mql5.com/en/articles/252

Fichiers joints |
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)
Utilisation de Pseudo-Modèles comme Alternative aux Modèles C++ Utilisation de Pseudo-Modèles comme Alternative aux Modèles C++
L'article décrit une façon de programmer sans utiliser de modèles mais en gardant le style de programmation iherenet pour eux. Il explique l’implémentation de modèles à l'aide de méthodes personnalisées et comporte un script prêt à l'emploi pour créer un code sur la base de modèles indiqués.
Modèle de Régression Universel pour la Prévision des Prix du Marché Modèle de Régression Universel pour la Prévision des Prix du Marché
Le prix du marché est formé à partir d’un équilibre stable entre l’offre et la demande qui, à son tour, dépendent d’une variété de facteurs économiques, politiques et psychologiques. Les différences de nature ainsi que les causes d’influence de ces facteurs rendent difficile la prise en compte directe de tous les composants. Cet article présente une tentative de prédire le prix du marché sur la base d’un modèle de régression élaboré.
Le Rôle des Distributions Statistiques dans le Travail des Traders Le Rôle des Distributions Statistiques dans le Travail des Traders
Cet article est la suite logique de mon article Statistical Probability Distributions en MQL5 qui présente les classes pour travailler avec certaines distributions statistiques théoriques. Maintenant que nous disposons d'une base théorique, je suggère que nous procédions directement à des ensembles de données réelles et que nous essayions de faire un usage informatif de cette base.
Exposer le code C# à MQL5 à l'aide d'exportations non gérées Exposer le code C# à MQL5 à l'aide d'exportations non gérées
Dans cet article, j'ai présenté différentes méthodes d'interaction entre le code MQL5 et le code C# géré. J'ai également fourni plusieurs exemples sur la façon de rassembler des structures MQL5 contre C# et d'appeler des fonctions DLL exportées dans des scripts MQL5. Je pense que les exemples fournis peuvent servir de base à de futures recherches sur l'écriture de DLL en code géré. Cet article ouvre également la porte à MetaTrader pour utiliser de nombreuses bibliothèques déjà implémentées en C#.