Mon EA fait une double entrée - page 7

 

si j'utilise le sommeil, je vais perdre des tics ?

Quelles seront les conséquences ? Pouvez-vous m'en parler ?

Documentation on MQL5: Common Functions / Sleep
Documentation on MQL5: Common Functions / Sleep
  • www.mql5.com
Common Functions / Sleep - Documentation on MQL5
 
doshur:

si j'utilise le sommeil, je vais perdre des tics ?

Quelles seront les conséquences ? Pouvez-vous m'en parler ?

Cela dépend de votre stratégie. Comme ce problème de "double trades" ne peut se produire que si votre code de trading est exécuté à chaque tick, vous avez probablement une stratégie qui dépend du tick. C'est donc à vous d'évaluer quelles peuvent être les conséquences si vous perdez les ticks qui arrivent pendant votre délai (sommeil).

 
angevoyageur:

Cela dépend de votre stratégie. Comme le problème des "doubles trades" ne peut se produire que si votre code de trading est exécuté à chaque tick, vous avez probablement une stratégie qui dépend du tick. C'est donc à vous d'évaluer quelle peut être la conséquence si vous perdez les ticks qui arrivent pendant votre délai (sommeil).

Ainsi, si je dors pendant 800

signifie que je perds des ticks pour les 800ms suivants ? Après avoir entré mon trade, mon EA ne fait rien, il reste là jusqu'au TP ou SL ou attend le moment de sortir.

Donc ma stratégie est correcte si j'utilise sleep?

L'appel à refreshrates() permet-il de récupérer les ticks ?

Documentation on MQL5: Common Functions / Sleep
Documentation on MQL5: Common Functions / Sleep
  • www.mql5.com
Common Functions / Sleep - Documentation on MQL5
 
doshur:

Donc si je dors pendant 800

signifie que je perds des ticks pendant les 800 ms suivantes ? Après avoir entré ma transaction, mon EA ne fait rien, il reste là jusqu'au TP ou SL ou attend le moment de sortir.

Donc ma stratégie est correcte si j'utilise sleep?

L'appel à refreshrates() permet-il de récupérer les ticks ?

doshur, lesticks que vous perdez, vous perdez, il n'y a pas de machine à remonter le temps.

Concernant la documentation, à l'adressehttps://www.mql5.com/en/docs/common/sleep, la fonctionsuspend l'exécution du conseiller expert ou du script en cours dans un intervalle spécifié.

Ainsi, même les événements OnTimer seront suspendus, probablement parce que l'EA utilise un seul thread.

Donc, l'utilisation d'un Sleep fixe n'est pas une solution définitive, c'est juste de la "numérologie", c'est-à-dire une solution de contournement si le délai est inférieur à votre valeur.

Et c'est pourquoi je propose une boucle de test de PositionSelect après l'ouverture de la transaction, pour vérifier l'exécution et le retour de PositionOpen comme une meilleure solution de contournement que juste Sleep(), et qui comprove aussi la cause du problème (selon les tests d'angevoyageur).

Documentation on MQL5: Common Functions / Sleep
Documentation on MQL5: Common Functions / Sleep
  • www.mql5.com
Common Functions / Sleep - Documentation on MQL5
 

C'est ce que j'utilise actuellement. Où dois-je coder la solution de contournement fournie par figurelli d'une manière plus élégante ?

//
         {
            Price = SymbolInfoDouble(Symbol(), SYMBOL_ASK);

            if(m_Trade.PositionOpen(Symbol(), ORDER_TYPE_BUY, LotSize, Price, 0, 0))
            {
               Sleep(800);

               if(m_Trade.ResultRetcode() == 10009)
               {
                  Print("Position opened in ", Symbol());

                  return;
               }
               else
               {
                  Print("Error opening position in ", Symbol(), " - ", m_Trade.ResultComment(), "\n", "Return Code Desc - ", m_Trade.ResultRetcodeDescription());
               }
            }
            else
            {
               Print("Error with PositionOpen in ", Symbol(), " - ", m_Trade.ResultComment(), "\n", "Return Code Desc - ", m_Trade.ResultRetcodeDescription());
            }
         }
 
doshur:

C'est ce que j'utilise actuellement. Où dois-je coder la solution de contournement fournie par figurelli d'une manière plus élégante ?

Bonjour doshur, j'avais également des problèmes avec les doubles entrées dans l'un de mes EA. En fait, ces problèmes ne se produisaient que lorsque je négociais des actifs très liquides. Même après avoir configuré les ordres pour qu'ils soient envoyés en mode asynchrone, l'EA attendait "apparemment" trop longtemps une réponse du serveur pour mettre à jour PositionsTotal()... pendant ce temps, d'autres ticks entrants déclenchaient les conditions pour envoyer un deuxième ordre... dans le forum portugais j'ai posté une solution de contournement, que je voudrais partager ici.

L'idée est simple :

//--- global variables
CTrade trade;
bool position_opened=false;

