English Русский 中文 Español Deutsch 日本語 Português 한국어 Italiano Türkçe
Le marché et la physique de ses modèles globaux

Le marché et la physique de ses modèles globaux

MetaTrader 5Systèmes de trading | 10 avril 2024, 11:06
220 0
Evgeniy Ilin
Evgeniy Ilin

Introduction

Dans cet article, nous allons essayer de comprendre comment la physique des marchés peut être utilisée pour le trading automatisé. Le langage des mathématiques implique le passage de l'abstraction et de l'incertitude à la prévision. Cela permet de travailler avec des formules ou des critères clairs, plutôt qu'avec des valeurs approximatives et vagues, dans le but d'améliorer la qualité des systèmes créés. Je n'inventerai pas de théories ou de modèles, mais j'utiliserai uniquement des faits connus, que je traduirai progressivement dans le langage de l'analyse mathématique. La physique des marchés est impossible sans les mathématiques, car les signaux que nous générons sont de la substance mathématique. De nombreuses personnes tentent d'élaborer diverses théories et formules sans aucune analyse statistique ou en utilisant des statistiques très limitées, qui ne sont souvent pas suffisantes pour tirer des conclusions aussi audacieuses. Seule la pratique est le critère de la vérité. Dans un premier temps, je vais essayer de réfléchir un peu, puis, sur la base de ces réflexions, je vais créer un Expert Advisor (EA). Cette étape sera suivie par les tests de l’EA.


Prix et avantages

Tout contexte de marché implique l'existence de différents produits. Sur le marché des devises, le produit est la monnaie. La monnaie est le droit de posséder un certain produit ou une certaine information, qui sert de référence dans le monde entier. Prenons l'exemple de la paire EURUSD et de la valeur actuelle de son graphique. La valeur actuelle du graphique sera USD/EUR = Prix actuel. Ou : USD = EUR * PrixCourant, c'est-à-dire la quantité de dollars contenue dans un euro. En d'autres termes, la valeur indique le rapport entre le poids de chaque devise, tout en supposant, bien sûr, qu'il existe un équivalent d'échange commun pour chaque devise, c'est-à-dire une marchandise commune ou autre. Le prix est formé dans le carnet d'ordres, et la dynamique du carnet d'ordres détermine le mouvement du prix. Il faut toujours garder à l'esprit que nous ne pourrons jamais prendre en compte tous les facteurs de formation des prix. Par exemple, le FORTS est lié au FOREX et les deux marchés s'influencent mutuellement. Je ne suis pas un expert dans ce domaine, mais je suis capable de comprendre que tout est lié et que plus il y a de canaux de données, mieux c'est. Il me semble qu'il est préférable de ne pas entrer dans les détails, mais de se concentrer sur les choses simples qui font bouger les prix.

Toute dépendance peut être représentée par une fonction de plusieurs variables, comme des cotations par exemple. Dans un premier temps, le prix est :

  • P = P(t)

En d'autres termes, le prix est P fonction du temps t. La forme de la fonction ne peut pas être établie de manière fiable pour chaque paire de devises ou tout autre instrument. Cela prendrait un temps infini. Mais cette représentation ne nous donne rien. Mais le prix est de nature double puisqu'il comporte à la fois une composante prévisible et une composante aléatoire. La partie prévisible n'est pas la fonction elle-même, mais sa dérivée première. Il n'y a aucun sens à représenter cette fonction sous la forme de certains termes, puisque cela n'a aucune raison d'être pour le trading. Mais si l'on considère sa dérivée première, on obtient ce qui suit :

  • P'(t) = Pa'(t) + Pu'(t)

Ici, le premier terme reflète la partie qui peut être analysée d'une manière ou d'une autre à l'aide de l'analyse mathématique, le second est la partie imprévisible. Selon cette formule, nous pouvons dire qu'il est impossible de prédire l'ampleur et la direction du mouvement avec une précision de 100 %. Il n'est pas nécessaire de passer du temps à réfléchir au dernier terme puisque nous ne pouvons pas le déterminer. Mais nous pouvons déterminer le premier. On peut supposer que ce terme peut être représenté sous une forme différente, en tenant compte du fait que la fonction de valeur est discrète et que nous ne pouvons pas appliquer d'opérations différentielles. Mais nous pouvons prendre à la place la dérivée moyenne sur le temps "st". Lorsqu'elle est appliquée au prix, il s'agit de la durée d'une barre. Lorsqu'elle est appliqués aux ticks, il s'agit du temps minimum entre deux ticks.

  • PaM(t) = (Pa(t) - Pa(t-st)) / st - le mouvement moyen du prix (dérivée temporelle) sur une période de temps donnée.
  • Ma(t) = Ma(P(t), P(t - st) + ... + P(t - N * st), D(t),D(t - st) + ... + D(t - N * st), U[1](), U[2](t) + ... + U[N](t))
  • P(t[i]) - anciennes valeurs du prix (barre ou tick)
  • D(t[i]) - anciennes valeurs du prix sur d'autres paires de devises
  • U[i](t) - autres valeurs connues ou inconnues affectant le marché
  • Ma(t ) - espérance mathématique de la valeur PaM(t) à un moment donné

En d'autres termes, nous supposons que la partie prévisible du prix peut dépendre des barres ou des ticks précédents, ainsi que des prix d'autres paires de devises, d'autres bourses et des événements mondiaux. Mais il faut comprendre que même cette partie du prix ne peut pas être prédite avec une précision de 100%. Nous ne pouvons que calculer certaines de ses caractéristiques. L’une de ces caractéristiques peut être une probabilité ou des paramètres d'une variable aléatoire, tels que l'espérance mathématique, la variance, l'écart type et d'autres quantités de la théorie des probabilités. Le fait d'opérer avec des attentes mathématiques peut suffire à rendre le trading rentable. Après avoir pris le temps de réfléchir, nous pouvons arriver à la conclusion que le marché ne peut pas être analysé seulement avec cette logique. En effet, la partie prévisible du prix évolue en fonction de l'activité des acteurs du marché. Nous pouvons écarter différents paramètres du marché, à l'exception des facteurs créés par les acteurs du marché eux-mêmes. Bien sûr, tout cela entraîne une diminution de la fiabilité de notre méthode d'analyse, mais cela simplifie grandement le modèle. Ici, plus la valeur "st" est petite, plus nos formules décrivent le marché avec précision.

  • VMa(t) = VMa(P(t), P(t - st) + ... + P(t - N * st))
  • VMa(t) = VBuy(t) - VSell(t)
  • VMa(t) - volumes totaux
  • VBuy(t) - volumes des ordres d'achat ouverts
  • VSell(t) - volume des ordres de vente en cours

La fonction ci-dessus décrit la différence entre les volumes de toutes les positions d'achat et de vente actuellement ouvertes. Une partie de ces positions se compensent mutuellement, et les autres positions sont indépendantes. Les positions étant ouvertes, elles symbolisent une promesse de fermeture au bout d'un certain temps. Nous savons tous que l'achat fait monter les prix et que la vente les fait baisser. La seule façon de savoir où le prix va aller est de mesurer les volumes des positions ouvertes et d'estimer la direction de ces positions, en ne prenant en compte que les ordres de marché ouverts.

La nature ondulatoire du marché est liée à ce simple fait. Il ne s'agit que d'un cas particulier d'un processus plus général de fluctuations des volumes de positions, ou d'actions des haussiers et des baissiers.

Dans le cas des barres, il est également possible de tenir compte du fait qu'il y a 4 prix à l'intérieur d'une barre, ce qui permet d'obtenir de meilleures formules. Plus de données signifie une analyse plus précise, c'est pourquoi il est important de prendre en compte toutes les données relatives aux prix. Mais je n'aime pas compter chaque tick car cela ralentit les algorithmes de dix fois. De plus, les données relatives aux ticks peuvent varier d'un courtier à l'autre. Au contraire, les prix d'ouverture et de fermeture des barres sont presque tous identiques pour la plupart des courtiers. Modifions la fonction de volume pour prendre en compte toutes les données du prix :

  • VMa(t) = VMa(O(t), O(t - st) +...+ O(t - N * st) + C(t), C(t - st) + C(t - N * st), H(t), H(t - st)...H(t - N * st), L(t), L(t - st)...L(t - N * st))

Nous pourrions ajouter d'autres variables à cette fonction, telles que l'heure, les jours de la semaine, les mois et les semaines, mais cela produirait un grand nombre de fonctions liées à des zones de marché spécifiques, alors que notre objectif est de déterminer la physique générale du marché. Nous saurons qu'elle ne peut être brisée et qu'elle peut donc être utilisée tant que le marché existe. Un autre avantage de la formule est sa nature multidevise.

En termes pratiques, l'utilisation de ce type de représentation n'a pas de sens, puisque nous devons savoir exactement comment et sur la base de quelles données construire cette fonction. Nous ne pouvons pas nous contenter d'écrire la forme de cette fonction et de déterminer ses dépendances. Mais ces expressions peuvent nous aider à acquérir une première compréhension de la manière d'analyser et de passer aux hypothèses suivantes. Tout ensemble de conditions logiques peut finalement être représenté sous la forme d'une telle fonction. Inversement, la fonction elle-même peut être transformée en un ensemble de conditions. La forme que nous utilisons n'a pas d'importance. Il est seulement important de la comprendre. Tout algorithme peut être réduit à une formule unique. Il est parfois plus facile de décrire les signaux comme des conditions ou un système de conditions que de construire une fonction super-complexe. Une autre grande question est de savoir comment construire une telle fonction.

Dans un système de trading réel, nous ne pouvons pas analyser l'ensemble de l'historique en une seule fois, mais seulement pour une période de temps déterminée. Il existe 4 approches possibles pour cette analyse. Je vais leur donner des noms et vous les expliquer :

  • Formules (indicateurs ou leurs fonctions)
  • Simulation
  • Mathématiques générales
  • Types d'apprentissage automatique

La première option suppose que nous utilisions une certaine valeur ou un ensemble de valeurs. Il peut s'agir par exemple d'un indicateur ou de notre propre formule. L'avantage de cette approche est la disponibilité d'une large gamme d'outils dans les terminaux MetaTrader 4/5. Il existe également un grand nombre d'indicateurs basés sur des théories de marché populaires, disponibles sur le marché et sur le web. L'inconvénient de cette approche est que, dans la plupart des cas, nous ne comprendrons pas à partir de quoi l'indicateur fonctionne. Même si nous le comprenons, cette compréhension n'a aucune valeur.

Dans la deuxième option, nous n'utilisons pas les données que nous ne comprenons pas ou qui ne sont pas utiles. Au lieu de cela, nous pouvons essayer de simuler des ordres sur le marché et nous saurons ainsi que notre système sera capable, dans une certaine mesure, de décrire combien de positions sont ouvertes dans une direction et combien dans l'autre. Ces informations peuvent produire les prévisions nécessaires, permettant une description fine du marché dans une perspective globale. C'est la seule alternative à l'apprentissage automatique.

Par mathématiques, on entend la compréhension de certaines lois fondamentales ou la connaissance de certains principes mathématiques qui permettent d'exploiter n'importe quelle cotation, quelle que soit la situation actuelle du marché. Le fait est que toutes les fonctions, y compris les fonctions discrètes, présentent certaines caractéristiques qui peuvent être exploitées. Bien sûr, nous supposons ici que la dépendance n'est pas chaotique (dans notre cas, le forex n'est pas chaotique, de sorte que toute cotation peut être exploitée). Dans le prochain article, nous analyserons l'un de ces principes, que presque tout le monde connaît. Mais savoir et pouvoir utiliser sont deux choses différentes. L'avantage de cette approche est que si nous parvenons à construire un système performant, nous n'aurons pas à nous préoccuper de son comportement futur. 

La quatrième approche est la plus progressiste, car l'apprentissage automatique peut tirer le meilleur parti de n'importe quelle donnée. Plus la puissance de calcul est importante, plus la qualité de l'analyse est élevée. L'inconvénient de cette approche est qu'elle ne permet pas de comprendre la physique du marché. L'avantage est la simplicité de l'approche, la qualité maximale des résultats avec un minimum de temps. Mais cette approche n'est pas applicable dans le cadre de cet article.


À propos des Modèles

Le trading quotidien implique de nombreux termes, chacun ayant un niveau d'importance différent. Certains termes sont très souvent utilisés, mais tous les traders ne comprennent pas leur véritable objectif. L'un de ces termes est le Modèle. Je vais essayer de l'expliquer dans le langage des mathématiques. Un modèle est toujours lié à une période de temps spécifique, à une paire de devises et à une période graphique spécifiques. Certains modèles sont puissants. Ces modèles peuvent être multidevises ou mondiaux. Le modèle idéal est le Graal. Certaines affirmations peuvent s'appliquer à n'importe quel modèle :

  • L'existence d'une formule ou d'un ensemble de conditions qui symbolise le modèle
  • Des valeurs de test minimales dans le testeur de stratégie ou des valeurs de performance sur un compte démo ou réel
  • La classification d'un modèle en termes de performance pour toutes les paires de devises et périodes graphiques
  • La période de l'historique au cours de laquelle le modèle a été identifié
  • L’intervalle de temps dans le futur, pendant lequel le modèle reste opérationnel
  • La deuxième période de temps dans le futur, suivant la première, pendant laquelle le modèle original conserve certains paramètres ou les inverse.

