OnTradeTransaction - page 8

 
Igor Zakharov:

Sur les robots "normaux", le cas que j'ai décrit, je n'ai rien remarqué du tout ; mais dans un cas, on m'a demandé de faire un système de sécurité : la condition était que les positions soient toujours verrouillées (soit avec des positions réelles, soit avec un ordre en attente), c'est-à-dire que le nombre de lots d'achat soit égal au nombre de lots de vente. C'est le cas qui m'a fait découvrir les nuances du comptage des ordres/positions/échanges dans un fiver.

La différence, telle que je me la suis expliquée :) est que le quatre, lorsqu'il reçoit une réponse du courtier, synchronise d'abord ses "tables" avec les ordres ouverts et l'historique, puis informe l'utilisateur de la réponse du courtier. Le cinq nous diffuse immédiatement cette réponse, et en même temps corrige ses "tables" (et tous les programmes mql lisent les données de ces "tables"). C'est le moment que nous attrapons sur le chronomètre à millisecondes. Mais alors, pourquoi ne l'attrapons-nous pas dans le testeur ?

En général, j'ai fait en sorte que ma tranquillité d'esprit...

Non, les choses sont pires.

L'ordre au moment de la transformation d'un ordre en attente (ou de marché) en un ordre historique (exécuté ou annulé), il disparaît complètement du terminal pendant un certain temps. Il n'apparaît ni parmi les marchés en cours (ou "commencés"), ni parmi les marchés historiques.

Il ne s'agit donc pas d'une question d'exécution, mais de synchronisation de ces deux tables. La réponse du serveur est arrivée ("Ordre exécuté, transaction générée untel"), elle est retirée d'une table, mais elle n'est pas entrée dans l'autre.

 
Andrey Khatimlianskii:

Non, les choses sont pires.

Lorsqu'un ordre passe du statut d'ordre en attente (ou marché) à celui d'ordre historique (exécuté ou annulé), il disparaît complètement du terminal pendant un certain temps. Il n'apparaît ni parmi les marchés en cours (ou "commencés"), ni parmi les marchés historiques.

Il ne s'agit donc pas d'une question d'exécution, mais de synchronisation de ces deux tables. La réponse provient du serveur ("Ordre exécuté, a déclenché l'opération untel") et elle est supprimée d'une table mais pas entrée dans l'autre.

Il est intéressant de le vérifier.Igor Makanu m'a intrigué avec la tâchehttps://www.mql5.com/ru/forum/6343/page1097#comment_12518742.

J'ai fait la première approximation sur mon genou. Ensuite, je ferai quelquesstatistiques sur les opérations OnOrder et OnOrderTransaction et sur l'état de l'environnement de trading et, si je ne suis pas trop paresseux, je le mettrai en test démo pour voir ce qui se passe sur différents comptes/courtiers.

il sera alors possible de l'analyser. Hypothèses faites jusqu'à présent : 1. Aucune exécution partielle n'est contrôlée et les particularités du compte ne sont pas vérifiées ; j'ai envoyé un ordre au marché, la position ouverte est mémorisée, j'attends l'apparition de la clôture de cette position dans le journal et j'ouvre à nouveau dans la direction opposée. 2. Idéalement, une certaine transaction devrait être attrapée dans OnOrderTransaction, mais jusqu'à présent, j'ai procédé de cette façon - dans les deux événements, je vérifie tout de la même manière.

Bien sûr, le code n'est pas optimal. Je peux déjà voir où les positions d'ordre seront perdues si tout est aussi mauvais que décrit dans le post ci-dessus.

