English Русский 中文 Español Deutsch 日本語 Português 한국어 Italiano Türkçe
Interaction MetaTrader 5 et MATLAB

Interaction MetaTrader 5 et MATLAB

MetaTrader 5Exemples | 15 novembre 2021, 15:36
316 0
Andrey Emelyanov
Andrey Emelyanov

Introduction

Mon premier article Interaction entre MetaTrader 4 et MATLAB Engine (Virtual MATLAB Machine) a été remarqué par la communauté MQL. Certains lecteurs (1Q2W3E4R5T) ont même pu déplacer ce projet de Borland vers VS2008. Mais le temps passe inexorablement et (triste mais vrai) MetaTrader 4 est en train de disparaître, laissant la place à son successeur MetaTrader 5 avec MQL5, qui a introduit des pointeurs et une mémoire dynamique. 

Grâce à ces innovations, nous avons la possibilité de rédiger une bibliothèque universelle d'interaction avec la machine virtuelle MATLAB Engine, et de lier directement des bibliothèques, générées par MATLAB, avec MetaTrader 5. Cet article couvre une telle fonctionnalité. Cet article poursuit logiquement le précédent et aborde plus en détail le problème d'interaction entre MetaTrader 5 et MATLAB.

Pour rendre la portée de cet article plus compréhensible pour les lecteurs non préparés, nous le diviserons en trois parties : théorie, référence et pratique. La théorie couvrira les types de données utilisées dans MQL5 et MATLAB, ainsi que leur conversion mutuelle. Dans Référence, vous apprendrez les structures linguistiques et la syntaxe des fonctions, nécessaires pour créer une DLL. Et en pratique nous analyserons les « écueils » de cette interaction.

Les lecteurs expérimentés peuvent ignorer la Théorie et la Référence et commencer par la pratique. D'autres sont invités à lire la Théorie et la Référence, et ensuite seulement à passer à la pratique. Il vaut également la peine de lire les livres mentionnés dans la section "Documentation".

1. Théorie

1.1 Types de données dans MATLAB et MQL5

1.1.1 Types de Données Simples

Continuons.

Tout d'abord, nous devons nous familiariser avec les mondes intérieurs de MQL5 et MATLAB. Après inspection superficielle des types de variables, nous concluons qu'ils sont presque identiques :

MQL5
Taille en Octets
Valeur minimale
Valeur maximale
 MATLAB
char
1
-128
127
Tableau int8/char
uchar
1
0
255
Tableau int8/char
bool
1
0 (faux)
1 (vrai)
Tableau logique
Court
2
-32768
32767
Tableau int16
ushort
2
0
65535
Tableau int16
int
4
-2147483648
2147483647
Tableau int32
uint
4
0
4294967295
Tableau int32
long 8
-9223372036854775808
9223372036854775807 Tableau int64
ulong 8
0
18446744073709551615
Tableau int64
flotter 4
1.175494351e-38
3.402823466e+38
Tableau unique
double
8
2.225073858507201e-308
1.7976931348623158e+308
Tableau double

Tableau 1. Types de Données dans MATLAB et MQL5

Il y a une différence majeure : les variables dans MQL5 peuvent être simples ou composites (complexes), et dans MATLAB toutes les variables sont multidimensionnelles (complexes) - c'est-à-dire matricielles. Vous devez toujours vous rappeler de cette différence!

1.1.2 Types de Données Complexes

Dans MQL5, il existe 4 types complexes de données : les tableaux, les chaînes, les structures et les classes. Le type de données complexes est un ensemble de plusieurs types de données simples, combinés en un bloc de mémoire d'une certaine longueur. Lorsque vous traitez de telles données, vous devez toujours connaître soit la taille du bloc mémoire en octets, soit le nombre d'éléments (à l'exception des classes). Nous ne nous intéressons qu'aux tableaux et aux chaînes, car soumettre des classes et des structures MQL5 à MATLAB n'a aucun sens.

Lorsque vous passez des tableaux de tout type, vous devez connaître : le type (dimension) et le nombre d'éléments à l'aide de la fonction ArraySize(). Une attention particulière doit être accordée à l'indexation dans MetaTrader 5 - généralement c'est à l'envers (c'est-à-dire que le premier élément comporte des données plus récentes que le suivant). Vérifiez cela à l'aide de la fonction ArrayIsSeries(). Et MATLAB dispose de l'indexation suivante : le premier élément comporte les données les plus anciennes que le suivant - vous devez donc "inverser" vos tableaux avant de les envoyer à MATLAB, si le drapeau AS_SERIES = TRUE. Sur la base de ce qui précède, convenons-nous à ce qui suit :

  • Les tableaux « inversés » « invisiblement » vers les programmes MQL5, à l'exception des tableaux de type char et des tableaux à 2 dimensions - laissez-les inchangés.
  • Inversez "invisiblement" tous les tableaux de MATLAB et attribuez le drapeau AS_SERIES avec TRUE, à l'exception des tableaux de type char et des tableaux à 2 dimensions - laissez-les inchangés.
  • Dans chaque tableau du programme MQL5, créé selon une indexation "en arrière", l'indicateur AS_SERIES doit être TRUE, à l'exception des tableaux de type char et des tableaux à 2 dimensions - laissez-les inchangés.  

Mais ce n'est pas la seule limitation lorsque vous travaillez avec des tableaux. Lorsque vous travaillez avec des tableaux multidimensionnels, ou des matrices pour être plus corrects, en particulier à partir de MATLAB, nous introduisons la restriction pour les tableaux à 2 dimensions maximum. Ici, l'indicateur AS_SERIES ne peut pas être TRUE, et donc de tels tableaux ne sont pas "inversés".

N'oubliez pas que les chaînes dans MQL5 ne sont pas des tableaux d'éléments de type char. Ainsi, lors de la transmission de chaînes, un léger problème intervient : dans les chaînes MQL5 encodées à l'aide d'Unicode, et MATLAB utilise l'encodage ANSI. Ainsi, avant de passer une chaîne, elle doit être convertie en tableau de caractères ANSI à l'aide de la fonction StringToCharArray(). Et vice versa, lorsque vous obtenez un tableau de caractères de MATLAB, convertissez-le à l'aide de la fonction CharArrayToString() (voir Tableau 2). Pour éviter toute confusion, acceptez : stockez toutes les chaînes dans les programmes MQL5 en utilisant Unicode, pas de tableaux du type char.

1.2 Comparaison des types de données MQL5 et MATLAB

Afin de réduire la quantité de fonctions et de simplifier l'algorithme de la bibliothèque, nous réduirons la quantité de types au moyen d'une conversion automatique, qui ne devrait pas affecter l'intégrité des données. Le tableau suivant illustre la règle de conversion des types de données de MQL5 vers MATLAB :

 MQL5 
MatLab équivalant
char 
uchar
Tableau de caractères
bool
Tableau logique
Court
ushort
int
uint
Tableau int32
long
ulong
Tableau int64*
flotter
double
Tableau double
string
Array char, en utilisant les fonctions StringToCharArray() <=> CharArrayToString()

* Avec ce type de conversion, il y a une perte de précision. Nous ne l'utiliserons pas, mais vous pouvez utiliser une telle conversion dans vos programmes.

Tableau 2. Comparaison des types de données MQL5 et MATLAB

