![Comment développer un Expert Advisor à l'aide des outils UML](https://c.mql5.com/i/articles/overlay.png)
Comment développer un Expert Advisor à l'aide des outils UML
Les scientifiques étudient ce qui existe déjà ; Les ingénieurs créent ce qui n'a jamais existé.
Albert Einstein
Introduction
Dans mon article Simulink : un guide pour les développeurs Expert Advisors, j'ai proposé de modéliser un Expert Advisors à l'aide de systèmes dynamiques. Cependant, cette approche ne représente qu'un aspect du concepteur de systèmes de trading - le comportement dynamique du système. Les professionnels disposent d'outils spécifiques qui élargissent la méthodologie d'un développeur de système de trading. Dans cet article, nous verrons comment développer un Expert Advisor à l'aide de l'outil universel - graphical language UML.
En général, étant un langage graphique, UML est utilisé pour la modélisation visuelle de systèmes logiciels orientés objet. Mais, à mon sens, nous pouvons utiliser ses outils pour développer un système de trading. De plus, MQL5 appartient à la famille des langages orientés objet, ce qui facilite notre tâche.
Pour les besoins de modélisation, j'ai choisi le logiciel gratuit et non-commercial Software Ideas Modeler.
1. Bases UML
Comment UML peut aider à créer un Expert Advisor ? Tout d'abord, les graphiques - le problème de la modélisation multi-aspect peut être résolu en utilisant les images graphiques disponibles dans le langage. Deuxièmement, la lisibilité. Même si un Expert Advisor est grand et complexe, l'universalité d'UML permet de présenter son modèle à l'aide de diagrammes.
Comme le disent les développeurs d'UML, la spécificité de la perception humaine réside dans le fait qu'un texte avec des images est plus facilement perçu qu'un texte seul.
Discutons brièvement des bases d'UML. Si le sujet vous intéresse, vous pouvez vous familiariser avec les outils UML à partir des nombreuses publications disponibles gratuitement sur le web.
La structure UML peut être représentée dans un diagramme (Fig. 1).
Fig. 1. La structure UML
Les éléments constitutifs sont les suivants : entités (les éléments du modèle), relations (qui lient les choses) et diagrammes (représentant les modèles UML).
Les diagrammes UML permettent de visualiser la représentation du système conçu sous différents points de vue.
Les mécanismes communs incluent : les spécifications (description de la ), les ornements (marquant les caractéristiques importantes du modèle) , divisions communes (abstraction et ses instances, interfaces et mise en œuvre), mécanismes d'extensibilité (contraintes, stéréotypes et valeurs étiquetées).
L'architecture est responsable de la présentation de haut niveau du système dans son environnement. L'architecture UML peut être décrite au mieux par la « 4+1 architecture vue » (Fig. 2) :
- Vue logique
- Vue du processus
- Vue de développement
- Vue physique
- Scénarios
Fig. 2. Vue de l'architecture 4+1
Il convient également de noter que l'UML possède sa propre hiérarchie de diagrammes canoniques (Fig. 3). La version 2.2 du langage utilise 14 types de diagrammes UML.
Fig. 3. Diagrammes UML canoniques
Je propose en outre d'examiner certains cas particuliers d'utilisation des diagrammes UML. Ainsi, nous pouvons passer d'une abstraction à une variante spécifique de l'utilisation de l'un des diagrammes à des fins de développement EA. Une fois de plus, le principe de conception multi-aspects des systèmes de trading, qui est fourni par la hiérarchie des diagrammes UML, contribue à la solution systématique et complète de la tâche de création des TS.
2. diagrammes UML
2.1 Diagrammes de cas d'utilisation
Comme le dit le proverbe, un travail bien commencé est à moitié fait. Habituellement, mais pas nécessairement, le travail analytique commence parl'utilisation des diagrammes de cas. Il décrit le système du point de vue des utilisateurs.
En le créant, on peut :
- spécifier les variantes de l'utilisation du TS
- spécifier les limites du TS
- déterminer les acteurs TS
- définir la relation entre les acteurs et les versions TS.
cas d'utilisationest une liste d'étapes, définissant généralement les interactions entre un rôle (connu en UML comme un « acteur ») et un système, pour atteindre un objectif .
Un acteur « spécifie un rôle joué par un utilisateur ou tout autre système qui interagit avec le sujet. Les acteurs peuvent représenter des rôles joués par des utilisateurs humains, du matériel externe ou d'autres sujets.
La relation est une connexion sémantique entre les éléments individuels d'un modèle.
Vous remarquerez que ce type de diagramme est assez général et qu'il reflète la nature conceptuelle du TS, plutôt que sa mise en œuvre. Mais c'est là le but - passer du général au spécifique, de l'abstrait au concret. Qui a dit que nous n'étions pas des artistes ? Nous dessinons une image, en commençant par des idées générales et des croquis. Nous commençons par dessiner des traits sur une toile. Ensuite, nous ajoutons les couleurs. Nous dessinons les détails...
Essayons donc de créer un diagramme de cas d'utilisation pour un système de trading.
En tant qu'acteurs d'entrée, j'ai choisi les rôles suivants : Développeur, analyste système, gestionnaire de risques et administrateur. Il convient de noter que ces rôles peuvent être joués par une ou plusieurs personnes. Quelles actions notre système de trading prend-il et quelles actions sont prises par rapport à celui-ci ?
Ainsi, le développeur peut créer et mettre en œuvre un TS. De plus, il ou elle peut participer à l'optimisation du TS. L'analyste système optimise le TS. Le gestionnaire de risques est responsable de la gestion des risques. L'administrateur surveille l'ensemble des travaux du TS. Du côté des résultats, nous voyons que l'Utilisateur réalise un profit grâce au fonctionnement du TS. Ce rôle est une somme de rôles tels que celui du trader et de l'investisseur. Et le gestionnaire ainsi que l'administrateur supervisent le travail du TS.
Le diagramme contient le bloc « Système de trading ». Il exprime la limite du TS et le sépare du monde extérieur.
Maintenant, quelques mots sur la relation entre les acteurs et les cas d'utilisation, ainsi qu'entre les acteurs et les autres acteurs, et les cas d'utilisation et les autres cas d'utilisation. La plupart des relations sont représentées par des associations, marquées par une ligne continue. Cela signifie qu'un certain acteur initie un cas d'utilisation. Ainsi, le gestionnaire de risques initie le processus de gestion des risques, etc. Les acteurs qui initient les cas d'utilisation sont principaux, et ceux qui utilisent les résultats des actions engagées - sont secondaires. Par exemple, un acteur secondaire est le gestionnaire du côté des résultats.
L'association peut indiquer que l'acteur initie le cas d'utilisation approprié.
La généralisation simule la généralité appropriée des rôles.
L'extension est une sorte de relation de dépendance entre le cas d'utilisation de base et son cas particulier.
Inclure définit la relation entre le cas d'utilisation de base et un autre cas d'utilisation, dont le comportement fonctionnel n'est pas toujours utilisé par le cas de base, mais uniquement dans des conditions supplémentaires.
Toutefois, notez qu'un rôle secondaire par rapport au cas d'utilisation ne signifie pas que ce rôle est d'une importance secondaire. De plus, dans le diagramme, nous voyons que le rôle de l'utilisateur TS comprend les rôles du trader et de l'investisseur à travers les relations de généralisation, représentées par une ligne avec la pointe de flèche triangulaire « non peinte ».
Fig. 4. Diagramme de cas d'utilisation du TS
Les cas d'utilisation « Position ouverte » et « Position fermée », quant à eux, sont liés par une généralisation avec le « Trading ». Ce dernier cas est celui qui sert de base aux deux autres. Ainsi, il inclut le cas d'utilisation « Gérer le risque ». Et son comportement est complémentaire à celui du cas dépendant « Profit ».
Puisque le profit TS est formé à la condition que le prix de vente d'un actif soit plus grand que son prix d'achat, j'ai utilisé la relation d'extension pour ces cas. Le diagramme montre également le point d'extension, c'est-à-dire une condition spécifique, sous laquelle le cas « Pour faire du profit » est utilisé. Les relations de dépendance sont affichées par la ligne en pointillés avec une flèche avec les stéréotypes correspondants « inclure » et « étendre ».
Pour chaque cas d'utilisation, vous devez créer un scénario, c'est-à-dire décrire une séquence d'étapes menant à l'objectif visée. Le cas d'utilisation peut être décrit sous plusieurs formes. Les formes communément acceptées sont les suivantes : descriptions textuelles, pseudocode, diagramme d'activité, diagramme d'interaction.
Il convient de noter qu'un trader s'intéresse à un TS au sens strict, plutôt qu'à celui qui est représenté sur la figure 4. Par conséquent, je suggère de se concentrer sur le cas d'utilisation « Trading » avec l'extension « Pour faire du profit ».
2.2 Diagramme de classes
En utilisant le diagramme de classe nous allons décrire la structure du TS. Plus précisément, nous allons présenter un modèle de structure statique du système de trading en termes de classes de programmation orientée objet. Ainsi, nous refléterons la logique de programmation du TS.
En UML, un diagramme de classe est un type de diagramme de structure statique. Il décrit la structure du système en montrant ses classes, leurs attributs et opérateurs, ainsi que la relation entre les classes.
Quels sont les avantages de ce type de diagramme ? Ceux qui sont un peu familiarisés avec les langages de programmation orientés objet remarqueront immédiatement la notion familière de « classe ». La classe agit dans le diagramme de classe UML en tant qu’élément constitutif. Par exemple, lors de la génération d'un code C++, le bloc de classe UML est automatiquement créé sous la forme d'un modèle de classe. Vous n'aurez qu'à terminer la mise en œuvre de chaque méthode et propriété.
Essayons maintenant de concevoir quelque chose à titre d'exemple. Mais je voudrais d'abord attirer votre attention sur l'article « Prototype d'un robot de trading », dans lequel l'auteur décrit les avantages d'utiliser une logique directe. À mon avis, le principe d'imbrication - « macros-fonctions-modules de trading » - est très efficace et productif.
Par exemple, nous avons besoin d'un Expert Advisor qui utilise les possibilités de classes de trading de la bibliothèque standard.
À l'aide du bloc Classe, créez un modèle de classe dans le diagramme de classes. Je l'ai appelé CTradeExpert. Nous ajoutons quelques attributs (dans MQL5, ce sont des membres de données de classe) pour la nouvelle classe. Ce sont : Magic_No, e_trade, e_account, e_deal, e_symbol, e_pnt. Nous insérons également une méthode de construction de la classe CTradeExpert. Graphiquement, l'opération se déroule comme indiqué à la Fig. 5.
Fig. 5. Modèle UML de la classe CTradeExpert
Le caractère « - » devant un attribut indique que l'attribut a le droit d'accès en mode « privé », « # » - « protégé », « + » - « public ». Ainsi, pour l'attribut Magic_No, le spécificateur d'accès est défini comme privé, pour e_pnt - comme public et pour les autres - comme protégé. Un deux-points qui suit le nom de l'attribut indique un type de données pour les attributs et le type de données renvoyées pour les méthodes. Par exemple, l'attribut Magic_No est de type int, e_trade - CTrade, etc.
Nous n'ajoutons aucune méthode ni aucun attribut maintenant, montrons simplement comment notre classe CTradeExpert est connectée aux classes de la bibliothèque standard. Pour ce faire, ajoutez 6 blocs de classes au diagramme et appelez-les comme suit : CTrade, CAccountInfo, CDealInfo, CSymbolInfo, CObject. Nous associons maintenant le modèle de la classe CTradeExpert à 4 blocs de classes de trading par le biais de relations de dépendance avec le stéréotype « usage » (la ligne pointillée avec une flèche).
La dépendanceest une relation sémantique entre deux entités, dans laquelle un changement dans l'entité indépendante peut affecter la sémantique de l'autre entité dépendante.
Le stéréotype en UML est une description du comportement de l'objet.
Ensuite, nous relions ces blocs au bloc CObject par la relation de généralisation à l'aide d'une ligne avec une pointe de flèche triangulaire « non peinte ». Ajouter des commentaires aux classes de la bibliothèque standard. Maintenant, notre diagramme UML ressemble à celui de la figure 6.
Fig. 6. diagramme de classes UML
Il ne nous reste plus qu'à générer le code à l'aide de la fonction « Générer » de l'onglet « Générer » de la barre latérale (Fig. 7).
Fig. 7. Code généré
Le plus approprié est le langage С++. Nous utiliserons C++ pour générer le code de la classe Expert Advisor, puis nous le traduirons facilement en MQL5.
Pour ce diagramme, le code généré est le suivant :
// class CTradeExpert { private: int Magic_No; protected: CTrade e_trade; protected: CAccountInfo e_account; protected: CDealInfo e_deal; protected: CSymbolInfo e_symbol; public: double e_pnt; public: void CTradeExpert () { } }; // class CObject { }; // class CTrade : public CObject { }; // class CDealInfo : public CObject { }; // class CSymbolInfo : public CObject { }; // class CAccountInfo : public CObject { };
Une syntaxe vraiment familière, n'est-ce pas ? Nous avons juste besoin d'adapter le corps de la classe. À cette fin, dans MetaEditor, nous créons un fichier pour la nouvelle classe TradeExpert.mqh. Copiez-y le code généré précédemment. Pour plus de lisibilité, nous supprimons le spécificateur d'accès répété protégé pour les membres de la classe CTradeExpert.
Supprimez les lignes liées à la déclaration des classes de bibliothèque standard. Après cela, ajoutez le fichier comprenant l'instruction # Include pour chaque classe utilisée de la bibliothèque standard, car ces classes sont déjà définies par le développeur. Et ajouter nos commentaires. En conséquence, nous obtenons le code suivant :
//includes #include <Trade\Trade.mqh> #include <Trade\AccountInfo.mqh> #include <Trade\DealInfo.mqh> #include <Trade\SymbolInfo.mqh> //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ class CTradeExpert { private: int Magic_No; // Expert Advisor magic protected: CTrade e_trade; // An object for executing trade orders CAccountInfo e_account; // An object for receiving account properties CDealInfo e_deal; // An object for receiving deal properties CSymbolInfo e_symbol; // An object for receiving symbol properties public: double e_pnt; // Value in points public: CTradeExpert() { } }; //+------------------------------------------------------------------+
ajoutons maintenant d'autres modules de fonctions de trading à notre classe Expert Advisor.
Ceux-ci peuvent être : CheckSignal, OpenPosition, CheckPosition, ClosePosition etc. J'espère que vous connaissez déjà le principe du « service conditionnel ». Dans ce cas, notre classe de test CTradeExpert ne vous paraîtra pas difficile. Je me suis spécifiquement concentré sur un exemple déjà familier d'un Expert Advisor pour vous permettre de comprendre plus facilement les mécanismes d'UML.
Ainsi, maintenant, le modèle de la classe ressemble à celui de la figure 8.
Fig. 8. Modèle UML de la classe CTradeExpert
Pour le modèle mis à jour de la classe, nous pouvons également générer un code en utilisant la méthode déjà décrite.
2.3 Diagramme d'activité
En utilisant ce type de diagrammes UML, nous pouvons étudier le comportement du système en utilisant les modèles de flux de données et de flux de contrôle. Les diagrammes d'activité sont des représentations graphiques de flux de travail d'activités et d'actions par étapes.
Le diagramme d'activité diffère de l'organigramme, qui ne décrit que les étapes de l'algorithme. La notation du diagramme d'activité est plus large. Par exemple, il est possible de spécifier l'état des objets qu'il contient.
Les diagrammes d'activité sont utilisés par les développeurs pour décrire :
- les règles commerciales
- les cas d'utilisation unique
- une série complexe de cas d'utilisation multiples
- des processus avec des solutions et des flux alternatifs
- des opérations parallèles
- les flux de programmes et les structures de contrôle logique
Supposons que la classe d'experts CTradeExpert créée sera utilisée dans le fichier de l'Expert Advisor Test_TradeExpert.mq5. Comme nous nous en souvenons, le modèle par défaut lors de la création d'une EA dans le MetaEditor 5 fournit trois fonctions de gestion d'événements par défaut : OnInit, OnDeinit et OnTick. Attardons-nous sur elles.
Essayons d'afficher un schéma avec notre opération EA en prenant en compte le fichier Test_TradeExpert.mq5. Ici, il convient de noter que l'Expert Advisor, ou plutôt sa structure, est assez primitive. Nous sommes seulement en train de nous entraîner. Une simple structure EA convient à cet effet.
Concevons un diagramme d'utilisation de notre Expert Advisor, dont l'algorithme est représenté dans le fichier Test_TradeExpert.mq5.
Tout commence donc par le nœud initial (Fig. 9). A partir de ce nœud, un jeton de contrôle se déplace vers le nœud appelant l'action « Créer une instance Expert Advisor ». Cette action initie le flux de l'objet (flèche bleue), qui change l'état du nœud objet (myTE=created), et le flux de contrôle vers un nœud qui appelle « Initialiser l'Expert Advisor ».
Un flux de contrôle est représenté sous la forme d'une arête d'activité, qui relie les deux nœuds d'activité et sur laquelle seuls les jetons de contrôle sont passés .
Un flux d'objets est représenté comme un bord d'activité, auquel seuls les jetons d'objet ou de données sont transmis.
Un nœud d'activité d'activité est une classe abstraite pour des points individuels dans le flux d'activités connectés par des bords.
Un nœud de décision est un nœud de contrôle, qui choisit entre les flux sortants.
Un nœud d'objet représente les objets utilisés dans l'activité.
Un arête d'activité est une classe abstraite pour les connexions dirigées entre deux nœuds d'activité.
Le nœud initial indique où commence l'activité.
Le nœud final d'une activité complète tous les flux d'activité.Il modifie à son tour l'état de l'objet myTE (myTE=initialized) et transmet le jeton de contrôle au nœud de décision. Si l'Expert Advisor est initialisé avec succès, le flux de contrôle passe au nœud « Traiter l'événement de trading NewTick ». Si l'initialisation échoue, alors le jeton de contrôle entre d'abord dans le nœud de généralisation, puis dans le nœud d'action « Désinitialiser l'Expert Advisor ».
Les jetons sont des constructions abstraites qui sont introduites par commodité pour décrire le processus dynamique d'exécution d'un graphique d'activité défini statistiquement. Le jeton ne peut contenir aucune information supplémentaire (un jeton vide) ; dans ce cas, il est appelé jeton de flux de contrôle, ou il peut contenir une référence à un objet ou à une structure de données, et dans ce cas, il est appelé jeton de flux de données.
Examinons le premier flux de contrôle qui provient du nœud de décision. Il est dirigé vers une zone dont l'action est interrompue, comme l'indique un rectangle aux coins arrondis dessiné par la ligne pointillée rouge et le stéréotype « interruptible ». Lorsque le flux de contrôle se trouve dans cette zone, il peut s'arrêter de manière inattendue. Si vous activez le nœud d'action (drapeau orange) qui reçoit l'événement « Décharger Expert Advisor », il interrompra tous les flux. Le jeton de contrôle se déplace vers le bord d'interruption (flèche orange en zigzag), puis vers le nœud de connexion. Après cela, l'EA est désinitialisé. Ensuite, le jeton de contrôle va au nœud « Supprimer les variables globales », puis le flux sera terminé dans le nœud d'activité final.
Le nœud d'action « Désinitaliser Expert Advisor » modifie également l'état de l'objet myTE (myTE=deinitsialized) par un flux d'objets. Le nœud « Supprimer les variables globales », à son tour, supprime l'objet myTE (myTE=deleted).
Fig. 9. Diagramme d'activité de Test_TradeExpert.mq5
Supposons que le flux de contrôle soit stable : l'EA n'est pas déchargé. À partir du nœud « Traiter l'événement de trading NewTick », le flux se déplace vers un autre bloc - zone d'expansion, dont le stéréotype est défini comme « itératif » (rectangle vert avec des lignes pointillées).
J'appelle cette zone « Block de Trading », pour refléter les caractéristiques de base et améliorer la perception du diagramme. Une caractéristique du bloc est l'exécution cyclique des opérations pour les objets entrants. Nous n'avons besoin que de 2 cycles - gérer les directions longues et courtes. À l'entrée du bloc et à la sortie du bloc, il y a des nœuds d'extension qui incluent des objets de direction de trading (longs ou courts).
Un nœud d'expansion est une collection d'objets qui entre ou sort de la zone d'expansion, qui est exécuté une fois pour chaque objet.
Le nœud d'action qui envoie un signal (envoyer un signal d'action) représente l'envoi de signal.
Le nœud d'action qui accepte un événement accepter l'action de l'événement), attend la réception d'un événement du type approprié.
Ainsi, chaque direction est traitée par des nœuds tels que : « Signal de contrôle » (nœud émetteur de signal), « Signal de réception » (nœud récepteur de signal), « Position ouverte » (nœud émetteur de signal), « Position de contrôle » (nœud émetteur de signal), « Position fermée » (nœud émetteur de signal). Il convient de noter que l'objet de direction (dir) peut être transmis dans le flux d'objets entre les nœuds d'action, comme indiqué par les flèches violettes. Les opérations dans un bloc se poursuivent tant que l'Expert Adviser est déchargé.
2.4 Le diagramme de séquence
Nous utilisons le diagramme de séquence pour décrire la séquence d'interaction de l'objet. Un aspect très important de ce type de diagramme est le temps.
Ainsi, le diagramme comporte deux échelles sous une forme implicite. L'horizontale est responsable de la séquence des interactions entre les objets. L'axe vertical est un axe de temps. Le début de l'intervalle de temps est la partie supérieure du diagramme.
La partie supérieure du diagramme contient les objets du diagramme, qui interagissent. Un objet a sa propre ligne de vie sous la forme d'une ligne pointillée verticale. Les objets échangent des messages. Ils sont représentés par des flèches. Lorsqu'un objet est actif, il reçoit un foyer de contrôle. Graphiquement, ce foyer est exprimée par un rectangle étroit sur la ligne de vie.
Un objet est un rectangle qui contient un nom d'objet et un nom de classe (facultatif) soulignés et séparés par deux points.
Une ligne de vie d'objet est une ligne qui montre l'existence d'un objet pendant une certaine période de temps ; plus la ligne est longue, plus l'objet existe.
Le foyer de contrôle est dessiné sous la forme d'un rectangle étroit, dont la partie supérieure indique le début de la réception du focus de contrôle par l'objet (début de l'activité), et sa partie inférieure - la fin du foyer de contrôle (fin de l'activité).
En UML, chaque interaction est décrite par un ensemble de messages, que les objets participant à l'interaction échangent.
Entraînons-nous un peu.
Le terminal est un acteur. Il initie le fonctionnement de l'Expert Advisor. Les autres objets marqués du stéréotype « événement » sont les événements du terminal client : Init, Deinit, NewTick. Bien sûr, si vous le souhaitez, vous pouvez étendre la gamme des événements. Lors du démarrage d'un Expert Advisor, l'objet myTE est créé au niveau global. C'est une instance de la classe CTradeExpert. L'objet classe est légèrement inférieur aux autres objets du diagramme, ce qui indique qu'il est créé après la fonction constructeur.
Une commande de création est signalée par une ligne pointillée et par une flèche ouverte et un message 1.1 CTradeExpert(). La ligne pointillée avec une flèche indique le type « créer » du constructeur par défaut CTradeExpert(). Après avoir créé une instance de CTradeExpert, l'étape 1.2 est activée - le foyer de contrôle est renvoyé au terminal. Pour des raisons de lisibilité, j'indique les messages synchrones sous le format #.#, comme 1.1, et asynchrones - #. Ensuite, le terminal traite l'événement Init à l'aide de la fonction OnInit() à l'étape 2.1, le focus est retourné à l'étape 2.2. Les messages de type « appel » sont représentés sous forme de lignes avec une flèche triangulaire « peinte » à l'extrémité.
Si l'événement Init renvoie une valeur non nulle au terminal, cela signifie que l'initialisation a échoué : on utilise l'étape 3.1 qui conduit à la génération et au traitement de l'événement Deinit. À l'étape 3.2, le focus de contrôle est renvoyé au terminal. Ensuite, l'objet de classe CTradeExpert est supprimé (étape 4.1). A propos, lors de la création d'un diagramme de classe, je n'ai pas inclus la fonction destructeur CTradeExpert dans la classe. Cela peut être fait plus tard. C'est l'un des avantages de la construction de diagrammes - le processus de construction de plusieurs diagrammes est itératif. Ce qui a été fait d'abord pour un diagramme, peut être fait ensuite pour un autre, et plus tard vous pouvez modifier le premier.
Il convient de noter que le code MQL5 d'un modèle EA standard ne contient pas de bloc qui gère l'échec de l'initialisation. Je l'ai spécifié pour sauvegarder la logique de la séquence. Le diagramme de séquence UML utilise le bloc opt avec une condition de garde OnInit()!=0, ce qui équivaut à la construction MQL5 if(OnInit()!= 0) {}.
À l'étape 4.2, le contrôle est transféré au terminal.
Le terminal est maintenant prêt à gérer l'événement NewTick.
Le traitement de cet événement se fait dans le block loop, c'est-à-dire une boucle infinie. C'est-à-dire que l'EA va gérer cet événement jusqu'à ce que nous le désactivions. Le terminal traite l'événement NewTick à l'aide de la fonction OnTick (étape 5). À l'étape 6, le focus de contrôle est transféré à l'Expert Advisor myTE. Utilisant 4 messages réflexifs, il met en œuvre les fonctions suivantes : CheckSignal, OpenPosition, CheckPosition, ClosePosition. La réflexivité est due au fait que l'objet Expert Advisor s'envoie des messages.
De plus, ces fonctions de la classe CTradeExpert sont incluses dans le bloc loop(2). Deux signifie que la boucle est constituée de deux passages. Pourquoi deux ? Parce qu'il gère deux directions de trading - long et court (de l'étape 7 à 10). Dans la 11ème étape, le focus est transmis au terminal.
Les étapes 12 et 13 sont responsables de la désinitialisation et de la suppression de l'objet Expert Advisor, respectivement.
Fig. 10. Diagramme SD pour Test_TradeExpert.mq5
Ainsi, nous disposons des compétences primaires en matière de conception. A l'aide des diagrammes créés, le travail du développeur est optimisé. Nous pouvons maintenant commencer à écrire un code pour le fichier Test_TradeExpert.mq5. Bien sûr, vous pouvez vous passer de diagrammes. Mais lorsque vous avez un Expert Advisor complexe, l'utilisation de diagrammes réduit la probabilité d'erreurs et vous permet de gérer efficacement le développement de votre TS.
En utilisant le modèle Expert Advisor, nous créons maintenant Test_TradeExpert.mq5.
Nous créons une instance de la classe CTradeExpert myTE au niveau global.
Maintenant, remplissons le corps de la fonction OnTick().
Nous écrivons les fonctions de la classe comme suit :
for(long dir=0;dir<2;dir++) { myTE.CheckSignal(dir); myTE.OpenPosition(dir); myTE.CheckPosition (dir); myTE.ClosePosition(dir); }
Quelque chose comme ceci sera la gestion de l'événement NewTick. Bien sûr, nous devons encore spécifier chacune des fonctions qui seront utilisées par les membres des données de la classe, entre autres. Mais laissons ce travail pour plus tard. Notre objectif est maintenant de transférer la logique des diagrammes UML dans le code MQL5.
3. Développement et présentation d'un Expert Advisor basé sur les diagrammes UML
À titre d'exemple, créons des diagrammes pour un Expert Advisor complexe. Définissons ses caractéristiques dans le contexte d'une stratégie donnée mise en œuvre dans le MQL5. En général, notre Expert Advisor effectue des opérations de trading ; il génère notamment des signaux de trading, maintient des positions ouvertes et gère l'argent. Il s'agit plutôt d'un modèle de stratégie de trading. Cependant, à des fins de formation, nous essaierons de travailler avec celui-ci.
Tout d'abord, nous allons créer un diagramme de cas d'utilisation pour notre EA. Ce n'est que dans une certaine mesure qu'il sera différent de celui dont il a été question précédemment. J'ai prêté attention à l'environnement interne du TS, en ignorant l'extérieur (Fig. 11), car dans le code nous ne mettrons en œuvre que les tâches de trading.
Fig. 11. Diagramme de cas d'utilisation du TS
Définissons maintenant la structure de l'Expert Advisor. Supposons que nous utiliserons les développements de la bibliothèque standard, parce qu'ils sont compatibles avec les objectifs déclarés du TS. Il a été récemment élargi de manière substantielle. Et surtout, il s'agit des catégories de stratégies de trading. Notre objectif est donc de créer un diagramme de classes. Ce ne sera pas simple, il faut donc de la patience.
Ici, je voudrais noter que nous considérons la bibliothèque standard pour plusieurs raisons. Tout d'abord, sur sa base, nous essayons de créer un robot de trading. Et, deuxièmement, ce qui est également important, nous avons une certaine pratique du travail avec les diagrammes UML. Troisièmement, la bibliothèque elle-même est peut-être très précieuse. Nous pouvons donc apprendre beaucoup de choses utiles de la bibliothèque et, en même temps, essayer de comprendre sa structure pas tout à fait simple.
La conversion d'un code dans la structure d'un diagramme UML est appelée ingénierie inverse. En fait, nous le faisons manuellement. Il existe des logiciels professionnels qui permettent de le faire automatiquement (IBM Rational Rose, Visual Paradigm pour UML, etc.). Mais pour des raisons pratiques, je pense que nous devons travailler « manuellement ».
Créons un modèle de la classe de base pour mettre en œuvre les stratégies de trading CExpert en utilisant le bloc « Class ». Voyons quelles autres classes et constructions sont utilisées dans le corps de la classe CExpert. Tout d'abord, il convient de noter que la classe CExpert est dérivée de la classe de base CExpertBase, qui, à son tour, est dérivée de la classe de base CObject.
Dans le diagramme, nous créons des blocs pour ces classes et définissons la relation entre les classes à l'aide d'une ligne avec une pointe de flèche triangulaire « non peinte » (généralisation). Ajoutez un commentaire au modèle de la classe CExpert (un rectangle jaune avec un coin courbé). La structure de classe intermédiaire ressemble maintenant à ceci - Fig. 12. Appelons le diagramme Expert.
Fig. 12. Le diagramme Expert, la vue initiale
Voyons le code dans le fichier Expert.mqh. La classe CExpert, entre autres, fait intervenir les énumérations ENUM_TRADE_EVENTS et ENUM_TIMEFRAMES, une des 8 structures prédéfinies MqlDateTime. La classe utilise également d'autres instances de classe, telles que : CExpertTrade, CExpertSignal, CExpertMoney, CExpertTrailing, CIndicators, CPositiontInfo, COrderInfo.
Nous devons maintenant apporter quelques modifications au diagramme. Premièrement, nous spécifions que les classes CExpertSignal, CExpertMoney, CExpertTrailing sont dérivées d'une classe de base CExpertBase, et les classes CPositiontInfo, COrderInfo sont dérivées de CObject (j'ai défini le stéréotype « metaclass » pour cela).
Marquons les relations de dépendance avec le stéréotype « use » entre le bloc de la classe CExpert et les autres classes, sans oublier la structure et les énumérations MqlDateTime. Nous modifions le style de couleur des blocs et obtenons la structure suivante - Fig. 13.
Fig. 13. Le diagramme Expert, la vue initiale
Toutefois, cette structure ne reflète pas l'ensemble de la situation, car il existe un certain nombre de classes qui sont indirectement utilisées par les classes déjà mentionnées. De quel genre de classes s'agit-il ? Premièrement, la classe CExpertTrade est dérivée de CTrade. Ce dernier est une sous-classe de CObject.
La classe CExpertTrade utilise l'énumération ENUM_ORDER_TYPE_TIME, les classes CSymbolInfo et CAccountInfo sont également des enfants de CObject. La classe CTrade utilise également des instances des classes CSymbolInfo. Effectuons des changements dans le diagramme. Notre diagramme a maintenant la forme suivante - Fig. 14.
Fig. 14. Le diagramme Expert, la vue initiale
Encore une fois, le diagramme n'est pas complet. Par exemple, si vous regardez dans le fichier de bibliothèque standard Trade.mqh, vous verrez que CTrade utilise plusieurs structures différentes, des énumérations et la classe CSymbolInfo. S'ils sont tous affichés sur un même diagramme, il sera trop chargé. Et cela rendra la compréhension difficile.
Pour faire face à cette difficulté, j'ai utilisé un package pour le diagramme. Il encapsule les classes associées, les énumérations, d'autres packages, etc. J'ai connecté le paquet avec les éléments du diagramme à travers l'interface. Par exemple, le schéma du paquet CTrade peut être représenté comme suit - Fig. 15.
Fig. 15. Le diagramme de classes du paquet CTrade
Le diagramme du paquet CTrade montre les relations de dépendance de la CTrade classe avec les énumérations et la structure.
Les relations avec la classe de base CObject et la classe CSymbolInfo utilisée sont mises en œuvre par le biais d'une interface.
Près des interfaces, il y a une icône de relation avec le diagramme de classes qui contient le paquet CTrade en tant qu'élément unique. Un clic sur l'une des interfaces ramène automatiquement au diagramme original (Fig. 16).
Fig. 16. Le diagramme Expert avec interfaces
Les relations d'interface sont orange. L'icône du diagramme de classes à côté du paquet CTrade indique la possibilité de passer à ce diagramme. Ainsi, en utilisant l'encapsulation, nous pouvons améliorer de manière significative la lisibilité du diagramme de classes.
Passons à autre chose. La classe CObject utilise des pointeurs vers des instances de la même classe dans son corps. Par conséquent, nous pouvons définir la relation de dépendance pour le bloc CObject avec le stéréotype « use » par rapport à lui-même.
Examinons le bloc du modèle de la classe CExpertBase. D'après les premières lignes du fichier d'en-tête ExpertBase.mqh, nous pouvons dire que cette classe utilise plusieurs instances de différentes classes et énumérations. Par conséquent, pour le modèle de classe et ses relations, il est raisonnable de créer le paquet CExpertBase.
Donc, nous définissons d'abord le modèle de classe CExpertBase dans le diagramme de paquet. A travers l'interface, nous montrons la relation avec la classe de base CObject, et la relation d'utilisation avec les classes CSymbolInfo et CAccountInfo. Ensuite, à l'aide de blocs de classes et de relations de dépendance, nous spécifions que la classe CExpertBase utilise les classes suivantes : CiOpen, CiHigh, CiLow, CiSpread, CiTime, CiTickVolume, CiRealVolume.
Les quatre premières classes sont dérivées de CPriceSeries et les quatre dernières – de CSeries. De plus, la classe CSeries a un enfant CPriceSeries et est, à son tour, un enfant de CArrayObj. Les relations d'héritage ont déjà été utilisées auparavant, comme on s'en souvient. Désignez-les comme une relation de généralisation dans le diagramme.
N'oubliez pas que la classe CExpertBase utilise dans son corps des énumérations telles que : ENUM_TYPE_TREND, ENUM_USED_SERIES, ENUM_INIT_PHASE, ENUM_TIMEFRAMES. La dernière énumération est également utilisée par les enfants de la classe CPriceSeries et de la classe CSeries. Pour ne pas perdre les relations et pour que le diagramme soit clair, ajustons le style pour chacun des éléments du diagramme. En conséquence, nous obtenons le schéma suivant (Fig. 17).
Fig.. 17. Le diagramme de classes du paquet CExpertBase
Ce n'est pas encore terminé, et nous devrons y travailler un peu plus. Il s'avère que les quatre classes qui héritent de la classe CPriceSeries utilisent également la classe CDoubleBuffer. De plus, chacune des quatre classes utilise sa classe tampon qui dérive de CDoubleBuffer. Ainsi, COpen utilise COpenBuffer etc. CDoubleBuffer a une classe de base (CArrayDouble) et utilise ENUM_TIMEFRAMES.
CArrayDouble hérite de CArray, utilise des pointeurs vers les instances de sa propre classe et l'énumération ENUM_DATATYPE. La classe COpenBuffer et les autres classes tampons des séries de prix (CHighBuffer, CLowBuffer, CCloseBuffer) utilisent l'énumération ENUM_TIMEFRAMES.
Les quatre classes qui héritent de la classe CSeries n'utilisent que leurs propres classes de tampon (CSpreadBuffer, CTimeBuffer, CTickVolumeBuffer, CRealVolumeBuffer). Le premier des tampons de classe CSpreadBuffer hérite de CArrayInt, les autres – CArrayLong. Les deux dernières classes utilisent les pointeurs vers les instances de leur propre classe, l'énumération ENUM_DATATYPE et sont dérivées de CArray, qui, à son tour, est un enfant de la classe CObject.
La classe CPriceSeries et ses enfants utilisent la classe CDoubleBuffer et l'énumération ENUM_TIMEFRAMES.
CSeries utilise les énumérations ENUM_SERIES_INFO_INTEGER, ENUM_TIMEFRAMES. Il hérite de CArrayObj. Cette dernière hérite de CArray, utilise ENUM_POINTER_TYPE, des pointeurs sur les instances de sa propre classe et de la classe CObject. En conséquence, nous obtenons le diagramme présenté à la figure 18.
Fig. 18. Diagramme de classes étendu pour le paquet CExpertBase
Et le diagramme original Expert pour les classes et paquet CExpert, CExpertBase, CSymbolInfo, CAccountInfo et CObject avec les interfaces se présente comme suit (Fig.19).
Fig. 19. Le diagramme Expert avec interfaces
J'ai également ajouté l'énumération ENUM_ORDER_TYPE utilisée par CExpertTrade. Pour plus de lisibilité, j'ai marqué le groupe de relations avec des couleurs différentes.
Nous poursuivons notre travail. J'espère que vous comprenez la logique. Le modèle d'une classe sur le diagramme peut avoir de nombreuses relations avec d'autres classes et d'autres entités. Je remplace donc simplement un ensemble par un paquet dans le diagramme de base.
Nous allons donc étudier CSymbolInfo. Si vous regardez le code de SymbolInfo.mqh, vous verrez que la classe de base CSymbolInfo utilise des énumérations et des structures MQL5. Il est bon d'utiliser un paquet pour lui et ses relations (Fig. 20).
Fig. 20. Diagramme du paquet CSymbolInfo
Un espace libre dans le diagramme peut être utilisé pour des commentaires. Aussi, j'ai marqué l'interface de relation avec la classe parent CObject. Le diagramme Expert original des paquet et des classes sera légèrement modifié. Je donnerai sa version mise à jour plus tard, lorsque toutes les classes et paquets seront reflétés dans le diagramme.
Passons à autre chose. Regardons le code MQL dans AccountInfo.mqh. Il s'avère que CAccountInfo utilise également des énumérations. Nous les reflétons sur le diagramme du paquet qui va créer pour cette classe et ses relations avec les autres entités (Fig. 21).
Fig. 21. Diagramme du paquet CAccountlInfo
Passons maintenant à la classe CExpert. Pour cette classe, nous créons également un paquet CExpert, qui apparaîtra comme indiqué sur la Fig. 22. Nous continuons à améliorer la lisibilité de notre diagramme principal. La classe CExpert est connectée à plusieurs autres classes, comme indiqué par les lignes d'interface orange avec une flèche.
Fig. 22. Diagramme du paquet CExpert
Explorons les autres classes restantes. Nous allons créer d'autres paquets pour eux.
CExpertSignal dérive de CExpertBase. Cette relation a déjà été montrée sur le diagramme original Expert. De plus, la classe CExpertSignal utilise CArrayObj, COrderInfo, CIndicators et les instances de sa propre classe (Fig .23). En particulier, l'interface de relation avec la classe CArrayObj nous amènera au diagramme du paquet CExpertBase, qui montre la relation de la classe CArrayObj avec d'autres entités.
Fig. 23. Diagramme du paquet CExpertSignal
Je ne montre pas tous les diagrammes maintenant - ils sont tous disponibles dans le fichier joint Expert.simp. Regardons maintenant notre diagramme mis à jour des paquets et des classes Expert (Fig. 24).
Comme vous pouvez le constater, presque toutes les classes clés du diagramme ont été encapsulées dans des paquets afin de rendre le diagramme plus facile à comprendre. J'ai changé la couleur de la ligne de généralisation en marron, pour la distinguer de la ligne de la relation de dépendance.
Fig. 24. Le diagramme des paquets et des classes Expert
Nous avons donc réfléchi à tout ce qui peut être tiré du code disponible dans la bibliothèque standard pour créer des diagrammes. Nous devons seulement ajouter quelques blocs supplémentaires, qui spécifient les opérations de trading de l'Expert Advisor.
Le tout premier bloc est le bloc de CmyExpert qui hérite des « compétences » de trading de la classe CExpert. C'est le bloc pour lequel nous avons si longtemps fait de la rétro-ingénierie. Il mettra en œuvre une stratégie de trading spécifique. Nous devons également spécifier les fonctions virtuelles des classes de base de l'EA.
à cet effet, nous créons un bloc de classes CmyExpertSignal, CmyExpertMoney, CmyExpertTrailing et indiquons qu'elles sont dérivées de la appropriée (Fig. 25).
Fig. 25. Diagramme élargi des paquets et des classes Expert
Le choix des fonctions et des données à inclure dans chacune des classes est laissé à l'appréciation du développeur. Ici, j'essaie de montrer le schéma plus général, pas une mise en œuvre spécifique d'une classe dérivée. Ainsi, pour chacune des classes dérivées, nous pouvons créer un diagramme séparé avec une liste détaillée des méthodes et propriétés incluses, comme cela a été fait, par exemple, dans la figure 8.
Voyons maintenant comment nous pouvons utiliser le diagramme de séquence dans notre travail. Je vous rappelle qu'il montre comment notre EA fonctionne par rapport à la chronologie.
Ainsi, nous écrivons les détails du travail de l'EA par ordre chronologique (Fig. 26).
Fig. 26. Le diagramme de séquence de l'Expert Advisor
Le terminal sert d'acteur. Au niveau global, il crée l'objet myTrader - une instance de CmyExpert (étape 1.1). Le vert indique des événements prédéfinis du terminal client (Init, Deinit, NewTick, Trade.) La logique du diagramme de séquence a été décrite précédemment. Je voudrais ici souligner quelques points spécifiques. Lorsque le corps de l'Expert Advisor s'agrandit et qu'il y a de plus en plus de code, il devient plus difficile de l'afficher dans un diagramme.
Pour résoudre ce problème, utilisez l'approche par blocs. Un ensemble de quelques fonctions communes est visualisé sous forme de bloc. En règle générale, il s'agit d'un autre diagramme de séquence. On dit qu'il s'agit d'un usage d'interaction.
Ainsi, dans ce cas, j'ai créé un diagramme de séquence appelé OnInit afin de refléter la logique de gestion de l'événement terminal Init dans un diagramme séparé. Syntaxiquement, il est défini comme une bordure avec le mot-clé ref (référence) et est utilisé lorsque le jeton de contrôle passe de OnInit (étape 2.1) à la ligne de Init objet.
De plus, j'ai défini un déplacement d'interface vers ce diagramme de séquence pour OnInit. C'est-à-dire que si vous cliquez 2 fois sur la bordure, vous pouvez effectivement ouvrir un diagramme de séquence détaillé de OnInit (Fig. 27).
Fig. 27. Le diagramme de séquence d'OnInit
Les déplacements vers d'autres diagrammes de séquence sont très pratiques pour les répétitions de certaines actions.
Par exemple, le diagramme OnInit contient des actions liées à la désinitialisation de l'EA, dont le traitement est effectué dans myTrader_Deinit (Fig. 28).
Fig. 28. Le diagramme de séquence de myTrader_Deinit
En général, à ce stade de la conception de l'EA, je dispose de quatre diagrammes de séquence. Naturellement, lors d'un développement plus sérieux, vous pouvez avoir besoin de diagrammes supplémentaires. Par exemple, je n'ai pas traité les autres événements du terminal client (NewTick, Trade).
Conclusions
Dans cet article, j'ai suggéré de prendre en compte la nature multidimensionnelle du processus de développement d'Expert Advisor en utilisant le langage graphique UML, qui est utilisé pour la modélisation visuelle des systèmes logiciels orientés objet. Le principal avantage de cette approche est la visualisation du concepteur.
Comme tout phénomène complexe, UML a ses propres inconvénients dont le développeur doit être conscient (redondance, sémantique imprécise, etc.).
J'espère que la méthodologie décrite pour le développement de l'EA vous intéresse. Je serais reconnaissant pour tout commentaire et toute critique constructive.
Emplacement des fichiers :
# | Fichier | Chemin | Description |
---|---|---|---|
1 | TradeExpert.mqh | %MetaTrader%\MQL5\Include | Type d'Expert Advisor |
2 | Test_TradeExpert.mq5 | %MetaTrader%\MQL5\Experts | Expert Advisor |
3 | Expert.simp | %Documents%\projets UML | Projet de diagrammes UML |
4 | SoftwareIdeasModeler.4.103.zip | %Program Files%\SoftwareIdeasModeler | Fichier de distribution du logiciel Ideas Modeler |
Référence :
- Free UML courses. L'Université Internet des technologies de l'information
- Jim Arlow, Ila Neutstadt. UML2 et le Processus Unifié Pratique : Analyse et conception orientées objet
- Leonenkov A. Analyse et conception orientées objet utilisant UML et IBM Rational Rose.
- Martin Fowler UML distillé : Un bref guide du langage standard de modélisation des objets. - 192 стр.
- Paul Kimmel. UML démystifié. - 272 стр.
- F. A. Novikov, D. Y. Ivanov. Modélisation en UML
- Mark Priestly. Conception pratique orientée objet avec Uml, Mcgraw Hill Higher Education; 2e édition, 2007.
Traduit du russe par MetaQuotes Ltd.
Article original : https://www.mql5.com/ru/articles/304
![Comment ajouter de nouvelles langues à l'interface utilisateur de la plateforme MetaTrader 5](https://c.mql5.com/2/0/language.png)
![Application de la transformation de Fisher et de la transformation inverse de Fisher à l'analyse des marchés dans MetaTrader 5](https://c.mql5.com/2/0/Fisher_Transform_MQL5__1.png)
![Dr. Tradelove ou comment j'ai arrêté de m'inquiéter et créé un Expert Advisor en autoformation](https://c.mql5.com/2/0/smart_EA.png)
![Paiements et modes de paiement](https://c.mql5.com/2/0/mql5_payment__1.png)
![MQL5 - Langage des stratégies de trading intégré au terminal client MetaTrader 5](https://c.mql5.com/i/registerlandings/logo-2.png)
- Applications de trading gratuites
- Plus de 8 000 signaux à copier
- Actualités économiques pour explorer les marchés financiers
Vous acceptez la politique du site Web et les conditions d'utilisation