//+------------------------------------------------------------------+
//|                                                 Test_Makalu2.mq5 |
//|                                           Copyright 2019, Allex@ |
//|                                                 alex-all@mail.ru |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019, Allex@"
#property link      "alex-all@mail.ru"
#property version   "1.00"
#include <Expert\Expert.mqh>
//--- input parameters
input int      TP=200;
input int      SL=200;
input double   Lot=0.01;
input string   File;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CExpertTest : public CExpert
  {
public:
   int               type;
   ulong             order;
   ulong             deal;
   ulong             position;
   bool              send;
   bool              placed;
   bool              opened;
   bool              history;
   datetime          last_history;

                     CExpertTest() {order=0;};
                    ~CExpertTest() {};
   bool              Buy(double volume,double price,double sl,double tp,const string comment="") {return m_trade.Buy(volume, price, sl, tp,  comment);};
   bool              Sell(double volume,double price,double sl,double tp,const string comment="") {return m_trade.Sell(volume, price, sl, tp,  comment);};
   bool              CheckOrder(ulong order)
     {
      ulong state;
      if(OrderSelect(order))
        {
         if(OrderGetInteger(ORDER_STATE)==ORDER_STATE_FILLED)
            position=OrderGetInteger(ORDER_POSITION_ID);
        }
      else
         if(HistoryOrderSelect(order))
           {
            if(HistoryOrderGetInteger(order,ORDER_STATE,state)&& state==ORDER_STATE_FILLED)
               position=HistoryOrderGetInteger(order,ORDER_POSITION_ID);
           }
         else
           {
            return false;
           }
      return true;

     }
   virtual bool      Processing(void)
     {
      double price;
      if(order==0)
        {
         last_history=TimeCurrent();
         price=m_symbol.Ask();
         if(Buy(Lot,price,m_symbol.NormalizePrice(price-SL*m_symbol.Point()),m_symbol.NormalizePrice(price+TP*m_symbol.Point())))
            if(m_trade.ResultRetcode()==TRADE_RETCODE_DONE)
              {
               //ulong deal2;
               deal=m_trade.ResultDeal();
               order=m_trade.ResultOrder();
               if(order!=0 && CheckOrder(order))
                  return true;
              }
        }
      return false;
     }
   void              OnTrade()
     {
      if(order==0 || !CheckOrder(order))
         return;
      HistorySelect(last_history,TimeCurrent());
      for(int i=HistoryDealsTotal()-1; i>=0; i--)
        {
         ulong ticket=HistoryDealGetTicket(i);
         ulong ordticket=HistoryDealGetInteger(ticket,DEAL_ORDER);
         ulong pos=HistoryDealGetInteger(ticket,DEAL_POSITION_ID);
         if(pos==position || ordticket==order || ticket==deal)
           {
            int entry=HistoryDealGetInteger(ticket,DEAL_ENTRY);
            ulong type=HistoryDealGetInteger(ticket,DEAL_TYPE);
            if(pos==position && entry==DEAL_ENTRY_OUT)
              {
               Refresh();
               double price;
               double sl;
               double tp;
               bool result=false;
               datetime dt=TimeCurrent();
               if(type==DEAL_TYPE_SELL)
                 {
                  price=m_symbol.Bid();
                  sl=m_symbol.NormalizePrice(price+SL*m_symbol.Point());
                  tp=m_symbol.NormalizePrice(price-TP*m_symbol.Point());
                  result=Sell(Lot,price,sl,tp);
                 }
               if(type==DEAL_TYPE_BUY)
                 {
                  price=m_symbol.Ask();
                  sl=m_symbol.NormalizePrice(price-SL*m_symbol.Point());
                  tp=m_symbol.NormalizePrice(price+TP*m_symbol.Point());
                  result=Buy(Lot,price,sl,tp);
                 }
               if(result && m_trade.ResultRetcode()==TRADE_RETCODE_DONE)
                 {
                  deal=m_trade.ResultDeal();
                  order=m_trade.ResultOrder();
                  if(order!=0 && CheckOrder(order))
                     last_history=dt;
                 }
              }
           }
        }
     }
  };
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
CExpertTest Expert;
//---
int OnInit()
  {
   if(!Expert.Init(Symbol(),Period(),Point()))
      return INIT_FAILED;
   Expert.OnTradeProcess(true);
   return(INIT_SUCCEEDED);
  }
//---
void OnTick()
  {
   Expert.OnTick();
  }
//+------------------------------------------------------------------+
void OnTrade()
  {
   Expert.OnTrade();
  }
//+------------------------------------------------------------------+
void OnTradeTransaction(const MqlTradeTransaction& trans,
                        const MqlTradeRequest& request,
                        const MqlTradeResult& result)
  {
   Expert.OnTrade();
  }
Вопросы от начинающих MQL5 MT5 MetaTrader 5
Вопросы от начинающих MQL5 MT5 MetaTrader 5
  • 2019.07.21
  • www.mql5.com
Подскажите пожалуйста, такой показатель тестера в жизни реален? И хороший это или плохой результат за год с депо 3000...
 
Aleksey Mavrin:

C'est intéressant à vérifier.Igor Makanu m'intrigue avec un défi https://www.mql5.com/ru/forum/6343/page1097#comment_12518742.

il y avait une solution dans la discussionhttps://www.mql5.com/ru/forum/6343/page1098#comment_12519819, une partie de la discussion, cependant, a été supprimée (((
 
Il existe une solution dans le fil de discussion MT4Orders. Mais vous devez sentir chaque râteau vous-même ;)
 
Aleksey Mavrin:

J'ai fait une première approximation sur le genou.

Cette démo est plus intéressante à regarder.ForexTimeFXTM-Demo01

 
Igor Zakharov:

Je n'ai pas du tout remarqué le cas que j'ai décrit sur les robots "normaux".

Toute bibliothèque de trading peut et doit être vérifiée au moyen de tests de résistance sur différents comptes de démonstration. Il devrait tout passer sans problème.

Pour y parvenir, l'auteur doit se familiariser personnellement avec les blagues MT5. Dans ma pratique, il s'est avéré que même cela n'est pas suffisant.

Il y a des choses très spécifiques qui n'ont pas été détectées par le terrible spamming d'ordres aux serveurs commerciaux. Grâce au retour d'information, il a été possible de découvrir des comportements assez étranges que les développeurs eux-mêmes ne semblent pas avoir compris.

 
Igor Makanu:
il y avait une solution dans la discussionhttps://www.mql5.com/ru/forum/6343/page1098#comment_12519819, une partie de la discussion a été supprimée (((
Andrey Khatimlianskii:
Il existe une solution dans la branche de MT4Orders. Mais vous devez sentir chaque râteau vous-même ;)

C'est vrai, le râteau est toujours intéressant, et puis voyez comment les pros ont fait. La solution defxsaber est brillante dans sa concision, mais je vois un piège dans cette solution dans une chose - les manuels disent que le ticket de position est EXACTEMENT le ticket de l'ordre ouvert, mais PAS TOUT.

Dans ma solution, je partais de ce principe.

fxsaber
fxsaber
  • www.mql5.com
Опубликовал пост "Out-Of-Sample" - где расположить, справа или слева? Когда-то в паблике столкнулся с мнением, что OOS должен располагаться только справа. Т.е. расположение его слева от интервала Оптимизации - ошибка. Я с этим был категорически не согласен, т.к. не видел разницы. Теперь вижу. Ошибался, был не прав... Опубликовал пост...
 
fxsaber:

Toute bibliothèque de trading peut et doit être vérifiée par des tests de résistance sur différents comptes de démonstration. Il devrait tout passer sans problème.

J'ai utilisé 200 ms pour les tests et lorsque je l'ai rendu, l'homme l'a réglé sur 5 ms. À 5, cela a fonctionné presque tout le temps sur n'importe quel compte.

Je ne sais pas si c'est important, mais ils ont utilisé le timeBeginPeriod(1) de winapi, c'est-à-dire que tout s'est passé en dessous des 20ms standards.

 
Aleksey Mavrin:

Le ticket de position est SURTOUT le ticket d'ordre d'ouverture, mais PAS TOUJOURS.

Je ne m'en souviens pas très bien, mais ça semble toujours être le cas.

 
fxsaber:

Je ne m'en souviens pas très bien, mais je pense que ça a toujours été là.

Oui, vous avez raison, car dans ce cas, il s'agit d'un identifiant de position, constant tout au long de sa vie. Je l'ai confondu avec le ticker de position, qui change pendant les rollovers et la compensation.

Mais je ne comprends pas - quand une position est partiellement fermée, le ticket ne devient pas le ticket du dernier ordre affectant la position ?

Je vais revoir mes codes, merci. Je n'ai pas visité le forum pour rien)

Concernant la "commande perdue" qui n'est pas dans la liste des commandes actuelles ou historiques : Il me semble que ce n'est pas un bug, il faut juste que je regarde attentivement les fonctionnalités de

Je pense que ce n'est pas un bug, il faut juste examiner attentivement les particularités du terminal-serveur MT-market (dans le cas d'une exécution instantanée, le marché ne fonctionne pas). Je pense que oui, regardez - le terminal envoie un ordre de marché, dans le cas de la fonction synchrone - il attend et reçoit une réponse du serveur,

S'il n'y a pas d'erreur, la réponse ne peut être que TRADE_RETCODE_DONE (dans le cas d'une exécution instantanée, il s'agit de requotes, mais jusqu'à présent, c'est le type de marché), ce qui signifie essentiellement que le serveur a envoyé l'ordre au marché et que celui-ci

Cela signifie en fait que le serveur a envoyé l'ordre et attend sa réponse. L'état de la commande à ce moment estORDER_STATE_STARTED si je ne me trompe pas et son ticket est connu. Si l'ordre est exécuté, le serveur envoie OnTradeTransaction au terminal et le statut de l'ordre passe à ORDER_STATE_FILLED et la transaction est connue.

et la position devient connue. C'est seulement à ce moment que le terminal enregistre la commande dans l'historique. Il ne le fait pas au préalable car nous ne savons pas ce qui lui est arrivé et il a déjà donné la réponse initiale du serveur.

C'est le temps jusqu'à ce que l'ordre soit exécuté dans le réseau ECN ou ailleurs, ils ne sont dans aucune des deux listes. C'est-à-dire que dans le cas d'un ordre au marché, il n'apparaît que dans l'historique (je ne suis pas sûr du cas des requêtes lors de l'exécution instantanée),

il n'apparaîtra jamais dans la liste de ceux qui sont ouverts. Et quand un ordre en attente se déclenche, il est retiré de la liste des ordres ouverts parce qu'il est déjà devenu un ordre de marché et nous attendons que le serveur de marché réponde, puis il est envoyé à l'historique.

Ai-je raison ?