Vous êtes maintenant familiarisé avec les types de données utilisés dans MQL5 et MATLAB. Vous savez quels « écueils » vous attendent dans la transmission de données et comment les contourner avec compétence. Encore faut-il connaître l'API MATLAB Engine et se familiariser avec MATLAB Compiler 4.

2. Référence de l'API MATLAB Engine, référence du compilateur MATLAB 4 et référence de la bibliothèque d'entrée/sortie C++

Cette section vous présente les fonctions les plus importantes de l'API MATLAB Engine, les fonctionnalités de MATLAB Compiler 4 et le nombre de fonctions utiles de la bibliothèque d'entrée/sortie standard C++. Alors, commençons.

2.1 Fonctions API et MCR du moteur MATLAB

MATLAB Engine - est une interface externe qui permet à d'autres programmes d'utiliser le bureau MATLAB. Il fournit un travail entièrement pratique de tous les packages MATLAB sans aucune restriction.

Bien que cela ne soit pas dit dans la documentation, mais en termes de programmeur système - c'est juste une machine virtuelle, comme PHP, MySQL, etc. qui prend en charge un moyen simple et relativement rapide d'échanger des données entre MetaTrader 4/5 et MATLAB.  

Cette méthode de connexion de programmes externes avec le package MATLAB est recommandée par les développeurs. L'interface se compose de six fonctions :

Engine *pEng = engOpen(NULL) — cette fonction appelle le bureau MATLAB, le paramètre est toujours NULL, renvoie un pointeur vers le descripteur du bureau.

int exitCode = engClose(Engine *pEng) — cette fonction ferme le bureau, renvoie le nombre d'utilisateurs restants du bureau MATLAB, où :

  • Engine *pEng — pointeur vers le descripteur de bureau.  

mxArray *mxVector = mxCreateDoubleMatrix(int m, int n, int ComplexFlag) — cette fonction crée une variable (matrice) du bureau MATLAB, renvoie un pointeur vers la variable (matrice), où :

  • mxArray *mxVector — pointeur vers la variable matricielle.  
  • int m — nombre de lignes.  
  • int n — nombre de colonnes.  
  • ComplexFlag — type de nombre complexe, pour MetaTrader 4/5 mxREAL.
void = mxDestroyArray(mxArray * mxVector) - cette fonction détruit la matrice MATLAB, elle est nécessaire pour effacer la mémoire, où :
  • mxArray *mxVector — pointeur vers la variable matricielle.  
int = engPutVariable(Engine *pEng, char *Name, mxArray *mxVector) — cette fonction envoie la variable au bureau. Vous devez non seulement créer des variables de type mxArray, mais aussi les envoyer à MATLAB, où :
  • Engine *pEng — pointeur vers le descripteur de bureau.  
  • char *Name — nom de variable du type char dans le bureau MATLAB.  
  • mxArray *mxVector — pointeur vers la variable matricielle.  
mxArray *mxVector = engGetVariable(Engine *pEng, char *Name) - cette fonction obtient la variable du bureau - l'inverse de la fonction précédente. Seules les variables de type mxArray sont acceptées, où :
  • mxArray *mxVector — pointeur vers la variable matricielle.  
  • Engine *pEng — pointeur vers le descripteur de bureau.  
  • char *Name — nom de variable du type char dans le bureau MATLAB.  
double *p = mxGetPr(mxArray *mxVector) — cette fonction obtient un pointeur vers un tableau de valeurs, elle est utilisée pour copier des données avec memcpy() (voir 2.3 Bibliothèque d'entrée/sortie standard C++), où :
  • double *p — pointeur vers un tableau du type double.  
  • mxArray *mxVector — pointeur vers la variable matricielle.  
int = engEvalString(Engine *pEng, char *Command) — cette fonction envoie des commandes au bureau MATLAB, où :
  • Engine *pEng — pointeur vers le descripteur de bureau.  
  • char *Command — commande pour MATLAB, chaîne du type char.  

Vous avez probablement remarqué que l'API MATLAB Engine vous permet de créer une structure mxArray uniquement pour le type double. Mais cette restriction n'affecte pas vos possibilités, mais affectera l'algorithme de votre bibliothèque.

MCR (instance MCR) — est la bibliothèque spéciale du package MATLAB, qui permet d'exécuter des applications autonomes/bibliothèques publiques, générées par l'environnement MATLAB sur n'importe quel ordinateur. Notez que même si vous disposez d'un package MATLAB complet, vous devez toujours installer la bibliothèque MCR en exécutant le fichier MCRInstaller.exe, situé dans le dossier <MATLAB>\Toolbox\compiler\deploy\win32. Ainsi, avant d'appeler une fonction de bibliothèque publique, créée par l'environnement MATLAB, vous devez appeler la fonction d'initialisation MCR :
 
bool = mclInitializeApplication(const char **option, int count) – renvoie TRUE si le démarrage MCR a réussi, sinon FALSE, où :

  • const char **option — chaîne d'options, comme dans mcc - R; est généralement NULL  
  • int count — chaîne d'options de taille, généralement 0.

À la fin des travaux de la bibliothèque publique, vous devez appeler :
bool = mclTerminateApplication(void) — renvoie TRUE si MCR a été fermé avec succès.

2.2 Compilateur MATLAB 4

Le compilateur MATLAB vous permet de créer les éléments suivants à partir des fonctions M :  

  • Des applications autonomes qui s'exécutent même si MATLAB n'est pas installé.
  • Bibliothèques de partage C/C++, qui peuvent être utilisées sans MATLAB sur les systèmes des utilisateurs finaux.

Le compilateur prend en charge la plupart des commandes et des packages de MATLAB, mais pas toutes. La liste complète des restrictions est disponible sur le site Web de MATLAB. Cette méthode vous permet de créer un «un ensemble indépendant du logiciel » de MetaTrader 5 et MATLAB, mais contrairement au moteur MATLAB, nécessite un programmeur bien formé et une connaissance approfondie de la compilation.

Le compilateur MATLAB requiert au moins l'un des compilateurs C/C++ suivants :

  • Lcc C (fourni généralement avec MATLAB). C'est seulement un compilateur C.  
  • Borland C++ versions 5.3, 5.4, 5.5, 5.6.
  • Microsoft Visual C/C++ versions 6.0, 7.0, 7.1.

MATLAB Compiler 4, contrairement à ses prédécesseurs, ne génère que le code d'interface (bande), c'est-à-dire qu'il ne traduit pas les fonctions m en code binaire ou C/C++, mais il crée un fichier spécial basé sur la technologie Component Technology File (CTF), qui comprend les intégrations de divers packages, nécessaires pour prendre en charge les fonctions m. Le compilateur MATLAB crypte également ce fichier avec une clé unique (non répétée) de 1024 bits.

Examinons maintenant l'algorithme du travail de MATLAB Compiler 4, car l'ignorance de ce sujet entraînera de nombreuses erreurs stupides au moment de la compilation :

  1. Analyse des dépendances — à ce stade, déterminez toutes les fonctions, fichiers MEX et fichiers P, dont dépendent les fonctions m compilées.  
  2. Création de l'archive - Le fichier CTF est créé, il est crypté et compressé.  
  3. Génération du code objet de la bande - à ce stade, tous les codes sources sont créés, nécessaires pour le composant :
    • Code d'interface C/C++ pour les fonctions m indiquées dans la ligne de commande (NomFichier_main.c).
    • Fichier de composants (NameFile_component.dat), qui comporte toutes les informations nécessaires à l'exécution du m-code (y compris les clés et les chemins de cryptage, stockés dans le fichier CTF).  
  4. C/C++ traduction A ce stade, les fichiers de code source C/C++ sont compilés en fichiers objets.
  5. Mise en relation. La dernière étape de la construction du projet.

Maintenant, lorsque vous êtes familiarisé avec le comportement de l'algorithme du compilateur MATLAB, vous devez en savoir plus sur les clés afin d'avoir un plan d'actions détaillé, lors de l'utilisation du compilateur (mcc) :   

Clé
But
    un nom de fichier
 Ajoutez le fichier <filename> à archiver, déterminez quels fichiers seront ajoutés à l'archive CTF
     l
 Macro, qui génère une bibliothèque de fonctions
    N
 Effacer tous les chemins, à l'exception de l'ensemble minimal de répertoires nécessaire
    p <répertoire>
 Ajouter le chemin de traduction selon la procédure. Nécessite la touche -N.
    R -nojvm
 Annuler l'option MCR (MATLAB Component Runtime, voir l'aide MATLAB)
    W
 Gérer la création de fonction de bandes
    lib
 Créer des fonctions d'initialisation et d'achèvement
    Principal
 Créer un shell POSIX de la fonction principale()
    T
 Indiquez l’étape de sortie
    codegen
 Créer un code emballeur pour une application autonome
    compiler:exe
 Identique à codegen
    compile:lib
 Créer un code emballeur pour la DLL publique
    link:exe
 Identique à compile:exe plus liaison
    link:lib
 Identique à compile:exe plus liaison

Tableau 3. Clés du compilateur Matlab mcc (version 4)

Le tableau 3 comporte des clés de base qui peuvent être utiles dans la résolution des problèmes typiques. Pour plus d'aide, utilisez les commandes MATLAB help mcc ou doc mcc.

Nous devons nous familiariser avec l'éditeur de liens MATLAB, voici les clés principales (mbuild):

 Clé
But
 -Définir
 En mode interactif, définition du fichier d'options du compilateur à utiliser par défaut dans les futurs appels de mbuild
 -g
 Créer un programme avec des informations de débogage. Ajoutez DEBUGFLAGS à la fin du fichier.
 -O
 Optimisation du code objet

Tableau 4. Clés Matlab mbuild Linker (version 4)

Le tableau 4 répertorie les clés principales. Pour plus d'informations, utilisez les commandes help mbuild ou doc mbuild.

2.3 Bibliothèque d'entrée/sortie standard C++

L'utilisation de la bibliothèque d'entrée/sortie standard permet de copier correctement les données. Son utilisation vous évitera des erreurs « stupides » qui surviennent lors de la phase de conception du programme (par exemple : de nombreux programmeurs novices ne copient que le pointeur vers le bloc mémoire au lieu de copier l'intégralité du bloc mémoire). De toute la bibliothèque d'entrée/sortie, nous ne sommes intéressés que par une seule fonction :

void *pIn = memcpy(void *pIn, void *pOut, int nSizeByte) - cette fonction copie (clone) la variable/le tableau de pOut à pIn avec une taille d'octets nSizeByte, où :

  • void *pIn — pointeur vers le tableau, où copier.  
  • void *pOut — pointeur vers le tableau, à partir duquel la copie est effectuée.  
  • int nSizeByte — la taille des données copiées, ne doit pas dépasser la taille du tableau pIn, sinon une erreur d'accès à la mémoire se produira.  

3. S'entraîner

Nous en avons maintenant terminé avec la théorie et nous pouvons procéder à la réalisation de l'interaction MetaTrader 5 & MATLAB.

Comme vous l'avez probablement deviné, cela se fera de deux manières : en utilisant la machine virtuelle MATLAB Engine et en utilisant les bibliothèques générées par le compilateur MATLAB. Tout d'abord, envisagez un moyen d'interaction simple, rapide et polyvalent — via MATLAB Engine.

Cette partie de l'article doit être lue du début à la fin, car, malgré la différence apparente entre les méthodes d'interaction, elles ont une philosophie et une syntaxe familière des constructions linguistiques, et apprendre quelque chose de nouveau est plus facile avec des exemples simples.

3.1 Élaboration d'une bibliothèque universelle d'interaction avec le moteur MetaTrader 5 et MATLAB

Cette méthode d'interaction ne peut pas être qualifiée d'élégante et de rapide, mais elle est la plus fiable et couvre l'ensemble du package MATLAB. Bien sûr, nous devons mentionner la vitesse d’élaboration du modèle final. L'essence du développement est d'écrire un bande de bibliothèque universel pour l'interaction MetaTrader 4/5 & MATLAB Engine. Après ce script/indicateur/expert MetaTrader 4/5 peut gérer le bureau virtuel MATLAB. Et l'ensemble de l'algorithme mathématique peut être stocké dans le programme MQL sous forme de chaînes, vous pouvez donc l'utiliser pour protéger votre propriété intellectuelle (pour plus de détails, consultez l'article « Protégez-vous, développeurs ! »). Il peut également être stocké dans des fichiers séparés de fonctions m ou de fonctions P dans le dossier <MetaTrader 5>\MQL5\Libraries.  

Champs d'application possibles d'une telle interaction :

  • Pour tester ou démontrer des "modèles/idées mathématiques" sans avoir à écrire des programmes complexes (la protection de la propriété intellectuelle peut être organisée comme dans le programme MQL et au moyen du package MATLAB - en utilisant les fonctions P).  
  • Rédiger des modèles mathématiques complexes en utilisant toutes les fonctionnalités de MATLAB.
  • A tous ceux qui ne vont pas distribuer leurs scripts/indicateurs/experts.

Continuons. J'espère que vous avez lu les types de données 1.1 dans MATLAB et MQL5, 1.2 Comparaison des types de données MQL5 et MATLAB, 2.1 MATLAB Engine API et MCR Functions et 2.3 C++ Standard Input/Output Library, car nous ne ferons plus de pause et ne les analyserons plus . Lisez attentivement le schéma de blocs suivant, qui illustre l'algorithme de la future bibliothèque :  

Figure 1. Schéma de blocs de l'algorithme de bibliothèque

Figure 1. Schéma de blocs de l'algorithme de bibliothèque

Comme on le constate sur la figure 1, la bibliothèque se compose de trois blocs principaux. Examinons leurs objectifs :

  • Bloc MQL5, préparation préalable des données envoyées/reçues :  
    • Tableaux inversés.
    • Conversion de types.
    • Conversion des encodages de chaînes.
  • Bloc C/C++ :
    • Convertit le tableau dans la structure mxArray.
    • Passe les commandes du moteur MATLAB.
  • Bloc moteur MATLAB — système de calculs.  

Passons maintenant aux algorithmes. Nous allons commencer par le bloc MQL5. Le lecteur attentif a déjà remarqué qu'il se concentrera sur l’implémentation de ce qu’a été rédigé dans la section Types de données dans MATLAB et MQL5. Si vous l'avez manqué, vous comprendrez à peine pourquoi tout cela est nécessaire.

L'algorithme des fonctions mlInput <variable_type> est presque identique. Discutons de son travail à l'aide de la fonction mlInputDouble() qui fournit une entrée de variables de type double à la machine virtuelle MATLAB.

Voici le prototype :