Si vous lisez attentivement chaque propriété, vous comprendrez qu'un modèle est une formule ou un ensemble de conditions qui décrivent le plus précisément possible l'évolution des prix à des intervalles choisis. Un modèle peut s'avérer aléatoire, surtout s'il est trouvé sur une période trop courte ou si le système concerné produit des valeurs trop optimistes. Il est très important de comprendre que lorsqu'on teste un système sur de courtes périodes, les chances de trouver des modèles globaux tendent vers zéro. Ceci est lié à la taille de l'échantillon. Plus l'échantillon est petit, plus les résultats sont aléatoires. 

Nous avons déterminé ce qu'est un modèle. Mais comment utiliser efficacement les modèles ? Tout dépend de la manière dont ce modèle a été trouvé et de sa qualité. Si nous ne tenons pas compte des méthodes d'analyse utilisant la puissance de calcul, nous en arrivons à l'analyse. À mon avis, l'analyse ne peut rivaliser avec aucun type d'analyse automatique - même une bonne équipe d'analystes ne peut pas traiter les données qui peuvent être traitées par une seule machine. Quoi qu'il en soit, le processus de recherche de modèles globaux nécessite de la puissance de calcul. Sauf dans le cas où vous avez vu des choses évidentes de vos propres yeux et compris leur dynamique.


Écrire le Plus Simple des Simulateurs de Position

Afin d'essayer de trouver des modèles globaux, il serait intéressant de développer un Expert Advisor capable de décrire l'humeur des acteurs du marché. Pour cela, j'ai décidé d'essayer de créer un simulateur de positions de marché. Les positions seront simulées à l'intérieur des barres proches du bord du marché. Il faudra supposer que les acteurs du marché sont différents et que le poids de leurs ordres est également différent. Cela doit aussi être présenté sous une forme simple. Si un simple prototype s'avère rentable, ses principes peuvent être utilisés ultérieurement.

La logique sera conditionnellement divisée en 3 simulations distinctes et en toute combinaison possible de celles-ci :

  • Simulation des ordres stop
  • Simulation des ordres à cours limité
  • Simulation des ordres de marché
  • Toutes les combinaisons possibles

La logique suivante sera utilisée pour passer les ordres :

Logique de la Grille des Ordres

Ces grilles sont placées à chaque nouvelle barre dans le but de simuler l'humeur d'une partie des participants au marché. Le statut des grilles des anciens ordres est mis à jour en fonction de la nouvelle barre qui apparaît sur le graphique. Cette approche n'est pas très précise, mais la simulation tick par tick conduirait à des calculs interminables. Et en plus je ne fais pas vraiment confiance aux ticks.

Il existe deux types de distribution des volumes relatifs, avec atténuation et uniforme, mais uniquement pour les ordres Stop et Limit. Les ordres de marché ont une distribution uniforme. Il sera également possible d'élargir les types de distribution, si cela est mis en perspective. Voici l'illustration :

Types de Remplissage Volumes Relatifs

Ici, la longueur de la ligne symbolisant l'ordre est proportionnelle à son volume. Je pense que ce genre d’illustrations seront simples et compréhensibles pour tout le monde.

Dans ce cas, tout peut être fait en utilisant une approche orientée objet. Commençons par décrire les listes numérotées :

enum CLOSE_MODE// how to close orders
   {
   CLOSE_FAST,// fast
   CLOSE_QUALITY// wait for an opposite signal
   };

enum WORK_MODE// operation mode
   {
   MODE_SIMPLE,// slow mode
   MODE_FAST// fast mode
   };

enum ENUM_GRID_WEIGHT//weight fill type for limit and stop orders
   {
   WEIGHT_DECREASE,// with attenuation if moving from the price
   WEIGHT_SAME// the same for the entire grid
   };

enum ENUM_STATUS_ORDER// statuses of orders or positions
   {
   STATUS_VIRTUAL,// stop or limit order
   STATUS_MARKET,// market order
   STATUS_ABORTED// canceled stop or limit order
   };

Le simulateur fonctionnera en 2 modes : lent et rapide. Le mode lent est principalement nécessaire pour commencer l'analyse. Dans l'analyse de départ, le calcul est effectué dans le premier "n" le plus proche des chandeliers du marché. En mode rapide, le calcul est effectué uniquement sur le dernier chandelier apparu. Mais cette approche simple s'avère insuffisante. Une fonctionnalité supplémentaire est nécessaire pour augmenter la vitesse de l'algorithme. Un calcul assez important est effectué lors de l'initialisation de l’Expert Advisor. Mais nous n'avons ensuite besoin que de mettre à jour la simulation pour le nouveau chandelier, à chaque chandelier. Il y aura 2 types de distribution de volume, pour les ordres limites et les ordres stop, en fonction de la distance par rapport au prix actuel du marché, Open[i] pour chaque barre. En effet, une grille d'ordres stop et limit est ouverte à chaque barre, avec des distributions et des pondérations différentes. Après un certain temps, les ordres stop et limit se transforment en ordres de marché. Si le prix n'atteint pas le prix désiré pendant le temps spécifié, les ordres stop et limit sont annulés.

Commençons par construire cette simulation, du plus simple au plus complexe, en assemblant progressivement tous les éléments. Tout d'abord, définissons ce qu'est un ordre :

struct Order// structure symbolizing a player's order
   {
   public:
   double WantedPrice;// desired open price
   int BarsExpirationOpen;// If the order remains for certain number of bars, the player can't wait any more and cancels the order
   int BarsExpirationClose;//If this is a market order and the player does not want to wait, he closes the position
   double UpPriceToClose;//The total upward price movement at which the player closes the order (points)
   double LowPriceToClose;//The total downward price movement at which the player closes the order 
   double VolumeAlpha;// current volume equivalent [0...1]
   double VolumeStart;// starting volume equivalent [0...1]
   int IndexMarket;// the index of the bar on which the virtual market turned into market
   ENUM_STATUS_ORDER Status;// order status
   Order(ENUM_STATUS_ORDER S)// constructor that creates a certain order
      {
      Status=S;
      }
   };

Les paramètres sont peu nombreux et chacun d'entre eux est important pour l'algorithme général. De nombreux champs s'appliquent à tous les ordres, alors que d'autres ne s'appliquent qu'aux ordres à cours limité ou aux ordres stop. Par exemple, le prix souhaité est le prix d’ouverture pour un ordre au marché, alors qu'il est exactement le prix souhaité pour les ordres à cours limité et pour les ordres stop.

Les prix de clôture supérieur et inférieur servent de niveaux d'arrêt. Nous supposerons en même temps que l'ordre en grille n'est pas tout à fait un ordre, et que cet ordre contient toute une série d'ordres, alors qu'ils fusionnent simplement en un seul ordre, qui est ouvert avec un certain volume à un certain prix. Les variables du volume de départ et du volume actuel nous indiquent l'importance des ordres d'une barre spécifique à un niveau spécifique.

Le volume de départ est le volume au moment du passage de l’ordre. Le volume actuel est le volume au fur et à mesure que les événements se développent. Ce qui est important, c'est le rapport entre les volumes d'ordres d'achat et de vente plutôt que les bénéfices réalisés sur certains ordres. Les signaux de trading seront générés sur la base de ces considérations. Nous pourrions bien sûr trouver d'autres signaux, mais cela nécessite d'autres considérations. Notez également que les ordres ne seront pas fermés lorsqu'ils atteignent certains niveaux, mais que la fermeture se fera progressivement à chaque barre, dans un effort pour simuler le plus possible le développement réel des événements.

Nous devons ensuite définir le stockage de chaque barre. La barre stocke les ordres qui s'ouvrent à cette barre :

class OrderBox// Order box of a specific bar
   {
   public:
   Order BuyStopOrders[];
   Order BuyLimitOrders[];
   Order BuyMarketOrders[];
   Order SellStopOrders[];
   Order SellLimitOrders[];
   Order SellMarketOrders[];
   
   OrderBox(int OrdersToOneBar)
      {
      ArrayResize(BuyStopOrders,OrdersToOneBar);
      ArrayResize(BuyLimitOrders,OrdersToOneBar);
      ArrayResize(BuyMarketOrders,OrdersToOneBar);
      ArrayResize(SellStopOrders,OrdersToOneBar);
      ArrayResize(SellLimitOrders,OrdersToOneBar);
      ArrayResize(SellMarketOrders,OrdersToOneBar);      
      for ( int i=0; i<ArraySize(BuyStopOrders); i++ )// Set types for all orders
         {
         BuyStopOrders[i]=Order(STATUS_VIRTUAL);
         BuyLimitOrders[i]=Order(STATUS_VIRTUAL);
         BuyMarketOrders[i]=Order(STATUS_MARKET);
         SellStopOrders[i]=Order(STATUS_VIRTUAL);
         SellLimitOrders[i]=Order(STATUS_VIRTUAL);
         SellMarketOrders[i]=Order(STATUS_MARKET);         
         }
      }
   };

Ici, tout est très simple. Six types d'ordres, décrits par des tableaux. Ceci permet d'éviter toute confusion. La classe ne sera pas utilisée dans sa forme pure, car elle n'est qu'une brique dans la construction.

Définissions ensuite le stockage commun de toutes les barres sous la forme d'un objet unique, à partir duquel l'héritage sera effectué ultérieurement. Les techniques utilisées ici sont très simples.

class BarBox// Storage for all orders
   {
   protected:
   OrderBox BarOrders[];
   
   BarBox(int OrdersToOneBar,int BarsTotal)
      {
      ArrayResize(BarOrders,BarsTotal);
      for ( int i=0; i<ArraySize(BarOrders); i++ )// Set types for all orders
         {
         BarOrders[i]=OrderBox(OrdersToOneBar);
         }
      }   
   };

Il s'agit simplement d'un stockage de données sur les barres (ordres) et rien de plus. Jusqu'à présent, tout est assez simple. Mais les choses se compliquent ensuite.

Une fois que nous avons déterminé un stockage pratique des données pour les ordres, nous devons déterminer comment et selon quelles règles les ordres sont créés, quelle est l'importance de certains types d'ordres, etc. J'ai créé la classe suivante pour cela :

class PositionGenerator:public BarBox// Inherit class from the box to avoid the need to include it as an internal member and to avoid multiple references
   {
   protected:
   double VolumeAlphaStop;// importance of volumes of STOP orders
   double VolumeAlphaLimit;// importance of volumes of LIMIT orders
   double VolumeAlphaMarket;// importance of volumes of MARKET orders
   double HalfCorridorLimitStop;// step of the corridor of Limit and Stop orders in points
   int ExpirationOpenLimit;// after how many bars the volumes of the grid of limit orders for opening will completely attenuate
   int ExpirationOpenStop;// after how many bars the volumes of the grid of stop orders for opening will completely attenuate
   int ExpirationClose;// after how many bars the volumes of orders for closing will completely attenuate
   int ProfitPointsCorridorPart;// half corridor size for the profit of all orders
   int LossPointsCorridorPart;// half corridor size for the loss of all orders
   int OrdersToOneBar;// orders of one type per 1 bar
   ENUM_GRID_WEIGHT WeightStopLimitFillingType;
   
   PositionGenerator( ENUM_GRID_WEIGHT WeightStopLimitFillingType0
                     ,int HalfCorridorLimitStop0,int OrdersToOneBar0,int BarsTotal0
                     ,int ExpirationOpenLimit0,int ExpirationOpenStop0
                     ,int ExpirationClose0
                     ,int ProfitPointsCorridorPart0,int LossPointsCorridorPart0
                     ,double VolumeAlphaStop0,double VolumeAlphaLimit0,double VolumeAlphaMarket0) 
                     : BarBox(OrdersToOneBar0,BarsTotal0)
      {
      VolumeAlphaStop=VolumeAlphaStop0;
      VolumeAlphaLimit=VolumeAlphaLimit0;
      VolumeAlphaMarket=VolumeAlphaMarket0;
      OrdersToOneBar=OrdersToOneBar0;
      HalfCorridorLimitStop=double(HalfCorridorLimitStop0)/double(OrdersToOneBar);
      ExpirationOpenLimit=ExpirationOpenLimit0;
      ExpirationOpenStop=ExpirationOpenStop0;
      ExpirationClose=ExpirationClose0;
      ProfitPointsCorridorPart=ProfitPointsCorridorPart0;
      LossPointsCorridorPart=LossPointsCorridorPart0;
      OrdersToOneBar=OrdersToOneBar0;
      WeightStopLimitFillingType=WeightStopLimitFillingType0;
      }
   private:
   
   double CalcVolumeDecrease(double TypeWeight,int i,int size)// attenuation volume
      {
      if ( size > 1 )
         {
         double K=1.0/(1.0-size);
         double C=1.0;
         return TypeWeight*K*i+C;
         }
      else return 0.0;
      }
      
   double CalcVolumeSimple(double TypeWeight)// equal volume
      {
      return TypeWeight;
      }
   
   void RebuildStops()// rebuild stop orders
      {
      int size=ArraySize(BarOrders[0].BuyStopOrders);
      for ( int j=ArraySize(BarOrders)-1; j>=0; j-- )
         {
         for ( int i=0; i<size; i++ )// reset all
            {
            BarOrders[j].BuyStopOrders[i].Status=STATUS_VIRTUAL;// reset status to initial
            BarOrders[j].BuyStopOrders[i].WantedPrice=Open[j+1]+HalfCorridorLimitStop*(i+1)*Point;// prices of the order grid
            if ( WeightStopLimitFillingType == WEIGHT_DECREASE ) BarOrders[j].BuyStopOrders[i].VolumeAlpha=CalcVolumeDecrease(VolumeAlphaStop,i,size);// weight of each element of the grid
            if ( WeightStopLimitFillingType == WEIGHT_SAME ) BarOrders[j].BuyStopOrders[i].VolumeAlpha=CalcVolumeSimple(VolumeAlphaStop);// current weight of each element of the grid
            BarOrders[j].BuyStopOrders[i].VolumeStart=BarOrders[j].BuyStopOrders[i].VolumeAlpha;// starting weight of each element of the grid
            BarOrders[j].BuyStopOrders[i].UpPriceToClose=BarOrders[j].BuyStopOrders[i].WantedPrice+ProfitPointsCorridorPart*Point;// upper border to close
            BarOrders[j].BuyStopOrders[i].LowPriceToClose=BarOrders[j].BuyStopOrders[i].WantedPrice-LossPointsCorridorPart*Point;// lower border to close
            BarOrders[j].BuyStopOrders[i].BarsExpirationOpen=ExpirationOpenStop;
            BarOrders[j].BuyStopOrders[i].BarsExpirationClose=ExpirationClose;
       
            BarOrders[j].SellStopOrders[i].Status=STATUS_VIRTUAL;
            BarOrders[j].SellStopOrders[i].WantedPrice=Open[j+1]-HalfCorridorLimitStop*(i+1)*Point;// prices of the order grid
            if ( WeightStopLimitFillingType == WEIGHT_DECREASE ) BarOrders[j].SellStopOrders[i].VolumeAlpha=CalcVolumeDecrease(VolumeAlphaStop,i,size);// weight of each element of the grid
            if ( WeightStopLimitFillingType == WEIGHT_SAME ) BarOrders[j].SellStopOrders[i].VolumeAlpha=CalcVolumeSimple(VolumeAlphaStop);// current weight of each element of the grid
            BarOrders[j].SellStopOrders[i].VolumeStart=BarOrders[j].SellStopOrders[i].VolumeAlpha;// starting weight of each element of the grid
            BarOrders[j].SellStopOrders[i].UpPriceToClose=BarOrders[j].SellStopOrders[i].WantedPrice+LossPointsCorridorPart*Point;// upper border to close
            BarOrders[j].SellStopOrders[i].LowPriceToClose=BarOrders[j].SellStopOrders[i].WantedPrice-ProfitPointsCorridorPart*Point;// lower border to close
            BarOrders[j].SellStopOrders[i].BarsExpirationOpen=ExpirationOpenStop;
            BarOrders[j].SellStopOrders[i].BarsExpirationClose=ExpirationClose;                    
            }         
         }      
      }
      
   void RebuildLimits()// rebuild limit orders
      {
      int size=ArraySize(BarOrders[0].BuyLimitOrders);
      for ( int j=ArraySize(BarOrders)-1; j>=0; j-- )
         {
         for ( int i=0; i<size; i++ )// reset all
            {
            BarOrders[j].BuyLimitOrders[i].Status=STATUS_VIRTUAL;// reset status to initial
            BarOrders[j].BuyLimitOrders[i].WantedPrice=Open[j+1]-HalfCorridorLimitStop*(i+1)*Point;// prices of the order grid
            if ( WeightStopLimitFillingType == WEIGHT_DECREASE ) BarOrders[j].BuyLimitOrders[i].VolumeAlpha=CalcVolumeDecrease(VolumeAlphaLimit,i,size);// weight of each element of the grid
            if ( WeightStopLimitFillingType == WEIGHT_SAME ) BarOrders[j].BuyLimitOrders[i].VolumeAlpha=CalcVolumeSimple(VolumeAlphaLimit);// current weight of each element of the grid
            BarOrders[j].BuyLimitOrders[i].VolumeStart=BarOrders[j].BuyLimitOrders[i].VolumeAlpha;// starting weight of each element of the grid
            BarOrders[j].BuyLimitOrders[i].UpPriceToClose=BarOrders[j].BuyLimitOrders[i].WantedPrice+ProfitPointsCorridorPart*Point;// upper border to close
            BarOrders[j].BuyLimitOrders[i].LowPriceToClose=BarOrders[j].BuyLimitOrders[i].WantedPrice-LossPointsCorridorPart*Point;// lower border to close
            BarOrders[j].BuyLimitOrders[i].BarsExpirationOpen=ExpirationOpenLimit;
            BarOrders[j].BuyLimitOrders[i].BarsExpirationClose=ExpirationClose;            
       
            BarOrders[j].SellLimitOrders[i].Status=STATUS_VIRTUAL;
            BarOrders[j].SellLimitOrders[i].WantedPrice=Open[j+1]+HalfCorridorLimitStop*(i+1)*Point;// prices of the order grid
            if ( WeightStopLimitFillingType == WEIGHT_DECREASE ) BarOrders[j].SellLimitOrders[i].VolumeAlpha=CalcVolumeDecrease(VolumeAlphaLimit,i,size);// weight of each element of the grid
            if ( WeightStopLimitFillingType == WEIGHT_SAME ) BarOrders[j].SellLimitOrders[i].VolumeAlpha=CalcVolumeSimple(VolumeAlphaLimit);// current weight of each element of the grid
            BarOrders[j].SellLimitOrders[i].VolumeStart=BarOrders[j].SellLimitOrders[i].VolumeAlpha;// starting weight of each element of the grid
            BarOrders[j].SellLimitOrders[i].UpPriceToClose=BarOrders[j].SellLimitOrders[i].WantedPrice+LossPointsCorridorPart*Point;// upper border to close
            BarOrders[j].SellLimitOrders[i].LowPriceToClose=BarOrders[j].SellLimitOrders[i].WantedPrice-ProfitPointsCorridorPart*Point;// lower border to close
            BarOrders[j].SellLimitOrders[i].BarsExpirationOpen=ExpirationOpenLimit;
            BarOrders[j].SellLimitOrders[i].BarsExpirationClose=ExpirationClose;
            }         
         }      
      }
      
   void RebuildMarkets()// rebuild market orders
      {
      int size=ArraySize(BarOrders[0].BuyMarketOrders);
      double MarketStep;
      for ( int j=ArraySize(BarOrders)-1; j>0; j-- )
         {
         MarketStep=(High[j+1]-Low[j+1])/double(OrdersToOneBar);
            
         for ( int i=0; i<size; i++ )// reset all
            {
            BarOrders[j].BuyMarketOrders[i].Status=STATUS_MARKET;// reset status to initial
            BarOrders[j].BuyMarketOrders[i].WantedPrice=Low[j+1]+MarketStep*i;// prices of the order grid
            BarOrders[j].BuyMarketOrders[i].VolumeAlpha=CalcVolumeSimple(VolumeAlphaMarket);// current weight of each element of the grid
            BarOrders[j].BuyMarketOrders[i].VolumeStart=BarOrders[j].BuyMarketOrders[i].VolumeAlpha;// starting weight of each element of the grid
            BarOrders[j].BuyMarketOrders[i].UpPriceToClose=BarOrders[j].BuyMarketOrders[i].WantedPrice+ProfitPointsCorridorPart*Point;// upper border to close
            BarOrders[j].BuyMarketOrders[i].LowPriceToClose=BarOrders[j].BuyMarketOrders[i].WantedPrice-LossPointsCorridorPart*Point;// lower border to close
            BarOrders[j].BuyMarketOrders[i].BarsExpirationClose=ExpirationClose;
               
            BarOrders[j].SellMarketOrders[i].Status=STATUS_MARKET;
            BarOrders[j].SellMarketOrders[i].WantedPrice=High[j+1]-MarketStep*i;// prices of the order grid
            BarOrders[j].SellMarketOrders[i].VolumeAlpha=CalcVolumeSimple(VolumeAlphaMarket);// current weight of each element of the grid
            BarOrders[j].SellMarketOrders[i].VolumeStart=BarOrders[j].SellMarketOrders[i].VolumeAlpha;// starting weight of each element of the grid
            BarOrders[j].SellMarketOrders[i].UpPriceToClose=BarOrders[j].SellMarketOrders[i].WantedPrice+LossPointsCorridorPart*Point;// upper border to close
            BarOrders[j].SellMarketOrders[i].LowPriceToClose=BarOrders[j].SellMarketOrders[i].WantedPrice-ProfitPointsCorridorPart*Point;// lower border to close
            BarOrders[j].SellMarketOrders[i].BarsExpirationClose=ExpirationClose;
            } 
         }      
      }

   ///// Fast methods
   void RebuildStopsFast()// rebuild stop orders
      {
      int size=ArraySize(BarOrders[0].BuyStopOrders);
      for ( int j=ArraySize(BarOrders)-1; j>0; j-- )
         {
         for ( int i=0; i<size; i++ )// shift orders
            {
            BarOrders[j].BuyStopOrders[i]=BarOrders[j-1].BuyStopOrders[i];
            BarOrders[j].SellStopOrders[i]=BarOrders[j-1].SellStopOrders[i];
            BarOrders[j].SellStopOrders[i].IndexMarket++;
            }
         }
         
      for ( int i=0; i<size; i++ )// create a new grid at a new bar
         {
         BarOrders[0].BuyStopOrders[i].Status=STATUS_VIRTUAL;// reset status to initial
         BarOrders[0].BuyStopOrders[i].WantedPrice=Close[1]+HalfCorridorLimitStop*(i+1)*Point;// prices of the order grid
         if ( WeightStopLimitFillingType == WEIGHT_DECREASE ) BarOrders[0].BuyStopOrders[i].VolumeAlpha=CalcVolumeDecrease(VolumeAlphaStop,i,size);// weight of each element of the grid
         if ( WeightStopLimitFillingType == WEIGHT_SAME ) BarOrders[0].BuyStopOrders[i].VolumeAlpha=CalcVolumeSimple(VolumeAlphaStop);// current weight of each element of the grid
         BarOrders[0].BuyStopOrders[i].VolumeStart=BarOrders[0].BuyStopOrders[i].VolumeAlpha;// starting weight of each element of the grid
         BarOrders[0].BuyStopOrders[i].UpPriceToClose=BarOrders[0].BuyStopOrders[i].WantedPrice+ProfitPointsCorridorPart*Point;//upper border to close
         BarOrders[0].BuyStopOrders[i].LowPriceToClose=BarOrders[0].BuyStopOrders[i].WantedPrice-LossPointsCorridorPart*Point;// lower border to close
         BarOrders[0].BuyStopOrders[i].BarsExpirationOpen=ExpirationOpenStop;
         BarOrders[0].BuyStopOrders[i].BarsExpirationClose=ExpirationClose;
       
         BarOrders[0].SellStopOrders[i].Status=STATUS_VIRTUAL;
         BarOrders[0].SellStopOrders[i].WantedPrice=Close[1]-HalfCorridorLimitStop*(i+1)*Point;// prices of the order grid
         if ( WeightStopLimitFillingType == WEIGHT_DECREASE ) BarOrders[0].SellStopOrders[i].VolumeAlpha=CalcVolumeDecrease(VolumeAlphaStop,i,size);// weight of each element of the grid
         if ( WeightStopLimitFillingType == WEIGHT_SAME ) BarOrders[0].SellStopOrders[i].VolumeAlpha=CalcVolumeSimple(VolumeAlphaStop);// current weight of each element of the grid
         BarOrders[0].SellStopOrders[i].VolumeStart=BarOrders[0].SellStopOrders[i].VolumeAlpha;// starting weight of each element of the grid
         BarOrders[0].SellStopOrders[i].UpPriceToClose=BarOrders[0].SellStopOrders[i].WantedPrice+LossPointsCorridorPart*Point;// upper border to close
         BarOrders[0].SellStopOrders[i].LowPriceToClose=BarOrders[0].SellStopOrders[i].WantedPrice-ProfitPointsCorridorPart*Point;// lower border to close
         BarOrders[0].SellStopOrders[i].BarsExpirationOpen=ExpirationOpenStop;
         BarOrders[0].SellStopOrders[i].BarsExpirationClose=ExpirationClose;                    
         }               
      }
      
   void RebuildLimitsFast()// rebuild limit orders
      {
      int size=ArraySize(BarOrders[0].BuyLimitOrders);
      for ( int j=ArraySize(BarOrders)-1; j>0; j-- )
         {
         for ( int i=0; i<size; i++ )// shift orders
            {
            BarOrders[j].BuyLimitOrders[i]=BarOrders[j-1].BuyLimitOrders[i];
            BarOrders[j].SellLimitOrders[i]=BarOrders[j-1].SellLimitOrders[i];
            BarOrders[j].SellLimitOrders[i].IndexMarket++;
            }         
         }
      
      for ( int i=0; i<size; i++ )// create a new grid at a new bar
         {
         BarOrders[0].BuyLimitOrders[i].Status=STATUS_VIRTUAL;// reset status to initial
         BarOrders[0].BuyLimitOrders[i].WantedPrice=Open[1]-HalfCorridorLimitStop*(i+1)*Point;// prices of the order grid
         if ( WeightStopLimitFillingType == WEIGHT_DECREASE ) BarOrders[0].BuyLimitOrders[i].VolumeAlpha=CalcVolumeDecrease(VolumeAlphaLimit,i,size);// weight of each element of the grid
         if ( WeightStopLimitFillingType == WEIGHT_SAME ) BarOrders[0].BuyLimitOrders[i].VolumeAlpha=CalcVolumeSimple(VolumeAlphaLimit);// current weight of each element of the grid
         BarOrders[0].BuyLimitOrders[i].VolumeStart=BarOrders[0].BuyLimitOrders[i].VolumeAlpha;// starting weight of each element of the grid
         BarOrders[0].BuyLimitOrders[i].UpPriceToClose=BarOrders[0].BuyLimitOrders[i].WantedPrice+ProfitPointsCorridorPart*Point;// upper border to close
         BarOrders[0].BuyLimitOrders[i].LowPriceToClose=BarOrders[0].BuyLimitOrders[i].WantedPrice-LossPointsCorridorPart*Point;// lower border to close
         BarOrders[0].BuyLimitOrders[i].BarsExpirationOpen=ExpirationOpenLimit;
         BarOrders[0].BuyLimitOrders[i].BarsExpirationClose=ExpirationClose;            
       
         BarOrders[0].SellLimitOrders[i].Status=STATUS_VIRTUAL;
         BarOrders[0].SellLimitOrders[i].WantedPrice=Open[1]+HalfCorridorLimitStop*(i+1)*Point;// prices of the order grid
         if ( WeightStopLimitFillingType == WEIGHT_DECREASE ) BarOrders[0].SellLimitOrders[i].VolumeAlpha=CalcVolumeDecrease(VolumeAlphaLimit,i,size);// weight of each element of the grid
         if ( WeightStopLimitFillingType == WEIGHT_SAME ) BarOrders[0].SellLimitOrders[i].VolumeAlpha=CalcVolumeSimple(VolumeAlphaLimit);// current weight of each element of the grid
         BarOrders[0].SellLimitOrders[i].VolumeStart=BarOrders[0].SellLimitOrders[i].VolumeAlpha;// starting weight of each element of the grid
         BarOrders[0].SellLimitOrders[i].UpPriceToClose=BarOrders[0].SellLimitOrders[i].WantedPrice+LossPointsCorridorPart*Point;// upper border to close
         BarOrders[0].SellLimitOrders[i].LowPriceToClose=BarOrders[0].SellLimitOrders[i].WantedPrice-ProfitPointsCorridorPart*Point;// lower order to close
         BarOrders[0].SellLimitOrders[i].BarsExpirationOpen=ExpirationOpenLimit;
         BarOrders[0].SellLimitOrders[i].BarsExpirationClose=ExpirationClose;
         }        
      }
      
   void RebuildMarketsFast()// rebuild market orders
      {
      int size=ArraySize(BarOrders[0].BuyMarketOrders);
      double MarketStep;
      for ( int j=ArraySize(BarOrders)-1; j>0; j-- )
         {
         for ( int i=0; i<size; i++ )// shift orders
            {
            BarOrders[j].BuyMarketOrders[i]=BarOrders[j-1].BuyMarketOrders[i];
            BarOrders[j].SellMarketOrders[i]=BarOrders[j-1].SellMarketOrders[i];
            }         
         }
      MarketStep=(High[1]-Low[1])/double(OrdersToOneBar);
      for ( int i=0; i<size; i++ )// create a new grid at a new bar
         {
         BarOrders[0].BuyMarketOrders[i].Status=STATUS_MARKET;// reset status to initial
         BarOrders[0].BuyMarketOrders[i].WantedPrice=Low[1]+MarketStep*i;// prices of the order grid
         BarOrders[0].BuyMarketOrders[i].VolumeAlpha=CalcVolumeSimple(VolumeAlphaMarket);// current weight of each element of the grid
         BarOrders[0].BuyMarketOrders[i].VolumeStart=BarOrders[0].BuyMarketOrders[i].VolumeAlpha;// starting weight of each element of the grid
         BarOrders[0].BuyMarketOrders[i].UpPriceToClose=BarOrders[0].BuyMarketOrders[i].WantedPrice+ProfitPointsCorridorPart*Point;// upper border to close
         BarOrders[0].BuyMarketOrders[i].LowPriceToClose=BarOrders[0].BuyMarketOrders[i].WantedPrice-LossPointsCorridorPart*Point;// lower border to close
         BarOrders[0].BuyMarketOrders[i].BarsExpirationClose=ExpirationClose;
               
         BarOrders[0].SellMarketOrders[i].Status=STATUS_MARKET;
         BarOrders[0].SellMarketOrders[i].WantedPrice=High[1]-MarketStep*i;// prices of the order grid
         BarOrders[0].SellMarketOrders[i].VolumeAlpha=CalcVolumeSimple(VolumeAlphaMarket);// current weight of each element of the grid
         BarOrders[0].SellMarketOrders[i].VolumeStart=BarOrders[0].SellMarketOrders[i].VolumeAlpha;// starting weight of each element of the grid
         BarOrders[0].SellMarketOrders[i].UpPriceToClose=BarOrders[0].SellMarketOrders[i].WantedPrice+LossPointsCorridorPart*Point;// upper border to close
         BarOrders[0].SellMarketOrders[i].LowPriceToClose=BarOrders[0].SellMarketOrders[i].WantedPrice-ProfitPointsCorridorPart*Point;// lower border to close
         BarOrders[0].SellMarketOrders[i].BarsExpirationClose=ExpirationClose;
         }         
      }   
   
   protected:
   void CreateNewOrders()// create new orders at each candlestick
      {
      if ( VolumeAlphaStop != 0.0 ) RebuildStops();
      if ( VolumeAlphaLimit != 0.0 ) RebuildLimits();
      if ( VolumeAlphaMarket != 0.0 ) RebuildMarkets();
      }
   
   void CreateNewOrdersFast()//
      {
      if ( VolumeAlphaStop != 0.0 ) RebuildStopsFast();
      if ( VolumeAlphaLimit != 0.0 ) RebuildLimitsFast();
      if ( VolumeAlphaMarket != 0.0 ) RebuildMarketsFast();      
      }
   
   public:   
   virtual void Update()// state updating function (will be expanded in child classes)
      {
      CreateNewOrders();
      }
      
   virtual void UpdateFast()// fast state update
      {
      CreateNewOrdersFast();
      }      
   };