//--- inside OnTick()
if( conditions to open && position_opened==false )
  {
   //--- set the global variable to true to avoid duplicate orders
   position_opened=true;
   trade.PositionOpen(_Symbol,order_type,lot,price,sl,tp,"comment");
  }

Le seul problème avec ce code est le cas où l'ordre n'est pas accepté par le serveur, donc vous devez "réinitialiser" la variable globale... Vous pourriez utiliser ceci :

MqlTradeResult mresult;

//--- 
if(mresult.retcode==10009 || mresult.retcode==10008)
  {Print("Success!");}
else 
  {
   Print("Error = ",GetLastError());
   ResetLastError();
   //--- Sets the global variable to false
   position_opened=false;
   return;
  }

Ainsi, dans le cas où le premier ordre envoyé renvoie une erreur, la variable globale sera mise à false afin que l'EA puisse envoyer un autre ordre. Cependant, je dois dire que j'ai testé ce code uniquement sur les actions et les futures, mais pas sur le marché des changes... :-(

 
Malacarne:

Bonjour doshur, j'avais également des problèmes de double entrée dans l'un de mes EA. En fait, ces problèmes ne survenaient que lorsque je négociais des actifs très liquides. Même après avoir configuré les ordres pour qu'ils soient envoyés en mode asynchrone, l'EA attendait "apparemment" trop longtemps une réponse du serveur pour mettre à jour PositionsTotal()... pendant ce temps, d'autres ticks entrants déclenchaient les conditions pour envoyer un deuxième ordre... dans le forum portugais j'ai posté une solution de contournement, que je voudrais partager ici.

L'idée est simple :

Le seul problème avec ce code est le cas où l'ordre n'est pas accepté par le serveur, donc vous devez "réinitialiser" la variable globale... Vous pourriez utiliser ceci :

Ainsi, dans le cas où le premier ordre envoyé renvoie une erreur, la variable globale sera mise à false pour que l'EA puisse envoyer un autre ordre. Cependant, je dois dire que j'ai testé ce code uniquement sur les actions et les futures, mais pas sur le marché des changes... :-(

Cela semble viable. Voyons sifigurelli etangevoyageur ont des commentaires sur cette solution de contournement...
 
doshur:
Cela semble viable. Voyons sifigurelli etangevoyageur ont des commentaires sur cette solution de contournement...

La solution proposée par Malacarne (avec quelques ajustements que je vais proposer) est géniale, car pour moi ce n'est pas une solution de contournement (comme Malacarne le mentionne modestement), mais une façon élégante et juste de traiter cette question.

À mon avis, le problème original de la double entrée n'est pas un bug de MT5, mais un bug de codage, puisque l'aide indique :

"La réussite de la méthode PositionOpen(...) ne signifie pas toujours l'exécution réussie de l'opération commerciale. Il est nécessaire de vérifier le résultat de la demande de transaction (code de retour du serveur de transaction) en utilisantResultRetcode() et la valeur, renvoyée parResultDeal()."

Donc, je suggère quelques petits changements pour être plus résilient à toute condition de marché :

1) Tester le retour de PostionOpen() aussi, comme le code original, par exemple :

if (trade.PositionOpen(_Symbol,order_type,lot,price,sl,tp,"comment")) position_opened=true;

2) Un traitement plus complet de ResultRetcode(), puisque vous pouvez avoir d'autres positions pertinentes ouvertes, comme 10010 -TRADE_RETCODE_DONE_PARTIAL - Seule une partie de la requête a été complétée. De même, 10008 - TRADE_RETCODE_PLACED - Ordre placé n'est pas un succès pour moi, juste 10009 -TRADE_RETCODE_DONE -Demande complétée, et ce sont des messages asynchrones, donc la deuxième partie du code de Malacarne pourrait considérer ceci et/ou leticket de transaction, après que la transaction soit exécutée,aussi.

Quoi qu'il en soit, il me semble que nous sommes sur la bonne voie et que nous avons atteint le stade final.

 
Malacarne:

Bonjour doshur, j'avais également des problèmes de double entrée dans l'un de mes EA. En fait, ces problèmes ne survenaient que lorsque je négociais des actifs très liquides. Même après avoir configuré les ordres pour qu'ils soient envoyés en mode asynchrone, l'EA attendait "apparemment" trop longtemps une réponse du serveur pour mettre à jour PositionsTotal()... pendant ce temps, d'autres ticks entrants déclenchaient les conditions pour envoyer un deuxième ordre... dans le forum portugais j'ai posté une solution de contournement, que je voudrais partager ici.

L'idée est simple :

Le seul problème avec ce code est le cas où l'ordre n'est pas accepté par le serveur, donc vous devez "réinitialiser" la variable globale... Vous pourriez utiliser ceci :