bool mlInputDouble(double &array[],int sizeArray, string NameArray), où :

  • array — référence à une variable ou à un tableau de type double.
  • sizeArray — taille du tableau (nombre d'éléments, pas d'octets !). 
  • NameArray — chaîne comportant un nom de variable unique pour la machine virtuelle MATLAB (le nom doit correspondre aux exigences MATLAB).

Algorithme:

  1. Convertissez la chaîne NameArray en tableau de caractères à l'aide de la fonction StringToCharArray().
  2. Vérifiezle type d'indexation à l'aide de la fonction ArrayIsSeries(). Si le type d'indexation est normal, transmettez la valeur à la fonction mlxInputDouble().
    Indexation ELSE du tableau de séries temporelles : tableau
    "inverse" et passer la valeur à la fonction mlxInputDouble().
  3. End function, passez la valeur renvoyée à la fonction mlxInputDouble().

L'algorithme des fonctions mlGet <variable_type> est également presque identique. Discutons de son travail à l'aide de la fonction mlGetDouble(), qui renvoie une variable de type double à partir de la machine virtuelle MATLAB.

Le Prototype:

int mlGetDouble(double &array[],int sizeArray, string NameArray), où :

  • array — référence à une variable ou à un tableau de type double.
  • sizeArray — taille du tableau (nombre d'éléments, pas d'octets !). 
  • NameArray — chaîne contenant un nom de variable unique pour la machine virtuelle MATLAB.

Algorithme:

  1. ConvertissezNameArray string vers char array à l’aide de la fonction StringToCharArray()   
  2. Trouvez la taille du tableau à l'aide de la fonction mlxGetSizeOfName().
    • SIla taille est SUPÉRIEURE À ZÉRO, attribuez le tableau destinataire de la taille nécessaire à l'aide de la fonction ArrayResize(), obtenez les données de mlxGetDouble(), retournez la taille du tableau.
    • SIla taille est ZÉRO, renvoie une erreur, c'est-à-dire une valeur nulle.  

C'est ça! Les fonctions mlGetInt() et mlGetLogical() produisent une conversion "ombre" des types double ->; int/bool. À cette fin, ces fonctions créent une mémoire tampon temporaire dans leur corps. Il s'agit d'une mesure forcée, car malheureusement l'API MATLAB ne permet pas de créer des structures mxArray pour des types de données autres que double. Cependant, cela ne signifie pas que MATLAB exploite exclusivement les typesdoubles .

Le bloc C/C++ est beaucoup plus simple - il devrait fournir une traduction des données du type double dans la structure mxArray. Cela se fait à l’aide de mxCreateDoubleMatrix(), mxGetPr() et les fonctionsmemcpy() Ensuite, à l'aide de la fonction engPutVariable(), il transmet les données à la machine virtuelle MATLAB et pour extraire les données, il utilise la fonction engGetVariable() Encore une fois, faites attention aux fonctions avec les préfixes Int et Logical- comme on le voit dans le schéma de blocs, elles n'interagissent pas directement avec MATLAB, mais utilisent les fonctions mlxInputDouble/mlxGetDouble et mlxInputChar() Algorithme de leur comportement est simple: Appel de la fonction mlxInputDouble/mlxGetDouble — Valeurs d’entrée/sortie en doubles(!) et envoyer un commande «ombre» de MATLAB pour convertir les données à travers la fonction mlxInputChar()

Le bloc moteur MATLAB est encore plus simple. Il ne fournit que des fonctions mathématiques. Son comportement dépend de vos commandes et de vos fonctions m/p.  

Maintenant, lorsque tous les "détails" du projet sont clairs, il est temps de s'occuper de la construction du projet.

Toute construction commence par la création de la bibliothèque principale - dans notre cas, il s'agit d'un bloc C/C++. À cette fin, dans n'importe quel éditeur de texte ANSI (Notepad, Bred, etc.), créez un fichier avec l'extension DEF. Il est souhaitable que le nom de ce fichier soit composé de caractères latins sans espaces ni ponctuation, sinon vous "entendrez" de nombreux "mots" flatteurs de votre compilateur... Ce fichier assure la pérennité de vos fonctions. Si ce fichier est absent, le compilateur C/C++ inventera ses propres "noms exotiques" pour exporter des fonctions.

Ce fichier comporte : LIBRARY— mot de contrôle, LibMlEngine — nom de la bibliothèque et EXPORTS — deuxième mot de contrôle, puis viennent les noms des fonctions. Comme vous le savez probablement, les noms des fonctions d'exportation ne peuvent pas comporter d'espaces ni de ponctuation. Voici le texte du fichier DllUnit.def de l'archive MATLABEngine.zip :  

BIBLIOTHÈQUE LibMlEngine
EXPORTATIONS
mlxClose
mlxInputChar
mlxInputDouble
mlxInputInt
mlxInputLogical
mlxGetDouble
mlxGetInt
mlxGetLogical
mlxGetSizeOfName
mlxOpen

Donc, nous avons le premier fichier de projet. Ouvrez maintenant l'Explorateur Windows et accédez au dossier '<MATLAB>\Extern\include'. Copiez le fichier engine.h (fichier d'en-tête de la machine virtuelle MATLAB) dans le dossier où votre projet est construit (si vous ne le faites pas, vous devrez indiquer manuellement le chemin d'accès au fichier au stade de la compilation).

Il est maintenant temps de créer le bloc C/C++. Nous n'inclurons pas l'intégralité du code source du programme dans l'article, car ce fichier se trouve dans MATLABEngine.zip sous le nom DllUnit.cpp et il est bien commenté. Notez qu'il est préférable de créer des fonctions en utilisant la convention __stdcall — c'est-à-dire que les paramètres sont passés à travers la pile et que la fonction nettoie la pile. Cette norme est "native" pour l'API Win32/64.

Observez comment déclarer une fonction :

extern "C" __declspec(dllexport) <variable_type> __stdcall Function(<type> <name>)

  1. extern "C" __declspec(dllexport) — indique au compilateur C++ que la fonction est externe.  
  2. <variable_type> — type de variable renvoyée, peut être : void, bool, int, double, types composites (connus non seulement de Dll, mais aussi du programme appelant) et des pointeurs.
  3.  __stdcall —déclaration sur le passage des paramètres à la fonction et inversement, c'est un standard pour l'API Win32/64.  
  4. Funcion — le nom de votre fonction.  
  5. <type> <name> — type et nom de la variable d'entrée, le nombre maximal de variables est de 64.

Ce sujet est traité en détail dans Comment échanger des données : Un article DLL pour MQL5 en 10 minutes.

Construction de blocs C/C++ : pour cela, vous devez inclure la bibliothèque d'entrées/sorties standard et ajouter au projet les fichiers suivants (dans votre compilateur : Projet->Ajouter un projet) :

  1. DllUnit.def
  2. Dans le dossier <MATLAB>\Extern\lib\<win32/64>\<compiler>\, où :
    <MATLAB> — Dossier principal MATLAB.
    <win32/64> — soit le dossier win32 pour le système d'exploitation 32 bits, soit win64 pour le système d'exploitation 64 bits.
    <compilateur> — le dossier "borland" pour Borland C/C++ ver. 5-6, le dossier "microsoft" pour Microsoft Visual C++ :  
    • libeng.lib
    • libmx.lib

Une question courante comme celle-ci peut se poser : "J'ai une version différente du compilateur ou aucun compilateur de ce type dans la liste ! (Très rarement, il n'y a pas de tels fichiers)". Voyons comment créer manuellement une bibliothèque publique. Nous verrons comment cela se fait en Visual C++ et en Borland C++ :

  1. Dans FAR, ouvrez le dossier <MATLAB>\Bin\<win32/64>, où :
    <MATLAB> — Dossier principal MATLAB.
    <win32/64> — soit le dossier win32 pour le système d'exploitation 32 bits, soit win64 pour le système d'exploitation 64 bits.  
  2. Pour Borland C++, entrez : implib libeng.lib libeng.dll. Idem pour libmx.dll.
  3. Pour Visual C++, entrez : lib libeng.dll. Idem pour libmx.dll.
  4. Si autre compilateur: tout compilateur de tout langage de programmation doit disposer de cet utilitaire - Library Manager, il s'agit généralement d'un programme console <compiler_folder>\bin\*lib*.exe.

Au fait, j'ai oublié de vous avertir - n'essayez pas de créer une LIB 64 bits pour un compilateur 32 bits. Tout d'abord, découvrez s'il existe une prise en charge de l'adressage 64 bits dans l'aide du compilateur. Sinon, recherchez une DLL MATLAB 32 bits ou choisissez un autre compilateur C/C++. Passons à la compilation, après quoi nous obtenons une bibliothèque, qui devrait être placée dans le dossier terminal_folder\MQL5\Libraries.

Commençons maintenant par le bloc MQL. Exécutez MetaEditor, cliquez sur "Nouveau" et procédez comme sur les figures suivantes :  

Figure 2. MQL5 Assistant: Créez une Bibliothèque

Figure 2. Assistant MQL5 : Créez une bibliothèque

Figure 3. Assistant MQL5 : Propriétés générales de la bibliothèque

Figure 3. Assistant MQL5 : Propriétés Générales de la Bibliothèque

Maintenant, lorsque Wizard MQL5 a créé un modèle, procédez à son édition :

1. Décrivez les fonctions d'importation :

//+------------------------------------------------------------------+
//| DECLARATION OF IMPORTED FUNCTIONS                                 |
//+------------------------------------------------------------------+
#import "LibMlEngine.dll"
void   mlxClose(void);                        //void – means: don't pass any parameters!
bool   mlxOpen(void);                         //void – means: don't pass and don't receive any parameters!
bool   mlxInputChar(char &CharArray[]);       //char& CharArray[] – means: pass a reference!
bool   mlxInputDouble(double &dArray[],
                      int sizeArray,
                      char &CharNameArray[]);
bool   mlxInputInt(double &dArray[],
                   int sizeArray,
                   char &CharNameArray[]);
bool   mlxInputLogical(double &dArray[],
                       int sizeArray,
                       char &CharNameArray[]);
int    mlxGetDouble(double &dArray[],
                    int sizeArray,
                    char &CharNameArray[]);
int    mlxGetInt(double &dArray[],
                 int sizeArray,
                 char &CharNameArray[]);
int    mlxGetLogical(double &dArray[],
                     int sizeArray,
                     char &CharNameArray[]);
int    mlxGetSizeOfName(char &CharNameArray[]);
#import    

Notez que MQL 5 vous permet de passer des "pointeurs" de deux manières :

  • void NameArray[] ;   // Cette méthode de passage depuis un tableau permet uniquement de lire des données. Cependant, si vous essayez d'utiliser cette référence pour "éditer son contenu", vous obtiendrez une erreur d'accès à la mémoire (dans le meilleur des cas pour vous, MetaTrader 5 gérera discrètement l'erreur dans le cadre SEH, mais nous N'AVONS PAS ÉCRIT une trame SEH, de sorte que nous puissions même manquer la raison de l'erreur).
  • void& NameArray[] ; // Cette méthode de transmission vous permet de lire et de modifier les contenus du tableau, mais vous devez conserver la taille du tableau.

Si la fonction n'accepte pas ou ne passe pas de paramètres, indiquez toujours le type void.

2. Nous ne décrirons pas toutes les fonctions du bloc MQL, car vous pouvez trouver le code source MatlabEngine.mq5 dans MATLABEngine.zip.

Par conséquent, nous allons examiner les détails de la déclaration et de la définition des fonctions externes dans MQL5 :

bool mlInputChar(string array)export
{
//... body of function
}

Comme on le voit dans l'exemple, la déclaration et la définition de fonction sont combinées. Dans ce cas, nous déclarons une fonction nommée mlInputChar() comme externe (export), qui renvoie une valeur de type bool et accepte laarray chaîne de tableau en paramètre. Maintenant, compilez...

Maintenant que nous avons terminé le dernier bloc de la bibliothèque et l'avons compilé, il est temps de le tester en conditions réelles.

Pour se faire, rédigez un script de test simple (ou prenez-le dans MATLABEngine.zip, fichier : TestMLEngine.mq5).

Le code du script est simple et bien commenté :

#property copyright "2010, MetaQuotes Software Corp."
#property link      "https://www.mql5.com/ru"
#property version   "1.00"
#import "MatlabEngine.ex5"
bool mlOpen(void);
void mlClose(void);
bool mlInputChar(string array);
bool mlInputDouble(double &array[],
                   int sizeArray,
                   string NameArray);
bool mlInputInt(int &array[],
                int sizeArray,
                string NameArray);
int mlGetDouble(double &array[],
                string NameArray);
int mlGetInt(int &array[],
             string NameArray);
bool mlInputLogical(bool &array[],
                    int sizeArray,
                    string NameArray);
int mlGetLogical(bool &array[],
                 string NameArray);
int mlGetSizeOfName(string strName);
#import
void OnStart()
  {
// Dynamic buffers for MATLAB output
   double dTestOut[];
   int    nTestOut[];
   bool   bTestOut[];
// Variables for MATLAB input
   double dTestIn[] = {   1,     2,    3,     4};
   int    nTestIn[] = {   9,    10,   11,    12};
   bool   bTestIn[] = {true, false, true, false};
   int nSize=0;
// Variables names and command line
   string strComm="clc; clear all;"; // command line - clear screen and variables
   string strA     = "A";            // variable A
   string strB     = "B";            // variable B
   string strC     = "C";            // variable C
/*
   ** 1. RUNNING DLL
   */
   if(mlOpen()==true)
     {
      printf("MATLAB has been loaded");
     }
   else
     {
      printf("Matlab ERROR! Load error.");
      mlClose();
      return;
     }
/*
   ** 2. PASSING THE COMMAND LINE
   */
   if(mlInputChar(strComm)==true)
     {
      printf("Command line has been passed into MATLAB");
     }
   else printf("ERROR! Passing the command line error");
/*
   ** 3. PASSING VARIABLE OF THE DOUBLE TYPE
   */
   if(mlInputDouble(dTestIn,ArraySize(dTestIn),strA)==true)
     {
      printf("Variable of the double type has been passed into MATLAB");
     }
   else printf("ERROR! When passing string of the double type");
/*
   ** 4. GETTING VARIABLE OF THE DOUBLE TYPE
   */
   if((nSize=mlGetDouble(dTestOut,strA))>0)
     {
      int ind=0;
      printf("Variable A of the double type has been got into MATLAB, with size = %i",nSize);
      for(ind=0; ind<nSize; ind++)
        {
         printf("A = %g",dTestOut[ind]);
        }
     }
   else printf("ERROR! Variable of the double type double hasn't ben got");
/*
   ** 5. PASSING VARIABLE OF THE INT TYPE
   */
   if(mlInputInt(nTestIn,ArraySize(nTestIn),strB)==true)
     {
      printf("Variable of the int type has been passed into MATLAB");
     }
   else printf("ERROR! When passing string of the int type");
/*
   ** 6. GETTING VARIABLE OF THE INT TYPE
   */
   if((nSize=mlGetInt(nTestOut,strB))>0)
     {
      int ind=0;
      printf("Variable B of the int type has been got into MATLAB, with size = %i",nSize);
      for(ind=0; ind<nSize; ind++)
        {
         printf("B = %i",nTestOut[ind]);
        }
     }
   else printf("ERROR! Variable of the int type double hasn't ben got");
/*
   ** 7. PASSING VARIABLE OF THE BOOL TYPE
   */
   if(mlInputLogical(bTestIn,ArraySize(bTestIn),strC)==true)
     {
      printf("Variable of the bool type has been passed into MATLAB");
     }
   else printf("ERROR! When passing string of the bool type");
/*
   ** 8. GETTING VARIABLE OF THE BOOL TYPE
   */
   if((nSize=mlGetLogical(bTestOut,strC))>0)
     {
      int ind=0;
      printf("Variable C of the bool type has been got into MATLAB, with size = %i",nSize);
      for(ind=0; ind<nSize; ind++)
        {
         printf("C = %i",bTestOut[ind]);
        }
     }
   else printf("ERROR! Variable of the bool type double hasn't ben got");
/*
   ** 9. ENDING WORK
   */
   mlClose();
  }

Comme on le constate depuis le script, nous entrons des valeurs, puis obtenons des valeurs. Cependant, contrairement à MetaTrader 4, où nous devions connaître la taille du tampon au stade de la conception, dans MetaTrader 5, ce n'est pas nécessaire, car nous utilisons des tampons dynamiques.

Maintenant que vous avez enfin compris la machine virtuelle MATLAB, vous pouvez commencer l’utilisation de la DLL intégrée à l'environnement MATLAB.

3.2 Directives techniques de création/utilisation de DLL générées par MATLAB Compiler 4

Dans la section précédente, vous avez appris à créer une bibliothèque pour une interaction universelle avec le package MATLAB. Cependant, cette méthode a un inconvénient - elle nécessite le package MATLAB de l'utilisateur final. Cette restriction crée un certain nombre de difficultés dans la distribution du produit logiciel fini. C'est pourquoi le package mathématique MATLAB dispose d'un compilateur intégré, qui vous permet de créer des "applications autonomes" indépendantes du package MATLAB. Jetons-y un coup d'œil.

Par exemple, examinons un indicateur simple - la moyenne mobile (SMA). Améliorez-la légèrement en ajoutant un filtre de réseau neuronal (GRNN), qui permet de lisser le "bruit blanc" (rafales aléatoires). Nommez le nouvel indicateur NeoSMA et filtrez GRNNFilter.  

Ainsi, nous avons deux fonctions m, dont nous voulons créer une DLL, qui peuvent être appelées depuis MetaTrader 5.

Rappelez-vous maintenant que MetaTrader 5 recherche les DLL dans les dossiers suivants :

  • <terminal_dir>\MQL5\Libraries  
  • <terminal_dir>  
  • Dossier en cours
  • Dossier système <rép_windows>\SYSTEM32 ;  
  • <windows_dir>  
  • Répertoires répertoriés dans la variable d'environnement système PATH.

Par conséquent, placez dans l'un de ces répertoires deux fonctions m (NeoSMA.m et GRNNFilter.m), où nous construirons la DLL. J'attire votre attention sur ce fait de placement, car cela n'est pas fait par accident. Le lecteur attentif connaît déjà la fonctionnalité du compilateur MATLAB - il préserve les chemins lors de la compilation (voir "2.2 Compilateur MATLAB 4").

  Avant de commencer à compiler le projet, vous devez configurer le compilateur. Pour le faire, suivez ces étapes:   

  1. Dans la ligne de commande MATLAB, entrez : mbuild -setup
  2. Appuyez sur 'y' pour confirmer la recherche des compilateurs compatibles C/C++ installés sur votre système.
  3. Choisissez le compilateur Lcc-win32 C standard.
  4. Appuyez sur 'y' pour confirmer le compilateur sélectionné.

Figure 4. Compilation du projet

Figure 4. Compiler le projet


Nous sommes maintenant prêts à passer au processus de compilation des fonctions m.

Pour cela entrez :

mcc -N -W lib:NeoSMA -T link:lib  NeoSMA.m GRNNFilter.m

Expliquez les clés :

-N - pour ignorer tous les chemins inutiles
-W lib:NeoSMA — indique au compilateur que NeoSMA est le nom de la bibliothèque
-T link:lib — indique au compilateur de créer une bibliothèque publique avec liaison
NeoSMA.m et GRNNFilter.m — noms des fonctions m

Voyons maintenant ce que le compilateur a créé :

  • mccExcludedFiles.log — fichier journal comportant les actions des compilateurs
  • NeoSMA.c — Version C de la bibliothèque (contient le -code du bande)  
  • NeoSMA.ctf — Section du fichier CTF (voir 2.2 MATLAB Compiler 4)  
  • NeoSMA.h — fichier d'en-tête (comporte les déclarations de bibliothèques, fonctions, constantes)  
  • NeoSMA.obj — fichier objet (fichier source comportant la machine et le pseudo-code)  
  • NeoSMA.exports — noms des fonctions exportées  
  • NeoSMA.dll — Dll pour plus de liens  
  • NeoSMA.lib — Dll à utiliser dans les projets C/C++  
  • NeoSMA_mcc_component_data.c — Version C sur le composant (utilisée pour la conformité avec le fichier CTF, comporte des chemins, etc.)  
  • NeoSMA_mcc_component_data.obj — version objet du composant (fichier source comportant la machine et le pseudo-code) ;

Alors manipulons-nous avec DLL, précisément avec sa structure interne. Il se compose (fonctions de base uniquement) de :

  1. Fonction principale de toute DLL - BOOL WINAPI DllMain(), qui (selon la spécification Microsoft) gère les événements se produisant dans la DLL : Chargement de la DLL dans l'espace d'adressage du processus, création d'un nouveau flux, suppression du flux et déchargement de la Dll de la mémoire.  
  2. Fonctions de service d'initialisation/désinitialisation de DLL : BOOL <NameLib>Initialize(void)/void <NameLib>Terminate(void) — sont nécessaires pour démarrer/décharger l'environnement Math Work avant d'utiliser les fonctions de la bibliothèque et à la fin de leur utilisation.
  3. Fonctions m exportées – void mlf<NameMfile>(int <number_of_return_values>, mxArray **<return_values>, mxArray *<input_values>, ...), où :
    • <number_of_return_values> — nombre de variables renvoyées (à ne pas confondre avec la taille du tableau, etc.).
    • mxArray **<return_values> — adresse de la structure mxArray où les résultats du travail de la fonction m seront renvoyés.
    • mxArray *<input_values> — pointeur vers la structure mxArray de la variable d'entrée de la fonction m.
     

Comme vous pouvez le voir, les fonctions m exportées comportent des adresses et des pointeurs vers la structure mxArray, et vous ne pouvez pas appeler directement ces fonctions depuis MetaTrader 5, car il ne comprendra pas ce type de données. Nous ne décrirons pas la structure mxArray dans MetaTrader 5, car les développeurs MATLAB ne garantissent pas qu'elle ne changera pas au fil du temps, même au sein de la même version du produit, vous devez donc écrire un simple adaptateur DLL.

Son schéma de blocs est illustré ci-dessous :

Figure 5. DLL-adaptateur Block-Scheme

Figure 5. DLL-adaptateur Block-Scheme

Il est très similaire au côté droit de la DLL pour MATLAB Engine, nous n'allons donc pas analyser son algorithme et passer directement au code. Pour se faire, créez deux petits fichiers dans votre compilateur C/C++ :  

nSMA.cpp (de DllMatlab.zip) :  

#include <stdio.h>
#include <windows.h>
/* Include MCR header file and library header file */
#include "mclmcr.h"
#include "NEOSMA.h"
/*---------------------------------------------------------------------------
** DLL Global Functions (external)
*/
extern "C" __declspec(dllexport) bool __stdcall IsStartSMA(void);
extern "C" __declspec(dllexport) bool __stdcall nSMA(double *pY,  int  nSizeY,
                                                     double *pIn, int nSizeIn,
                                                     double   dN, double dAd);
/*---------------------------------------------------------------------------
** Global Variables
*/
mxArray *TempY;
mxArray *TempIn;
mxArray *TempN;
mxArray *TempAd;
bool bIsNeoStart;
//---------------------------------------------------------------------------
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
{
    switch(reason)
    {
        case DLL_PROCESS_ATTACH:
         bIsNeoStart = false;
         TempY  = 0;   //Nullify pointers to buffers
         TempN  = 0;
         TempIn = 0;
         TempAd = 0;
         break;
        case DLL_PROCESS_DETACH:
         NEOSMATerminate();
         //Delete old data before exiting from Dll
         if(TempY  != NULL) mxDestroyArray(TempY);
         if(TempN  != NULL) mxDestroyArray(TempN);
         if(TempIn != NULL) mxDestroyArray(TempIn);
         if(TempAd != NULL) mxDestroyArray(TempAd);
         mclTerminateApplication();
    }
    return 1;
}
//---------------------------------------------------------------------------
bool __stdcall IsStartSMA(void)
{
 if(bIsNeoStart == false)
 {
  if(!mclInitializeApplication(NULL,0) )
  {
   MessageBoxA(NULL, (LPSTR)"Can't start MATLAB MCR!",
               (LPSTR) "MATLAB DLL: ERROR!", MB_OK|MB_ICONSTOP);
   return false;
  }else
   {
    bIsNeoStart = NEOSMAInitialize();
   };
 };
 return bIsNeoStart;
}
//---------------------------------------------------------------------------
bool __stdcall nSMA(double *pY, int nSizeY, double *pIn, int nSizeIn, double dN, double dAd)
{
   /*
   ** Create buffers
   */
   if(TempN == NULL){ TempN = mxCreateDoubleMatrix(1, 1, mxREAL);}
   else
   {
     mxDestroyArray(TempN);
     TempN= mxCreateDoubleMatrix(1, 1, mxREAL);
   };
   if(TempIn == NULL){ TempIn = mxCreateDoubleMatrix(1, nSizeIn, mxREAL);}
   else
   {
     mxDestroyArray(TempIn);
     TempIn= mxCreateDoubleMatrix(1, nSizeIn, mxREAL);
   };
   if(TempAd == NULL){ TempAd = mxCreateDoubleMatrix(1, 1, mxREAL);}
   else
   {
     mxDestroyArray(TempAd);
     TempAd= mxCreateDoubleMatrix(1, 1, mxREAL);
   };
   /*
   ** Creating data for processing
   */
   memcpy((char *)mxGetPr(TempIn), (char *) pIn, (nSizeIn)*8);
   memcpy((char *)mxGetPr(TempN), (char *) &dN, 8);
   memcpy((char *)mxGetPr(TempAd), (char *) &dAd, 8);
   /*
   ** Send and receive a response from the m-function
   */
   if(mlfNeoSMA(1, (mxArray **)TempY, (mxArray *)TempIn, (mxArray *)TempN
      , (mxArray *)TempAd) == false) return false;
   /*
   ** Return calculated vector from the m-function and clear buffers
   */
   memcpy((char *) pY, (char *)mxGetPr(TempY), (nSizeY)*8);
   mxDestroyArray((mxArray *)TempY);  TempY  = 0;
   mxDestroyArray((mxArray *)TempN);  TempN  = 0;
   mxDestroyArray((mxArray *)TempIn); TempIn = 0;
   mxDestroyArray((mxArray *)TempAd); TempAd = 0;
   return true;
}

nSMA.def (de DllMatlab.zip) :

BIBLIOTHÈQUE nnSMA
EXPORTATIONS
IsStartSMA
nSMA


Construisez le projet dans votre compilateur C/C++ : pour cela, vous devez inclure la bibliothèque d'entrées/sorties standard et ajouter au projet les fichiers suivants (dans votre compilateur : Projet->Ajouter un projet) :

  1. nSMA.def
  2. Dans le dossier <MATLAB>\Extern\lib\<win32/64>\<compiler>\, où :
    <MATLAB> — Dossier principal MATLAB.
    <win32/64> — soit le dossier win32 pour le système d'exploitation 32 bits, soit win64 pour le système d'exploitation 64 bits.
    <compilateur> — le dossier "borland" pour Borland C/C++ ver. 5-6, le dossier "microsoft" pour Microsoft Visual C++ (j'ai des fichiers pour la version 6) :  
    • libmx.lib
    • mclmcr.lib
  3. NeoSMA.lib — créer manuellement (voir 3.1 Élaboration de la bibliothèque universelle de MetaTrader 5 et de l'interaction avec le moteur MATLAB).  

Le dernier, ce que je souhaite vous dire dans cette section, concerne les fichiers nécessaires lors du déplacement du projet vers un autre ordinateur, sur lequel MATLAB n'est pas installé.

Voici une liste des fichiers et des chemins sur la machine cible :

  • MCRInstaller.exe n'importe quel dossier (installateur MCR)
  • extractCTF.exe n'importe quel dossier (pour l'installateur MCR)
  • MCRRegCOMComponent.exe n'importe quel dossier (pour l'installateur MCR)
  • unzip.exe n'importe quel dossier (pour l'installateur MCR)
  • NeoSMA.dll                           <terminal_dir>\MQL5\Libraries
  • NeoSMA.ctf                           <terminal_dir>\MQL5\Libraries
  • nnSMA.dll                             <terminal_dir>\MQL5\Libraries

De nombreux programmeurs sophistiqués ont déjà deviné qu'il est conseillé d'utiliser un programme d'installation (SETUP). Il y en a beaucoup sur Internet, y compris des produits gratuits.

Nous devons maintenant tester cette DLL dans MetaTrader 5. Pour ce faire, nous allons écrire un script simple (TestDllMatlab.mq5 à partir du DllMatlab.zip) :

#property copyright "2010, MetaQuotes Software Corp."
#property link      "nav_soft@mail.ru"
#property version   "1.00"
#import "nnSMA.dll"
bool  IsStartSMA(void);
bool  nSMA(double &pY[],
           int nSizeY,
           double &pIn[],
           int nSizeIn,
           double dN,
           double dAd);
#import
datetime    Time[];    // dynamic array of time coordinates
double      Price[];   // dynamic array of price
double      dNeoSma[]; // dynamic array of price
void OnStart()
  {
   int ind=0;
// run Dll
   if(IsStartSMA()==true)
     {
      //--- create and fill arrays
      CopyTime(Symbol(),0,0,301,Time);   // time array + 1
      ArraySetAsSeries(Time,true);       // get the time chart
      CopyOpen(Symbol(),0,0,300,Price);  // price array
      ArraySetAsSeries(Price,true);      // get the open prices
      ArrayResize(dNeoSma,300,0);        // reserve space for function response
                                         // get data
      if(nSMA(dNeoSma,300,Price,300,1,2)==false) return;
      // specify array orientation
      ArraySetAsSeries(dNeoSma,true);
      // plot data on chart
      for(ind=0; ind<ArraySize(dNeoSma);ind++)
        {
         DrawPoint(IntegerToString(ind,5,'-'),Time[ind],dNeoSma[ind]);
        }
     }
  }
//+------------------------------------------------------------------+
void DrawPoint(string NamePoint,datetime x,double y)
  {  // 100% ready. Plot data on chart. Drawing using arrows.
// Main properties of chart object
   ObjectCreate(0,NamePoint,OBJ_ARROW,0,0,0);
   ObjectSetInteger(0, NamePoint, OBJPROP_TIME, x);        // time coordinate x
   ObjectSetDouble(0, NamePoint, OBJPROP_PRICE, y);        // price coordinate y
// Additional properties of chart object
   ObjectSetInteger(0, NamePoint, OBJPROP_WIDTH, 0);       // line width
   ObjectSetInteger(0, NamePoint, OBJPROP_ARROWCODE, 173); // arrow type
   ObjectSetInteger(0, NamePoint, OBJPROP_COLOR, Red);     // arrow color
  }
//+------------------------------------------------------------------+

Conclusion

Ainsi, vous savez comment créer une bibliothèque universelle pour l'interaction MetaTrader 5 et MATLAB, et comment connecter la DLL intégrée à l'environnement MATLAB. Mais il reste encore des interfaces d'interaction MetaTrader 5 et MATLAB à décrire, mais cela dépasse le cadre de cet article. Le sujet de cet article est traité en détail. J'ai choisi les modes d'interaction les plus efficaces, ne nécessitant pas un type particulier d'"adaptateurs". Bien que vous puissiez emprunter une "autre voie", telle que la technologie .NET - Comment exporter des cotations de MetaTrader 5 vers des applications .NET à l'aide des services WCF.

De nombreux lecteurs peuvent se poser une question : quelle méthode choisir ? La réponse est simple - les deux, car lors de la conception/débogage du modèle mathématique, la vitesse n'est pas nécessaire. Mais vous aurez besoin de toute la puissance de MATLAB sans « coûts de production spéciaux » pour la programmation. MATLAB Engine vous aidera ici, bien sûr. Cependant, lorsque le modèle mathématique est débogué et prêt à l'emploi, vous aurez besoin de vitesse, de multitâche (travail d'indicateur et/ou de système de trade à plusieurs tableaux de prix) - ici vous aurez sans aucun doute besoin d'une DLL, construite dans l'environnement MATLAB .

Mais tout cela ne vous contraint pas à le suivre. Chacun donnera lui-même la réponse à cette question en s'appuyant principalement sur le rapport « coût de programmation » à l'échelle du projet (nombre d'utilisateurs d'indicateurs et/ou de systèmes de trade). Cela n'a aucun sens de créer des Dll dans l'environnement MATLAB pour un ou deux utilisateurs (il est plus facile d'installer MATLAB sur deux ordinateurs).  

De nombreux lecteurs, qui ne connaissent pas MATLAB, se posent probablement une question : pourquoi tout cela ? MQL5 dispose déjà des fonctions mathématiques ! La réponse est que l'utilisation de MATLAB vous permet de mettre en œuvre sans effort vos idées mathématiques, voici juste une liste partielle des possibilités :  

  • algorithme dynamique de logique floue dans l'indicateur et/ou le système de trade mécanique  
  • algorithme génétique dynamique dans le système de trade mécanique (testeur de stratégie dynamique)
  • algorithme de réseau neuronal dynamique dans l'indicateur et/ou le système de trade mécanique  
  • indicateurs tridimensionnels
  • simulation des systèmes de gestion non linéaires

Alors, tout est entre vos mains, et n'oubliez pas : "Les mathématiques ont toujours été la reine des sciences", et le package MATLAB est votre calculatrice scientifique.

Documentation

  1. Aide intégrée à MATLAB.
  2. Aide intégrée MQL5.
  3. Jeffrey Richter. Programming Applications pour Microsoft Windows.

Traduit du russe par MetaQuotes Ltd.
Article original : https://www.mql5.com/ru/articles/44

Fichiers joints |
dllmatlab_en.zip (955.7 KB)
matlabengine_en.zip (670.57 KB)
Création d'un indicateur avec plusieurs tampons d'indicateurs pour les débutants Création d'un indicateur avec plusieurs tampons d'indicateurs pour les débutants
Les codes complexes sont constitués d’un ensemble de codes simples. Si vous les connaissez, cela n’a pas l’air si compliqué. Dans cet article, nous allons examiner comment créer un indicateur avec plusieurs tampons d’indicateurs. À titre d’exemple, l’indicateur Aroon est analysé en détail et deux versions différentes du code sont présentées.
Création d’un indicateur avec des Options de Contrôle Graphique Création d’un indicateur avec des Options de Contrôle Graphique
Ceux qui sont familiers avec les attitudes du marché, connaissent l’indicateur MACD (son nom complet est Moyenne Mobile de Convergence / Divergence) - l’outil puissant pour analyser le mouvement des prix, utilisé par les traders dès les premiers moments d’apparition des méthodes d’analyse informatique. Dans cet article, nous examinerons les éventuelles modifications de MACD et les implémenterons dans un seul indicateur avec la possibilité de basculer graphiquement entre les modifications.
MQL pour "Nuls" : Comment Concevoir et Construire des Classes d'Objets MQL pour "Nuls" : Comment Concevoir et Construire des Classes d'Objets
En créant un échantillon de programme de conception visuelle, nous montrons comment concevoir et construire des classes dans MQL5. L'article est écrit pour les programmeurs débutants, qui travaillent sur des applications MT5. Nous proposons une technologie simple et facilement intelligible pour créer des classes, sans avoir besoin de s'immerger profondément dans la théorie de la programmation orientée-objet.
Gestion des événements dans MQL5 : Modification de la période  MA à la volée Gestion des événements dans MQL5 : Modification de la période MA à la volée
Admettons qu'un simple indicateur MA (Moyenne mobile) avec la période 13 soit appliqué à un graphique. Et nous souhaitons modifier la période à 20, mais nous ne souhaitons pas aller dans la boîte de dialogue des propriétés de l'indicateur et éditer le nombre 13 à 20 : tout simplement fatigué de ces actions fastidieuses avec la souris et le clavier. Et surtout nous ne souhaitons pas ouvrir le code indicateur et le modifier. Nous souhaitons faire tout cela d'une simple pression sur un bouton - "flèches vers le haut" à côté du pavé numérique. Dans cet article, je vais décrire comment le faire.