En fait, cette classe ne crée qu'une implémentation des méthodes Update() et UpdateFast(), qui sont similaires, à la seule différence que la dernière est beaucoup plus rapide. Ces méthodes créent de nouveaux ordres à chaque barre et suppriment les anciens, préparant ainsi les données pour la classe suivante qui simulera le cycle de vie des ordres. Tous les paramètres requis pour les ordres sont affectés dans cette classe, y compris le type, les prix d’ouvertures, les volumes et d'autres paramètres importants nécessaires pour la suite des opérations.

La classe suivante met en œuvre le processus de simulation des ordres, ainsi que les calculs des paramètres nécessaires au trading, sur la base desquels les signaux sont générés :

class Simulation:public PositionGenerator // then assemble a simulator of positions (inherited from the position generator)
   {// market parameter calculations will also performed in this class
   protected:
   double BuyPercent;// percent of open Buy positions
   double SellPercent;// percent of open Sell positions
   double StartVolume;// starting total volume of open Buy positions (the same for Buys and Sells)
   double RelativeVolume;// relative volume
   double SummVolumeBuy;// total volume for Buys
   double SummVolumeSell;// total volume for Sells
   
   public:   
   Simulation( ENUM_GRID_WEIGHT WeightStopLimitFillingType0
                     ,int HalfCorridorLimitStop0,int OrdersToOneBar0,int BarsTotal0
                     ,int ExpirationOpenLimit0,int ExpirationOpenStop0
                     ,int ExpirationClose0
                     ,int ProfitPointsCorridorPart0,int LossPointsCorridorPart0
                     ,double VolumeAlphaStop0,double VolumeAlphaLimit0,double VolumeAlphaMarket0) 
   :PositionGenerator(WeightStopLimitFillingType0
                     ,HalfCorridorLimitStop0,OrdersToOneBar0,BarsTotal0
                     ,ExpirationOpenLimit0,ExpirationOpenStop0
                     ,ExpirationClose0
                     ,ProfitPointsCorridorPart0,LossPointsCorridorPart0
                     ,VolumeAlphaStop0,VolumeAlphaLimit0,VolumeAlphaMarket0) 
      {
      CreateNewOrders();
      CalculateStartVolume();// calculate starting volumes
      UpdateVirtual();// first update virtual orders to process part of them as market orders in the next function
      UpdateMarket();// now update the state of all market orders
      CalculateCurrentVolume();// calculate current volumes of all open orders
      CalculatePercent();// calculate the percentage of positions
      CalculateRelativeVolume();// calculate relative volume
      }

   double GetBuyPercent()// get the percentage of open Buy deals
      {
      return BuyPercent;
      }
      
   double GetSellPercent()// get the percentage of open Sell deals
      {
      return SellPercent;
      }
      
   double GetRelativeVolume()// get relative volume
      {
      return RelativeVolume;
      }

   virtual void Update() override
      {
      PositionGenerator::Update();// call everything that was before
      UpdateVirtual();// first update virtual orders to process part of them as market orders in the next function
      UpdateMarket();// now update the state of all market orders
      CalculateCurrentVolume();// calculate current volumes of all open orders
      CalculatePercent();// calculate the percentage of positions
      CalculateRelativeVolume();// calculate relative volume
      }
      
   virtual void UpdateFast() override
      {
      PositionGenerator::UpdateFast();// call everything that was before
      UpdateVirtualFast();// first update virtual orders to process part of them as market orders in the next function
      UpdateMarketFast();// now update the state of all market orders
      CalculateCurrentVolume();// calculate current volumes of all open orders
      CalculatePercent();// calculate the percentage of positions
      CalculateRelativeVolume();// calculate relative volume
      }   
      
   private:
   
   void UpdateVirtual()// update the status of virtual orders
      {
      int size=ArraySize(BarOrders[0].BuyLimitOrders);
      int SizeBarOrders=ArraySize(BarOrders);
      
      if ( VolumeAlphaLimit != 0.0 )
         {
         for ( int i=SizeBarOrders; i>0; i-- )// update the state of limit orders simulating each candlestick
            {
            for ( int j=SizeBarOrders-1; j>i; j-- )// update the state of all candlesticks preceding this one
               {
               for ( int k=0; k<size; k++ )// update the state inside each preceding candlestick
                  {
                  if ( BarOrders[j].BuyLimitOrders[k].Status == STATUS_VIRTUAL 
                  && BarOrders[j].BuyLimitOrders[k].WantedPrice <= High[i] 
                  && BarOrders[j].BuyLimitOrders[k].WantedPrice >= Low[i] )// if the order is virtual and is inside a candlestick, then it turns into a market one
                     {
                     BarOrders[j].BuyLimitOrders[k].Status = STATUS_MARKET;
                     BarOrders[j].BuyLimitOrders[k].IndexMarket = i;
                     }
                  if ( BarOrders[j].SellLimitOrders[k].Status == STATUS_VIRTUAL 
                  && BarOrders[j].SellLimitOrders[k].WantedPrice <= High[i] 
                  && BarOrders[j].SellLimitOrders[k].WantedPrice >= Low[i] )// the same
                     {
                     BarOrders[j].SellLimitOrders[k].Status = STATUS_MARKET;
                     BarOrders[j].SellLimitOrders[k].IndexMarket = i;
                     } 
                 
                  /////// Check for interest expiration of limit players
                  if ( BarOrders[j].BuyLimitOrders[k].Status == STATUS_VIRTUAL )//
                     {
                     if ( BarOrders[j].BuyLimitOrders[k].IndexMarket - 1 >= BarOrders[j].BuyLimitOrders[k].BarsExpirationOpen )
                     BarOrders[j].BuyLimitOrders[k].Status=STATUS_ABORTED;
                     else
                        {
                        if ( BarOrders[j].BuyLimitOrders[k].VolumeAlpha > 0.0 )
                        BarOrders[j].BuyLimitOrders[k].VolumeAlpha-=BarOrders[j].BuyLimitOrders[k].VolumeStart/double(BarOrders[j].BuyLimitOrders[k].BarsExpirationOpen);
                        if ( BarOrders[j].BuyLimitOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].BuyLimitOrders[k].VolumeAlpha=0.0;
                        }
                     }
                  if ( BarOrders[j].SellLimitOrders[k].Status == STATUS_VIRTUAL )//
                     {
                     if ( BarOrders[j].SellLimitOrders[k].IndexMarket - 1 >= BarOrders[j].SellLimitOrders[k].BarsExpirationOpen  )
                     BarOrders[j].SellLimitOrders[k].Status=STATUS_ABORTED;
                     else
                        {
                        if ( BarOrders[j].SellLimitOrders[k].VolumeAlpha > 0.0 )
                        BarOrders[j].SellLimitOrders[k].VolumeAlpha-=BarOrders[j].SellLimitOrders[k].VolumeStart/double(BarOrders[j].SellLimitOrders[k].BarsExpirationOpen);
                        if ( BarOrders[j].SellLimitOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].SellLimitOrders[k].VolumeAlpha=0.0;                  
                        }
                     } 
                  }
               }         
            }
         }
         
      if ( VolumeAlphaStop != 0.0 )
         {
         for ( int i=SizeBarOrders; i>0; i-- )// update the state of limit orders simulating each candlestick
            {
            for ( int j=SizeBarOrders-1; j>i; j-- )// update the state of all candlesticks preceding this one
               {
               for ( int k=0; k<size; k++ )// update the state inside each preceding candlestick
                  {
                  if ( BarOrders[j].SellStopOrders[k].Status == STATUS_VIRTUAL 
                  && BarOrders[j].SellStopOrders[k].WantedPrice <= High[i] 
                  && BarOrders[j].SellStopOrders[k].WantedPrice >= Low[i] )// the same
                     {
                     BarOrders[j].SellStopOrders[k].Status = STATUS_MARKET;
                     BarOrders[j].SellStopOrders[k].IndexMarket = i;
                     }
                  if ( BarOrders[j].BuyStopOrders[k].Status == STATUS_VIRTUAL 
                  && BarOrders[j].BuyStopOrders[k].WantedPrice <= High[i] 
                  && BarOrders[j].BuyStopOrders[k].WantedPrice >= Low[i] )// the same
                     {
                     BarOrders[j].BuyStopOrders[k].Status = STATUS_MARKET;
                     BarOrders[j].BuyStopOrders[k].IndexMarket = i;
                     }
                  
                  /////// Check for interest expiration of stop and limit players
                  if ( BarOrders[j].BuyStopOrders[k].Status == STATUS_VIRTUAL )//
                     {
                     if ( BarOrders[j].BuyStopOrders[k].IndexMarket - 1 >= BarOrders[j].BuyStopOrders[k].BarsExpirationOpen  )
                     BarOrders[j].BuyStopOrders[k].Status=STATUS_ABORTED;
                     else
                        {
                        if ( BarOrders[j].BuyStopOrders[k].VolumeAlpha > 0.0 )
                        BarOrders[j].BuyStopOrders[k].VolumeAlpha-=BarOrders[j].BuyStopOrders[k].VolumeStart/double(BarOrders[j].BuyStopOrders[k].BarsExpirationOpen);
                        if ( BarOrders[j].BuyStopOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].BuyStopOrders[k].VolumeAlpha=0.0;                  
                        } 
                     }
                  if ( BarOrders[j].SellStopOrders[k].Status == STATUS_VIRTUAL )//
                     {
                     if ( BarOrders[j].SellStopOrders[k].IndexMarket - 1 >= BarOrders[j].SellStopOrders[k].BarsExpirationOpen  )
                     BarOrders[j].SellStopOrders[k].Status=STATUS_ABORTED;
                     else
                        {
                        if ( BarOrders[j].SellStopOrders[k].VolumeAlpha > 0.0 )
                        BarOrders[j].SellStopOrders[k].VolumeAlpha-=BarOrders[j].SellStopOrders[k].VolumeStart/double(BarOrders[j].SellStopOrders[k].BarsExpirationOpen);
                        if ( BarOrders[j].SellStopOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].SellStopOrders[k].VolumeAlpha=0.0;                     
                        }
                     }                                                                       
                  }
               }         
            }
         }               
      }
      
   void UpdateMarket()// update the status of market orders
      {
      int size=ArraySize(BarOrders[0].BuyLimitOrders);
      int SizeBarOrders=ArraySize(BarOrders);
      
      if ( VolumeAlphaLimit != 0.0 )
         {
         for ( int i=SizeBarOrders; i>1; i-- )// update the state of orders simulating each candlestick
            {
            for ( int j=SizeBarOrders-1; j>i; j-- )// update the state of all candlesticks preceding this one
               {
               for ( int k=0; k<size; k++ )// update the state inside each preceding candlestick
                  {
                  // Block for closing when prices change
                  if ( BarOrders[j].BuyLimitOrders[k].Status == STATUS_MARKET )//
                     {
                     if ( BarOrders[j].BuyLimitOrders[k].VolumeAlpha > 0.0 )
                        {
                        BarOrders[j].BuyLimitOrders[k].VolumeAlpha-=BarOrders[j].BuyLimitOrders[k].VolumeStart*(High[i]-Open[i])/(BarOrders[j].BuyLimitOrders[k].UpPriceToClose-BarOrders[j].BuyLimitOrders[k].WantedPrice);// with profit
                        BarOrders[j].BuyLimitOrders[k].VolumeAlpha-=BarOrders[j].BuyLimitOrders[k].VolumeStart*(Open[i]-Low[i])/(BarOrders[j].BuyLimitOrders[k].WantedPrice-BarOrders[j].BuyLimitOrders[k].LowPriceToClose);// with loss
                        }
                     if ( BarOrders[j].BuyLimitOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].BuyLimitOrders[k].VolumeAlpha=0.0;
                     }
                  if ( BarOrders[j].SellLimitOrders[k].Status == STATUS_MARKET )//
                     {
                     if ( BarOrders[j].SellLimitOrders[k].VolumeAlpha > 0.0 )
                        {
                        BarOrders[j].SellLimitOrders[k].VolumeAlpha-=BarOrders[j].SellLimitOrders[k].VolumeStart*(Open[i]-Low[i])/(BarOrders[j].SellLimitOrders[k].WantedPrice-BarOrders[j].SellLimitOrders[k].LowPriceToClose);//with profit
                        BarOrders[j].SellLimitOrders[k].VolumeAlpha-=BarOrders[j].SellLimitOrders[k].VolumeStart*(High[i]-Open[i])/(BarOrders[j].SellLimitOrders[k].UpPriceToClose-BarOrders[j].SellLimitOrders[k].WantedPrice);//with loss
                        }
                     if ( BarOrders[j].SellLimitOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].SellLimitOrders[k].VolumeAlpha=0.0;
                     } 
                  // End of lock for closing when prices change
               
                  // Block for closing when time changes******************************************************
                  if ( BarOrders[j].BuyLimitOrders[k].Status == STATUS_MARKET )//
                     {
                     if ( BarOrders[j].BuyLimitOrders[k].VolumeAlpha > 0.0 )
                     BarOrders[j].BuyLimitOrders[k].VolumeAlpha-=BarOrders[j].BuyLimitOrders[k].VolumeStart/double(BarOrders[j].BuyLimitOrders[k].BarsExpirationClose);
                     if ( BarOrders[j].BuyLimitOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].BuyLimitOrders[k].VolumeAlpha=0.0;
                     }
                  if ( BarOrders[j].SellLimitOrders[k].Status == STATUS_MARKET )//
                     {
                     if ( BarOrders[j].SellLimitOrders[k].VolumeAlpha > 0.0 )
                     BarOrders[j].SellLimitOrders[k].VolumeAlpha-=BarOrders[j].SellLimitOrders[k].VolumeStart/double(BarOrders[j].SellLimitOrders[k].BarsExpirationClose);
                     if ( BarOrders[j].SellLimitOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].SellLimitOrders[k].VolumeAlpha=0.0;
                     } 
                  }
               }         
            }
         }
         
      if ( VolumeAlphaStop != 0.0 )
         {
         for ( int i=SizeBarOrders; i>1; i-- )// update the state of orders simulating each candlestick
            {
            for ( int j=SizeBarOrders-1; j>i; j-- )// update the state of all candlesticks preceding this one
               {
               for ( int k=0; k<size; k++ )// update the state inside each preceding candlestick
                  {
                  // Block for closing when prices change
                  if ( BarOrders[j].BuyStopOrders[k].Status == STATUS_MARKET )//
                     {
                     if ( BarOrders[j].BuyStopOrders[k].VolumeAlpha > 0.0 )
                        {
                        BarOrders[j].BuyStopOrders[k].VolumeAlpha-=BarOrders[j].BuyStopOrders[k].VolumeStart*(High[i]-Open[i])/(BarOrders[j].BuyStopOrders[k].UpPriceToClose-BarOrders[j].BuyStopOrders[k].WantedPrice);// with profit
                        BarOrders[j].BuyStopOrders[k].VolumeAlpha-=BarOrders[j].BuyStopOrders[k].VolumeStart*(Open[i]-Low[i])/(BarOrders[j].BuyStopOrders[k].WantedPrice-BarOrders[j].BuyStopOrders[k].LowPriceToClose);// with loss
                        }
                     if ( BarOrders[j].BuyStopOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].BuyStopOrders[k].VolumeAlpha=0.0;
                     }
                  if ( BarOrders[j].SellStopOrders[k].Status == STATUS_MARKET )//
                     {
                     if ( BarOrders[j].SellStopOrders[k].VolumeAlpha > 0.0 )
                        {
                        BarOrders[j].SellStopOrders[k].VolumeAlpha-=BarOrders[j].SellStopOrders[k].VolumeStart*(Open[i]-Low[i])/(BarOrders[j].SellStopOrders[k].WantedPrice-BarOrders[j].SellStopOrders[k].LowPriceToClose);//with profit
                        BarOrders[j].SellStopOrders[k].VolumeAlpha-=BarOrders[j].SellStopOrders[k].VolumeStart*(High[i]-Open[i])/(BarOrders[j].SellStopOrders[k].UpPriceToClose-BarOrders[j].SellStopOrders[k].WantedPrice);//with loss
                        }
                     if ( BarOrders[j].SellStopOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].SellStopOrders[k].VolumeAlpha=0.0;
                     }
               
                  // End of lock for closing when prices change
               
                  // Block for closing when time changes******************************************************
                  if ( BarOrders[j].BuyStopOrders[k].Status == STATUS_MARKET )//
                     {
                     if ( BarOrders[j].BuyStopOrders[k].VolumeAlpha > 0.0 )
                     BarOrders[j].BuyStopOrders[k].VolumeAlpha-=BarOrders[j].BuyStopOrders[k].VolumeStart/double(BarOrders[j].BuyStopOrders[k].BarsExpirationClose);
                     if ( BarOrders[j].BuyStopOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].BuyStopOrders[k].VolumeAlpha=0.0;
                     }
                  if ( BarOrders[j].SellStopOrders[k].Status == STATUS_MARKET )//
                     {
                     if ( BarOrders[j].SellStopOrders[k].VolumeAlpha > 0.0 )
                     BarOrders[j].SellStopOrders[k].VolumeAlpha-=BarOrders[j].SellStopOrders[k].VolumeStart/double(BarOrders[j].SellStopOrders[k].BarsExpirationClose);
                     if ( BarOrders[j].SellStopOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].SellStopOrders[k].VolumeAlpha=0.0;
                     }
                  }
               }         
            }
         }
         
      if ( VolumeAlphaMarket != 0.0 )
         {
         for ( int i=SizeBarOrders; i>1; i-- )// update the state of orders simulating each candlestick
            {
            for ( int j=SizeBarOrders-1; j>i; j-- )// update the state of all candlesticks preceding this one
               {
               for ( int k=0; k<size; k++ )// update the state inside each preceding candlestick
                  {
                  // Block for closing when prices change
                  /// For obviously market positions
                  if ( BarOrders[j].BuyMarketOrders[k].VolumeAlpha > 0.0 )
                     {
                     BarOrders[j].BuyMarketOrders[k].VolumeAlpha-=BarOrders[j].BuyMarketOrders[k].VolumeStart*(High[i]-Open[i])/(BarOrders[j].BuyMarketOrders[k].UpPriceToClose-BarOrders[j].BuyMarketOrders[k].WantedPrice);// with profit
                     BarOrders[j].BuyMarketOrders[k].VolumeAlpha-=BarOrders[j].BuyMarketOrders[k].VolumeStart*(Open[i]-Low[i])/(BarOrders[j].BuyMarketOrders[k].WantedPrice-BarOrders[j].BuyMarketOrders[k].LowPriceToClose);// with loss
                     }
                  if ( BarOrders[j].BuyMarketOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].BuyMarketOrders[k].VolumeAlpha=0.0;
                              
                  if ( BarOrders[j].SellMarketOrders[k].VolumeAlpha > 0.0 )
                     {
                     BarOrders[j].SellMarketOrders[k].VolumeAlpha-=BarOrders[j].SellMarketOrders[k].VolumeStart*(Open[i]-Low[i])/(BarOrders[j].SellMarketOrders[k].WantedPrice-BarOrders[j].SellMarketOrders[k].LowPriceToClose);// with profit
                     BarOrders[j].SellMarketOrders[k].VolumeAlpha-=BarOrders[j].SellMarketOrders[k].VolumeStart*(High[i]-Open[i])/(BarOrders[j].SellMarketOrders[k].UpPriceToClose-BarOrders[j].SellMarketOrders[k].WantedPrice);// with loss
                     }
                  if ( BarOrders[j].SellMarketOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].SellMarketOrders[k].VolumeAlpha=0.0;                  
                  // End of lock for closing when prices change
               
                  // Block for closing when time changes******************************************************
              
                  /// For obviously market positions
                  if ( BarOrders[j].BuyMarketOrders[k].VolumeAlpha > 0.0 )
                  BarOrders[j].BuyMarketOrders[k].VolumeAlpha-=BarOrders[j].BuyMarketOrders[k].VolumeStart/double(BarOrders[j].BuyMarketOrders[k].BarsExpirationClose);
                  if ( BarOrders[j].BuyMarketOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].BuyMarketOrders[k].VolumeAlpha=0.0;
                  if ( BarOrders[j].SellMarketOrders[k].VolumeAlpha > 0.0 )
                  BarOrders[j].SellMarketOrders[k].VolumeAlpha-=BarOrders[j].SellMarketOrders[k].VolumeStart/double(BarOrders[j].SellMarketOrders[k].BarsExpirationClose);
                  if ( BarOrders[j].SellMarketOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].SellMarketOrders[k].VolumeAlpha=0.0;               
                  //
                  }
               }         
            }
         }
      }
      
   /// fast methods****   
   void UpdateVirtualFast()// update the status of virtual orders
      {
      int SizeBarOrders=ArraySize(BarOrders);
      int size=ArraySize(BarOrders[0].BuyLimitOrders);
      
      if ( VolumeAlphaLimit != 0.0 )
         {
         for ( int j=SizeBarOrders-1; j>0; j-- )// update the state of all candlesticks preceding this one
            {
            for ( int k=0; k<size; k++ )// update the state inside each preceding candlestick
               {
               if ( BarOrders[j].BuyLimitOrders[k].Status == STATUS_VIRTUAL 
               && BarOrders[j].BuyLimitOrders[k].WantedPrice <= High[1] 
               && BarOrders[j].BuyLimitOrders[k].WantedPrice >= Low[1] )// if the order is virtual and is inside a candlestick, then it turns into a market one
                  {
                  BarOrders[j].BuyLimitOrders[k].Status = STATUS_MARKET;
                  BarOrders[j].BuyLimitOrders[k].IndexMarket = 1;
                  }
               if ( BarOrders[j].SellLimitOrders[k].Status == STATUS_VIRTUAL 
               && BarOrders[j].SellLimitOrders[k].WantedPrice <= High[1] 
               && BarOrders[j].SellLimitOrders[k].WantedPrice >= Low[1] )// the same
                  {
                  BarOrders[j].SellLimitOrders[k].Status = STATUS_MARKET;
                  BarOrders[j].SellLimitOrders[k].IndexMarket = 1;
                  } 
                  
               /////// Check for interest expiration of limit players
               if ( BarOrders[j].BuyLimitOrders[k].Status == STATUS_VIRTUAL )//
                  {
                  if ( BarOrders[j].BuyLimitOrders[k].IndexMarket - 1 >= BarOrders[j].BuyLimitOrders[k].BarsExpirationOpen )
                  BarOrders[j].BuyLimitOrders[k].Status=STATUS_ABORTED;
                  else
                     {
                     if ( BarOrders[j].BuyLimitOrders[k].VolumeAlpha > 0.0 )
                     BarOrders[j].BuyLimitOrders[k].VolumeAlpha-=BarOrders[j].BuyLimitOrders[k].VolumeStart/double(BarOrders[j].BuyLimitOrders[k].BarsExpirationOpen);
                     if ( BarOrders[j].BuyLimitOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].BuyLimitOrders[k].VolumeAlpha=0.0;
                     }
                  }
               if ( BarOrders[j].SellLimitOrders[k].Status == STATUS_VIRTUAL )//
                  {
                  if ( BarOrders[j].SellLimitOrders[k].IndexMarket - 1 >= BarOrders[j].SellLimitOrders[k].BarsExpirationOpen  )
                  BarOrders[j].SellLimitOrders[k].Status=STATUS_ABORTED;
                  else
                     {
                     if ( BarOrders[j].SellLimitOrders[k].VolumeAlpha > 0.0 )
                     BarOrders[j].SellLimitOrders[k].VolumeAlpha-=BarOrders[j].SellLimitOrders[k].VolumeStart/double(BarOrders[j].SellLimitOrders[k].BarsExpirationOpen);
                     if ( BarOrders[j].SellLimitOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].SellLimitOrders[k].VolumeAlpha=0.0;                  
                     }
                  } 
               }
            }
         }
         
      if ( VolumeAlphaStop != 0.0 )
         {       
         for ( int j=SizeBarOrders-1; j>0; j-- )// update the state of all candlesticks preceding this one
            {
            for ( int k=0; k<size; k++ )// update the state inside each preceding candlestick
               {
               if ( BarOrders[j].SellStopOrders[k].Status == STATUS_VIRTUAL 
               && BarOrders[j].SellStopOrders[k].WantedPrice <= High[1] 
               && BarOrders[j].SellStopOrders[k].WantedPrice >= Low[1] )// the same
                  {
                  BarOrders[j].SellStopOrders[k].Status = STATUS_MARKET;
                  BarOrders[j].SellStopOrders[k].IndexMarket = 1;
                  }
               if ( BarOrders[j].BuyStopOrders[k].Status == STATUS_VIRTUAL 
               && BarOrders[j].BuyStopOrders[k].WantedPrice <= High[1] 
               && BarOrders[j].BuyStopOrders[k].WantedPrice >= Low[1] )// the same
                  {
                  BarOrders[j].BuyStopOrders[k].Status = STATUS_MARKET;
                  BarOrders[j].BuyStopOrders[k].IndexMarket = 1;
                  }
                  
               /////// Check for interest expiration of stop players
               if ( BarOrders[j].BuyStopOrders[k].Status == STATUS_VIRTUAL )//
                  {
                  if ( BarOrders[j].BuyStopOrders[k].IndexMarket - 1 >= BarOrders[j].BuyStopOrders[k].BarsExpirationOpen  )
                  BarOrders[j].BuyStopOrders[k].Status=STATUS_ABORTED;
                  else
                     {
                     if ( BarOrders[j].BuyStopOrders[k].VolumeAlpha > 0.0 )
                     BarOrders[j].BuyStopOrders[k].VolumeAlpha-=BarOrders[j].BuyStopOrders[k].VolumeStart/double(BarOrders[j].BuyStopOrders[k].BarsExpirationOpen);
                     if ( BarOrders[j].BuyStopOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].BuyStopOrders[k].VolumeAlpha=0.0;                  
                     } 
                  }
               if ( BarOrders[j].SellStopOrders[k].Status == STATUS_VIRTUAL )//
                  {
                  if ( BarOrders[j].SellStopOrders[k].IndexMarket - 1 >= BarOrders[j].SellStopOrders[k].BarsExpirationOpen  )
                  BarOrders[j].SellStopOrders[k].Status=STATUS_ABORTED;
                  else
                     {
                     if ( BarOrders[j].SellStopOrders[k].VolumeAlpha > 0.0 )
                     BarOrders[j].SellStopOrders[k].VolumeAlpha-=BarOrders[j].SellStopOrders[k].VolumeStart/double(BarOrders[j].SellStopOrders[k].BarsExpirationOpen);
                     if ( BarOrders[j].SellStopOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].SellStopOrders[k].VolumeAlpha=0.0;                     
                     }
                  }                                                                       
               }
            }
         }         
      }
      
   void UpdateMarketFast()// update the status of market orders
      {
      int size=ArraySize(BarOrders[0].BuyLimitOrders);
      int SizeBarOrders=ArraySize(BarOrders);
      
      if ( VolumeAlphaLimit != 0.0 )
         {
         for ( int j=SizeBarOrders-1; j>0; j-- )// update the state of all candlesticks preceding this one
            {
            for ( int k=0; k<size; k++ )// update the state inside each preceding candlestick
               {
               // Block for closing when prices change
               if ( BarOrders[j].BuyLimitOrders[k].Status == STATUS_MARKET )//
                  {
                  if ( BarOrders[j].BuyLimitOrders[k].VolumeAlpha > 0.0 )
                     {
                     BarOrders[j].BuyLimitOrders[k].VolumeAlpha-=BarOrders[j].BuyLimitOrders[k].VolumeStart*(High[1]-Open[1])/(BarOrders[j].BuyLimitOrders[k].UpPriceToClose-BarOrders[j].BuyLimitOrders[k].WantedPrice);// with profit
                     BarOrders[j].BuyLimitOrders[k].VolumeAlpha-=BarOrders[j].BuyLimitOrders[k].VolumeStart*(Open[1]-Low[1])/(BarOrders[j].BuyLimitOrders[k].WantedPrice-BarOrders[j].BuyLimitOrders[k].LowPriceToClose);// with loss
                     }
                  if ( BarOrders[j].BuyLimitOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].BuyLimitOrders[k].VolumeAlpha=0.0;
                  }
               if ( BarOrders[j].SellLimitOrders[k].Status == STATUS_MARKET )//
                  {
                  if ( BarOrders[j].SellLimitOrders[k].VolumeAlpha > 0.0 )
                     {
                     BarOrders[j].SellLimitOrders[k].VolumeAlpha-=BarOrders[j].SellLimitOrders[k].VolumeStart*(Open[1]-Low[1])/(BarOrders[j].SellLimitOrders[k].WantedPrice-BarOrders[j].SellLimitOrders[k].LowPriceToClose);// with profit
                     BarOrders[j].SellLimitOrders[k].VolumeAlpha-=BarOrders[j].SellLimitOrders[k].VolumeStart*(High[1]-Open[1])/(BarOrders[j].SellLimitOrders[k].UpPriceToClose-BarOrders[j].SellLimitOrders[k].WantedPrice);// with loss
                     }
                  if ( BarOrders[j].SellLimitOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].SellLimitOrders[k].VolumeAlpha=0.0;
                  } 
               // End of lock for closing when prices change
               
               // Block for closing when time changes******************************************************
               if ( BarOrders[j].BuyLimitOrders[k].Status == STATUS_MARKET )//
                  {
                  if ( BarOrders[j].BuyLimitOrders[k].VolumeAlpha > 0.0 )
                  BarOrders[j].BuyLimitOrders[k].VolumeAlpha-=BarOrders[j].BuyLimitOrders[k].VolumeStart/double(BarOrders[j].BuyLimitOrders[k].BarsExpirationClose);
                  if ( BarOrders[j].BuyLimitOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].BuyLimitOrders[k].VolumeAlpha=0.0;
                  }
               if ( BarOrders[j].SellLimitOrders[k].Status == STATUS_MARKET )//
                  {
                  if ( BarOrders[j].SellLimitOrders[k].VolumeAlpha > 0.0 )
                  BarOrders[j].SellLimitOrders[k].VolumeAlpha-=BarOrders[j].SellLimitOrders[k].VolumeStart/double(BarOrders[j].SellLimitOrders[k].BarsExpirationClose);
                  if ( BarOrders[j].SellLimitOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].SellLimitOrders[k].VolumeAlpha=0.0;
                  } 
               //
               }
            }
         }
         
      if ( VolumeAlphaStop != 0.0 )
         {
         for ( int j=SizeBarOrders-1; j>0; j-- )// update the state of all candlesticks preceding this one
            {
            for ( int k=0; k<size; k++ )// update the state inside each preceding candlestick
               {
               // Block for closing when prices change
               if ( BarOrders[j].BuyStopOrders[k].Status == STATUS_MARKET )//
                  {
                  if ( BarOrders[j].BuyStopOrders[k].VolumeAlpha > 0.0 )
                     {
                     BarOrders[j].BuyStopOrders[k].VolumeAlpha-=BarOrders[j].BuyStopOrders[k].VolumeStart*(High[1]-Open[1])/(BarOrders[j].BuyStopOrders[k].UpPriceToClose-BarOrders[j].BuyStopOrders[k].WantedPrice);// with profit
                     BarOrders[j].BuyStopOrders[k].VolumeAlpha-=BarOrders[j].BuyStopOrders[k].VolumeStart*(Open[1]-Low[1])/(BarOrders[j].BuyStopOrders[k].WantedPrice-BarOrders[j].BuyStopOrders[k].LowPriceToClose);// with loss
                     }
                  if ( BarOrders[j].BuyStopOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].BuyStopOrders[k].VolumeAlpha=0.0;
                  }
               if ( BarOrders[j].SellStopOrders[k].Status == STATUS_MARKET )//
                  {
                  if ( BarOrders[j].SellStopOrders[k].VolumeAlpha > 0.0 )
                     {
                     BarOrders[j].SellStopOrders[k].VolumeAlpha-=BarOrders[j].SellStopOrders[k].VolumeStart*(Open[1]-Low[1])/(BarOrders[j].SellStopOrders[k].WantedPrice-BarOrders[j].SellStopOrders[k].LowPriceToClose);// with profit
                     BarOrders[j].SellStopOrders[k].VolumeAlpha-=BarOrders[j].SellStopOrders[k].VolumeStart*(High[1]-Open[1])/(BarOrders[j].SellStopOrders[k].UpPriceToClose-BarOrders[j].SellStopOrders[k].WantedPrice);// with loss
                     }
                  if ( BarOrders[j].SellStopOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].SellStopOrders[k].VolumeAlpha=0.0;
                  }
               
               // End of lock for closing when prices change
               
               // Block for closing when time changes******************************************************
               if ( BarOrders[j].BuyStopOrders[k].Status == STATUS_MARKET )//
                  {
                  if ( BarOrders[j].BuyStopOrders[k].VolumeAlpha > 0.0 )
                  BarOrders[j].BuyStopOrders[k].VolumeAlpha-=BarOrders[j].BuyStopOrders[k].VolumeStart/double(BarOrders[j].BuyStopOrders[k].BarsExpirationClose);
                  if ( BarOrders[j].BuyStopOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].BuyStopOrders[k].VolumeAlpha=0.0;
                  }
               if ( BarOrders[j].SellStopOrders[k].Status == STATUS_MARKET )//
                  {
                  if ( BarOrders[j].SellStopOrders[k].VolumeAlpha > 0.0 )
                  BarOrders[j].SellStopOrders[k].VolumeAlpha-=BarOrders[j].SellStopOrders[k].VolumeStart/double(BarOrders[j].SellStopOrders[k].BarsExpirationClose);
                  if ( BarOrders[j].SellStopOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].SellStopOrders[k].VolumeAlpha=0.0;
                  }
               //
               }
            }
         }
         
       if ( VolumeAlphaMarket != 0.0 )
         {
         for ( int j=SizeBarOrders-1; j>0; j-- )// update the state of all candlesticks preceding this one
            {
            for ( int k=0; k<size; k++ )// update the state inside each preceding candlestick
               {
               /// For obviously market positions
               if ( BarOrders[j].BuyMarketOrders[k].VolumeAlpha > 0.0 )
                  {
                  BarOrders[j].BuyMarketOrders[k].VolumeAlpha-=BarOrders[j].BuyMarketOrders[k].VolumeStart*(High[1]-Open[1])/(BarOrders[j].BuyMarketOrders[k].UpPriceToClose-BarOrders[j].BuyMarketOrders[k].WantedPrice);// with profit
                  BarOrders[j].BuyMarketOrders[k].VolumeAlpha-=BarOrders[j].BuyMarketOrders[k].VolumeStart*(Open[1]-Low[1])/(BarOrders[j].BuyMarketOrders[k].WantedPrice-BarOrders[j].BuyMarketOrders[k].LowPriceToClose);// with loss
                  }
               if ( BarOrders[j].BuyMarketOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].BuyMarketOrders[k].VolumeAlpha=0.0;
                              
               if ( BarOrders[j].SellMarketOrders[k].VolumeAlpha > 0.0 )
                  {
                  BarOrders[j].SellMarketOrders[k].VolumeAlpha-=BarOrders[j].SellMarketOrders[k].VolumeStart*(Open[1]-Low[1])/(BarOrders[j].SellMarketOrders[k].WantedPrice-BarOrders[j].SellMarketOrders[k].LowPriceToClose);// with profit
                  BarOrders[j].SellMarketOrders[k].VolumeAlpha-=BarOrders[j].SellMarketOrders[k].VolumeStart*(High[1]-Open[1])/(BarOrders[j].SellMarketOrders[k].UpPriceToClose-BarOrders[j].SellMarketOrders[k].WantedPrice);// with loss
                  }
               if ( BarOrders[j].SellMarketOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].SellMarketOrders[k].VolumeAlpha=0.0;                  
               // End of lock for closing when prices change
               
               // Block for closing when time changes******************************************************
             
               /// For obviously market positions
               if ( BarOrders[j].BuyMarketOrders[k].VolumeAlpha > 0.0 )
               BarOrders[j].BuyMarketOrders[k].VolumeAlpha-=BarOrders[j].BuyMarketOrders[k].VolumeStart/double(BarOrders[j].BuyMarketOrders[k].BarsExpirationClose);
               if ( BarOrders[j].BuyMarketOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].BuyMarketOrders[k].VolumeAlpha=0.0;
               if ( BarOrders[j].SellMarketOrders[k].VolumeAlpha > 0.0 )
               BarOrders[j].SellMarketOrders[k].VolumeAlpha-=BarOrders[j].SellMarketOrders[k].VolumeStart/double(BarOrders[j].SellMarketOrders[k].BarsExpirationClose);
               if ( BarOrders[j].SellMarketOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].SellMarketOrders[k].VolumeAlpha=0.0;               
               //
               }
            }
         }                          
      }      
   ///******
      
   void CalculateStartVolume()// calculate the starting total volume of all positions (relative to it we will estimate market fullness)
      {
      StartVolume=0;
      int size=ArraySize(BarOrders[0].BuyStopOrders);
      if ( VolumeAlphaStop != 0.0 )
         {
         for ( int j=ArraySize(BarOrders)-1; j>=0; j-- )
            {
            for ( int i=0; i<size; i++ )
               {
               StartVolume+=BarOrders[j].BuyStopOrders[i].VolumeStart;
               }
            }        
         }
         
      if ( VolumeAlphaLimit != 0.0 )
         {
         size=ArraySize(BarOrders[0].BuyLimitOrders);
         for ( int j=ArraySize(BarOrders)-1; j>=0; j-- )
            {
            for ( int i=0; i<size; i++ )
               {
               StartVolume+=BarOrders[j].BuyLimitOrders[i].VolumeStart;
               }         
            }
         }
         
      if ( VolumeAlphaMarket != 0.0 )
         {
         size=ArraySize(BarOrders[0].BuyMarketOrders);
         for ( int j=ArraySize(BarOrders)-1; j>=0; j-- )
            {
            for ( int i=0; i<size; i++ )
               {
               StartVolume+=BarOrders[j].BuyMarketOrders[i].VolumeStart;
               }         
            }
         }         
      }
      
   void CalculateCurrentVolume()// calculate the current total volume of all positions
      {
      SummVolumeBuy=0;
      SummVolumeSell=0;
      int size=ArraySize(BarOrders[0].BuyStopOrders);
      
      if ( VolumeAlphaStop != 0.0 )
         {
         for ( int j=ArraySize(BarOrders)-1; j>=0; j-- )
            {
            for ( int i=0; i<size; i++ )
               {
               if ( BarOrders[j].BuyStopOrders[i].Status == STATUS_MARKET )
               SummVolumeBuy+=BarOrders[j].BuyStopOrders[i].VolumeAlpha;
               if ( BarOrders[j].SellStopOrders[i].Status == STATUS_MARKET )
               SummVolumeSell+=BarOrders[j].SellStopOrders[i].VolumeAlpha;            
               }         
            }
         }
      
      if ( VolumeAlphaLimit != 0.0 )
         {   
         size=ArraySize(BarOrders[0].BuyLimitOrders);
         for ( int j=ArraySize(BarOrders)-1; j>=0; j-- )
            {
            for ( int i=0; i<size; i++ )
               {
               if ( BarOrders[j].BuyLimitOrders[i].Status == STATUS_MARKET )
               SummVolumeBuy+=BarOrders[j].BuyLimitOrders[i].VolumeAlpha;
               if ( BarOrders[j].SellLimitOrders[i].Status == STATUS_MARKET )
               SummVolumeSell+=BarOrders[j].SellLimitOrders[i].VolumeAlpha;            
               }         
            }
         }
      
      if ( VolumeAlphaMarket != 0.0 )
         {
         size=ArraySize(BarOrders[0].BuyMarketOrders);
         for ( int j=ArraySize(BarOrders)-1; j>=0; j-- )
            {
            for ( int i=0; i<size; i++ )
               {
               SummVolumeBuy+=BarOrders[j].BuyMarketOrders[i].VolumeAlpha;
               SummVolumeSell+=BarOrders[j].SellMarketOrders[i].VolumeAlpha;
               }         
            }
         }         
      }
      
   void CalculatePercent()// calculate the percentage of Buys and Sells relative to all positions
      {
      if ( (SummVolumeBuy+SummVolumeSell) != 0.0 ) BuyPercent=100.0*SummVolumeBuy/(SummVolumeBuy+SummVolumeSell);
      else BuyPercent=50;
      if ( (SummVolumeBuy+SummVolumeSell) != 0.0 ) SellPercent=100.0*SummVolumeSell/(SummVolumeBuy+SummVolumeSell);
      else SellPercent=50;
      }      
      
   void CalculateRelativeVolume()// calculate relative volumes of Buys and Sells (calculate only uncovered part of positions)
      {
      if ( SummVolumeBuy >= SummVolumeSell ) RelativeVolume=(SummVolumeBuy-SummVolumeSell)/StartVolume;
      else RelativeVolume=(SummVolumeSell-SummVolumeBuy)/StartVolume;
      }                   
   
   };

Le code entier est valable pour MetaTrader 4 et MetaTrader 5. Ces classes peuvent être compilées dans les deux plateformes. Bien sûr, dans MetaTrader 5, vous devez implémenter des tableaux prédéfinis à l'avance, comme dans MQL4. Je ne fournirai pas ce code ici. Vous pouvez le vérifier dans le code source attaché à cet article. Mon code n'est pas très original. Il ne nous reste plus qu'à implémenter les variables responsables du trading et les fonctionnalités correspondantes. Les Experts Advisors pour les deux terminaux sont joints attachés également.

Le code est très gourmand en ressources. C'est pourquoi j'ai organisé une mise en œuvre lente de la logique pour commencer l'analyse et une mise en œuvre rapide pour travailler sur les barres. Tous mes Experts Advisors travaillent par barres pour éviter de dépendre de la génération artificielle de ticks et d'autres conséquences indésirables des tests de tous les ticks. Bien sûr, nous pourrions éviter complètement les fonctions lentes. Mais dans ce cas, il n'y aurait pas eu d'analyse de départ. En plus, je n'aime pas mettre en œuvre des fonctionnalités en dehors du corps de la classe, car cela ruine l'intégrité de l'image, à mon avis.

Le dernier constructeur de la classe acceptera les paramètres suivants comme entrées. Si vous le souhaitez, vous pouvez effectuer de nombreuses simulations de ce type, car il ne s'agit que d'une instance de classe :

input bool bPrintE=false;// print market parameters
input CLOSE_MODE CloseModeE=CLOSE_FAST;// order closing mode
input WORK_MODE ModeE=MODE_SIMPLE;// simulation mode
input ENUM_GRID_WEIGHT WeightFillingE=WEIGHT_SAME;// weight distribution type
input double LimitVolumeE=0.5;// significance of limit orders
input double StopVolumeE=0.5;// significance of stop orders
input double MarketVolume=0.5;// significance of market orders
input int ExpirationBars=100;// bars for full expiration of open orders
input int ExpirationOpenStopBars=1000;// patience of a stop player in bars, after which the order is canceled
input int ExpirationOpenLimitBars=1000;// patience of a limit player in bars, after which the order is canceled
input int ProfitPointsCloseE=200;// points to close with profit
input int LossPointsCloseE=400;// points to close with loss
input int HalfCorridorE=500;// half-corridor for limit and stop orders
input int OrdersToOneBarE=50;// orders for half-grid per 1 bar
input int BarsE=250;// bars for analysis
input double MinPercentE=60;// minimum superiority of one trading side in percentage 
input double MaxPercentE=80;// maximum percentage
input double MinRelativeVolumeE=0.0001;// minimum market filling [0...1]
input double MaxRelativeVolumeE=1.00;// maximum market filling [0...1]

Je ne fournirai pas ici de variables liées au trading, car tout est simple et clair. 

Voici ma fonction dans laquelle le trading est mis en œuvre :

void Trade()
   {
   if ( Area0 == NULL )
      {
      CalcAllMQL5Values();
      Area0 = new Simulation(WeightFillingE,HalfCorridorE,OrdersToOneBarE,BarsE
       ,ExpirationOpenLimitBars,ExpirationOpenStopBars,ExpirationBars,ProfitPointsCloseE,LossPointsCloseE
       ,StopVolumeE,LimitVolumeE,MarketVolume);      
      }
   
   switch(ModeE)
      {
      case MODE_SIMPLE:
         Area0.Update();// update simulation
      case MODE_FAST:
         Area0.UpdateFast();// fast update simulation
      }
   
   if (bPrintE)
      {
      Print("BuyPercent= ",Area0.GetBuyPercent());
      Print("SellPercent= ",Area0.GetSellPercent());
      Print("RelativeVolume= ",Area0.GetRelativeVolume());
      }
      
   if ( CloseModeE == CLOSE_FAST && Area0.GetBuyPercent() > 50.0 )
      {
      if ( !bInvert ) CloseBuyF();
      else CloseSellF();
      }
      
   if ( CloseModeE == CLOSE_FAST && Area0.GetSellPercent() > 50.0 )
      {
      if ( !bInvert ) CloseSellF();
      else CloseBuyF();
      }      
      
   if ( Area0.GetBuyPercent() > MinPercentE && Area0.GetBuyPercent() < MaxPercentE 
   && Area0.GetRelativeVolume() >= MinRelativeVolumeE && Area0.GetRelativeVolume() <= MaxRelativeVolumeE )
      {
      if ( !bInvert )
         {
         CloseBuyF();
         SellF();
         }
      else
         {
         CloseSellF();
         BuyF();
         }   
      }
      
   if ( Area0.GetSellPercent() > MinPercentE && Area0.GetSellPercent() < MaxPercentE 
   && Area0.GetRelativeVolume() >= MinRelativeVolumeE && Area0.GetRelativeVolume() <= MaxRelativeVolumeE )
      {
      if ( !bInvert )    
         {
         CloseSellF();
         BuyF();
         }  
      else
         {
         CloseBuyF();
         SellF();
         }
      }
   }

Si vous le souhaitez, il est possible de créer de meilleures conditions de trading et une fonction plus complexe, mais jusqu'à présent, je n'en vois pas l'intérêt. J'essaie toujours de séparer la partie trading de la partie logique. La logique est mise en œuvre dans l'objet. L'objet de simulation est créé dynamiquement dans la fonction de trading lors du premier déclenchement, et il est supprimé lors de la dé-initialisation. Ceci est dû à l'indisponibilité de tableaux prédéfinis dans MQL5. Ils doivent être créés artificiellement pour assurer un fonctionnement de la classe similaire à celui de MQL4.


Comment trouver les paramètres qui fonctionnent ?

D'après mon expérience, je peux dire qu'il est préférable de sélectionner les paramètres manuellement. Je suggère également d'ignorer le spread au début pour les Expert Advisors fonctionnant sur des périodes courtes et ayant une petite espérance mathématique - cela vous aidera à ne pas manquer les signes de performance au tout début. MetaTrader 4 est très bien adapté à cette fin. Une recherche fructueuse est toujours suivie d'une révision, d'une édition et ainsi de suite, dans le but d'augmenter l'espérance mathématique finale et le facteur de profit (force du signal). La structure des données d'entrée devrait également permettre idéalement des modes de fonctionnement indépendants. En d'autres termes, un paramètre doit avoir l'effet le plus indépendant sur les performances du système, quelle que soit la valeur des autres paramètres. Cette approche permet d'améliorer le signal global en définissant des paramètres équilibrés qui combinent tous les signaux trouvés. Ce type de mise en œuvre n'est pas toujours possible. Mais dans notre cas, elle est applicable car nous analysons chaque type d’ordre séparément.


Test de l’Expert Advisor

Cet Expert Advisor a été écrit sans aucune préparation, à partir de zéro. Ce code de l’EA est donc nouveau pour moi. J'avais un EA similaire, mais il était beaucoup plus simple et avait une logique complètement différente. Je tiens à le souligner, car l'objectif de l'article était de montrer que toute idée reposant sur des bases sous-jacentes correctes, même si elle ne décrit pas entièrement la physique du marché, a de très bonnes chances de donner des résultats. Si le système montre des capacités de performance de base, nous pouvons le tester, trouver ce qui fonctionne dans ce système et passer au niveau suivant dans la compréhension du marché. Le niveau suivant suppose des Expert Advisors de meilleure qualité que vous créerez vous-même.

Lorsque j'ai testé l'Expert Advisor, j'ai dû passer plusieurs jours à sélectionner patiemment des paramètres de trading. Tout était ennuyeux et long, mais j'ai réussi à trouver des réglages qui fonctionnent. Bien entendu, ces paramètres sont très faibles et la simulation n'utilise qu'un seul type d'ordre, mais cela a été fait à dessein. Il est en effet préférable d'analyser séparément la manière dont un type d'ordre spécifique affecte un signal, puis d'essayer de simuler d'autres types d'ordres. Voici mon résultat avec MetaTrader 4 :

EURUSD 2010.01.01 -2020.11.01

J'ai d'abord créé une version pour MetaTrader 4 et je l'ai testée avec le spread le plus bas possible. Le fait est que nous avons besoin de voir chaque tick afin de rechercher des modèles, en particulier sur les échelles de temps courtes. Lors du test de la version MetaTrader 5, nous n'avons pas pu le constater en raison des spreads, que MetaTester 5 peut ajuster à sa guise.

Il s'agit d'un outil parfait pour les tests de stress et l'évaluation des performances réelles du système. Il doit être utilisé à la dernière étape pour tester le système sur des ticks réels. Dans notre cas, il est préférable de commencer à tester le système dans MetaTrader 4. Je conseille à tout le monde d'utiliser cette approche, car si vous commencez immédiatement à tester la cinquième version, vous risquez de perdre beaucoup d'excellentes options de réglage, qui peuvent servir de base à des réglages de meilleure qualité.

Je ne recommande pas l'utilisation de l'optimisation pour de nombreuses raisons, la principale étant qu'il s'agit d'une simple itération de paramètres. Vous ne pourrez pas comprendre comment il fonctionne si vous n'essayez pas les paramètres manuellement. Si vous prenez une vieille radio, que vous connectez des moteurs électriques à ses poignées et que vous les démarrez, il est fort probable que vous ne trouverez pas de station de radio. Il en va de même ici. Même si vous parvenez à attraper quelque chose, il sera difficile de comprendre de quoi il s'agit.

Un autre aspect très important est le nombre d’ordres. Plus le nombre d'ordres est élevé par rapport au nombre de barres ouvertes, plus la physique est forte, et vous ne devriez pas vous préoccuper de ses performances futures. N'oubliez pas non plus que les modèles trouvés peuvent se situer à l'intérieur du spread, ce qui peut rendre le système inutilisable si ces moments ne sont pas contrôlés !

C'est ici que nous avons besoin du testeur MetaTrader 5. MetaTrader 5 permet de tester une stratégie en utilisant des ticks réels. Malheureusement, les ticks réels existent pour une période relativement récente pour toutes les paires de devises et tous les instruments. Je testerai la version du système pour MetaTrader 5 au cours de la dernière période en utilisant des ticks réels et des exigences très strictes en matière de spread pour voir si le système fonctionne en 2020. Mais je vais tout d’abord tester le système en mode "Chaque tick" sur la période précédemment utilisée :

Ce mode de test n'est pas aussi performant que celui utilisant de vrais ticks. Mais il est évident que seule une très petite partie des signaux du résultat initial est restée ici. Il existe néanmoins des signaux qui couvrent le spread et permettent même de réaliser un petit bénéfice. De même, je ne suis pas sûr des spreads que le testeur tire de l'historique profond. Dans ce test, le lot était de 0,01, ce qui signifie que l'espérance mathématique est de 5 points. Ce qui est encore plus élevé que le test original, bien que le graphique ne soit pas très bon. Ces données sont encore fiables car elles s'appuient sur un vaste échantillon de 100 000 transactions dans le cadre du test initial.

Jetons maintenant un coup d'œil sur l'année écoulée :

Dans ce test, j'ai fixé le lot à 0,1, l'espérance mathématique est donc de 23,4 points, ce qui est très bien, étant donné que le test initial sur MetaTrader 4 avait une espérance de seulement 3 points. Les attentes pourraient diminuer à l'avenir, mais pas de beaucoup de points. Il sera donc toujours suffisant pour atteindre le seuil de rentabilité.

L'Expert Advisor pour les deux terminaux est disponible dans la pièce jointe. Vous pouvez modifier les paramètres et essayer de trouver des paramètres de fonctionnement pour les ordres à cours limité et pour les ordres de marché. Vous pouvez ensuite combiner des ensembles et définir des paramètres moyens. Malheureusement, je n'ai pas eu assez de temps pour en tirer le meilleur parti, ce qui laisse de la place pour d'autres actions.

Bien sûr, veuillez noter qu'il ne s'agit pas d'un EA prêt à l'emploi, que vous pouvez simplement lancer sur un graphique et apprécier. Testez la simulation en utilisant d'autres types d'ordres, puis combinez les paramètres et répétez ces deux cycles de test jusqu'à ce que l'EA affiche des résultats de trading fiables. Vous pouvez éventuellement introduire des filtres ou ajuster les algorithmes eux-mêmes. Comme le montrent les tests, d'autres améliorations sont encore possibles. Vous pouvez donc utiliser le programme joint et l'affiner afin d'obtenir des résultats stables. Je n'ai pas non plus réussi à trouver des paramètres appropriés pour les périodes plus longues. L'EA fonctionne mieux sur M5, mais vous pouvez peut-être trouver d'autres périodes. Je n'ai pas non plus eu le temps de vérifier comment l’ensemble se comporte sur d'autres paires de devises. Cependant, de telles lignes plates signifient généralement que l'EA devrait également fonctionner sur d'autres paires de devises. J'essaierai de continuer à affiner l'EA si j'en ai le temps. Lors de la rédaction de cet article, j'ai trouvé quelques failles et erreurs dans l'EA. Il y a donc encore beaucoup à faire.


Conclusion

Le simulateur a prouvé que cette méthode d'analyse répondait aux attentes. Après avoir obtenu les premiers résultats, il est temps de réfléchir à la manière de les améliorer, de moderniser l'algorithme et de le rendre meilleur, plus rapide et plus variable. Le plus grand avantage de cette approche est sa simplicité maximale. Je ne parle pas de la mise en œuvre de la logique, mais de la logique sous-jacente de cette méthode d'un point de vue physique.

Nous ne pouvons pas prendre en compte tous les facteurs qui influencent l'évolution des prix. Mais même s'il existe au moins un tel facteur (même si nous ne pouvons pas le décrire de manière fiable), sa description imprécise produira certains signaux. Ces signaux ne sont peut-être pas d'une très grande qualité, mais ils sont suffisants pour générer un certain profit à partir de cette idée. N'essayez pas de trouver une formule idéale. C'est impossible, car vous ne pouvez jamais prendre en compte tous les facteurs qui affectent le marché.

De plus, vous n'êtes pas obligé d'utiliser exactement mon approche. L'objectif de cet article était d'utiliser certains principes physiques du marché qui, à mon avis, décrivent au moins partiellement le marché, et d'écrire un Expert Advisor qui peut prouver l'idée. J'ai donc mis au point un Expert Advisor qui a montré que de telles hypothèses peuvent servir de base à un système opérationnel.

Il faut également tenir compte du fait que le code présente des failles et des bugs plus ou moins importants. Même sous cette forme, l'EA fonctionne. Vous ne devez que l'affiner. Dans le prochain article, je présenterai un autre type d'analyse de marché multi-actifs, plus simple, plus efficace et connu de tous. Nous allons à nouveau créer un Expert Advisor.

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

Fichiers joints |
Simulation.zip (27.31 KB)
Combinatoires et probabilités pour le trading (Partie V) : Analyse des courbes Combinatoires et probabilités pour le trading (Partie V) : Analyse des courbes
Dans cet article, j'ai décidé de mener une étude sur la possibilité de réduire les états multiples à des systèmes à deux états. L'objectif principal de cet article est d'analyser et de tirer des conclusions utiles qui pourraient contribuer au développement d'algorithmes de trading évolutifs basés sur la théorie des probabilités. Bien entendu, ce sujet fait appel aux mathématiques. Mais au vu de l'expérience des articles précédents, je constate que les informations générales sont plus utiles que les détails.
Développer un Expert Advisor de trading à partir de zéro (Partie 28) : Vers l'avenir (III) Développer un Expert Advisor de trading à partir de zéro (Partie 28) : Vers l'avenir (III)
Il reste une tâche pour laquelle notre système d’ordres n'est pas à la hauteur, mais nous allons ENFIN la résoudre. MetaTrader 5 fournit un système de tickets qui permet de créer et de corriger les valeurs des ordres. L'idée est d'avoir un Expert Advisor qui rendrait le même système de tickets plus rapide et plus efficace.
Combinatoires et probabilités pour le trading (Partie IV) : Logique de Bernoulli Combinatoires et probabilités pour le trading (Partie IV) : Logique de Bernoulli
Dans cet article, j'ai décidé de mettre en avant le célèbre schéma de Bernoulli et de montrer comment il peut être utilisé pour décrire des tableaux de données liées au trading. Tous ces éléments seront ensuite utilisés pour créer un système de trading auto-adaptatif. Nous chercherons également un algorithme plus générique, dont un cas particulier est la formule de Bernoulli, et nous lui trouverons une application.
Développer un Expert Advisor de trading à partir de zéro (Partie 27) : Vers le futur (II) Développer un Expert Advisor de trading à partir de zéro (Partie 27) : Vers le futur (II)
Passons à un système d’ordres plus complet directement sur le graphique. Dans cet article, je vais montrer un moyen de corriger le système d’ordres, ou plutôt de le rendre plus intuitif.