Ainsi, dans le cas où le premier ordre envoyé renvoie une erreur, la variable globale sera mise à false afin que l'EA puisse envoyer un autre ordre. Cependant, je dois dire que j'ai testé ce code uniquement sur les actions et les futures, mais pas sur le marché des changes... :-(

C'est une approche valide, cependant vous devez remettre votre variable globale position_opened à false lorsque votre position est fermée. Où faites-vous cela ?

A propos de votre implémentation, quelques détails :

  1. Il n'y a pas besoin de mettre position_opened à true et ensuite à false s'il y a une erreur.
  2. Vous utilisez un objet de la classe CTrade, donc pas besoin d'utiliser une nouvelle structure MqlTradeResult.
  3. Comme figurelli l'a noté dans son post, vous devez vérifier la valeur retournée de PositionOpen.
  4. Le nom de la classe est CTrade, pas Ctrade. mql5 est sensible à la casse.
  5. position_opened est un bool, pas besoin de le comparer à false. Si vous le faites, vous devez utiliser '==' et non '='.

Donc, voici le code modifié(Compilé mais pas testé) :

//+------------------------------------------------------------------+
//|                                                      ProjectName |
//|                                      Copyright 2012, CompanyName |
//|                                       http://www.companyname.net |
//+------------------------------------------------------------------+
#include <Trade\Trade.mqh>

//--- global variables
CTrade trade;
bool position_opened=false;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnTick()
  {
   bool conditions_to_open;
   ENUM_ORDER_TYPE order_type;
   double lot;
   double price,sl,tp;

//---...set variables

//--- inside OnTick()
   if(conditions_to_open && !position_opened) //-- Or position_opened==false
     {
      if(trade.PositionOpen(_Symbol,order_type,lot,price,sl,tp,"comment")
         && 
         (trade.ResultRetcode()==10009 || trade.ResultRetcode()==10008)) //-- Or others condition according to your needs
        {
         //--- set the global variable to true to avoid duplicate orders
         position_opened=true;
         Print("Success!");
        }
      else
        {
         Print("Error = ",GetLastError(), "trade error = ", trade.ResultRetcode());
         //--- Sets the global variable to false
         // position_opened=false;                                         //-- Not needed as position_opened is already false
         return;
        }

     }
//--- 
  }
//+------------------------------------------------------------------+
 
figurelli:

...

A mon avis, le problème initial de double entrée n'est pas un bug de MT5, mais un bug de codage, puisque l'aide indique :

"L'exécution réussie de la méthode PositionOpen(...) ne signifie pas toujours l'exécution réussie de l'opération commerciale. Il est nécessaire de vérifier le résultat de la demande de transaction (code de retour du serveur de transaction) à l'aide deResultRetcode() et de la valeur renvoyée parResultDeal()."

Je ne pense pas que cela soit lié au problème de ce sujet. Le problème que nous rencontrons est dans le cas où une requête a été remplie avec succès et qu'une position est ouverte. Mais cette position est ouverte sur le serveur de trading, le problème que nous avons rencontré est lorsqu'il y a un délai plus important que d'habitude et que le terminal MT5 est notifié de cette nouvelle position APRÈS qu'un nouveau tick ait déjà été traité.

Ce n'est pas un bug, car c'est conçu de cette façon. MAIS à mon avis, c'est une mauvaise conception pour une plateforme qui permet explicitement des demandes de trading synchrones et asynchrones. Nous parlons ici d'une requête qui est supposée être synchrone, mais en fait elle ne l'est pas vraiment car lorsque vous recevez la réponse du serveur pour la requête (trade.ResultRetCode dans le code ci-dessus) nous devons encore attendre que la plateforme MT5 soit informée et mise à jour des résultats du trading. (J'ai compris tout cela avec ce fil de discussion).

Donc, je suggère quelques petits changements pour être plus résilient aux conditions du marché :

1) Tester le retour de PostionOpen() aussi, comme le code original, par exemple :

2) Un traitement plus complet de ResultRetcode(), puisque vous pouvez avoir d'autres positions pertinentes ouvertes, comme 10010 -TRADE_RETCODE_DONE_PARTIAL - Seule une partie de la demande a été réalisée. De même, 10008 - TRADE_RETCODE_PLACED - Ordre placé n'est pas un succès pour moi, juste 10009 -TRADE_RETCODE_DONE -Demande complétée, et ce sont des messagesasynchrones, donc la deuxième partie du code de Malacarne pourrait considérer ceci et/ou leticket de transaction, après que la transaction soit exécutée,aussi.

Quoi qu'il en soit, il me semble que nous sommes sur la bonne voie et que la coupe finale est prête.

Bien sûr, vous avez absolument raison de dire qu'il faut vérifier la valeur retournée de PositionOpen ET le code retourné du résultat de la transaction. Cependant le ResultRetCode est synchrone, c'est la mise à jour de la base de données MT5 sur la position (transaction et ordre) qui est asynchrone. Le test que j'ai fait avec votre proposition l'a démontré, car j'utilise bien sûr un code qui vérifie la valeur retournée de la demande de transaction.
Raison: