Avec quoi remplacer OnTradeTransaction() dans mql4 ? - page 8

 
Vitaly Muzichenko:

Voilà, la solution est simple : nous introduisons une autre vérification pour changer l'historique, de cette façon rien ne sera perdu et cela fonctionnera à 100%.

Cela peut même être utilisé comme un OnTrade() incomplet.

void OnTrade()
 {
  ...
 }

static __OTotal = -1;
static __HTotal = -1;
int OT=OrdersTotal();
int HT=OrdersHistoryTotal();
  if(OT!=__OTotal || HT!=__HTotal) // если изменилось - выполняем
   {
     OnTrade(); // здесь дёргаем текущую ситуацию на счёте и заполняем структуры
     __OTotal=OrdersTotal(); // запомним текущее количество
     __HTotal=OrdersHistoryTotal(); // запомним количество в истории
   }
 
Vitaly Muzichenko:

Je suppose que je ne suis pas assez intelligent.)

Comment puis-je l'appliquer ?

Il n'y a qu'un seul problème et il est extrêmement rare. Je l'ai trouvé aujourd'hui pour la première fois en deux ans, peut-être avant, mais je ne l'ai pas remarqué.


Je parlais du calcul de la somme de hachage - comment ajouter un nom de caractère à la valeur de la somme de hachage - calculer les valeurs des codes de lettres qui composent le nom de caractère.

 
Vitaly Muzichenko:

C'est ça, la solution est simple : introduire un autre contrôle de changement d'historique, comme ça rien ne sera perdu et ça marchera à 100%.

Voici un extrait de mon article n°3 :

-------

Concentrons-nous davantage sur le montant du dièse en tant que partie de la structure.
Il ne suffit pas de connaître le nombre d'ordres et de positions pour pouvoir déterminer avec précision ce qui a changé sur le compte - un ordre en attente peut être supprimé, et dans ce cas, le nombre total d'ordres et de positions sur le compte changera. Mais... Un ordre en attente peut se déclencher et devenir une position. Dans ce cas, le montant total des ordres et des positions ne changerait pas (pour les comptes de couverture et MQL4) - le nombre de positions a augmenté, mais le nombre d'ordres a diminué, donc le montant total reste le même. Cela ne fonctionne pas pour nous.

Prenons l'exemple d'un billet. L'ajout/la suppression d'un ordre en attente modifiera le nombre total de ticks sur le compte, le déclenchement d'un ordre en attente ne modifiera pas le nombre total de ticks sur le compte.

Regardons le volume total. Vous avez placé ou supprimé un ordre en attente - ; nous l'avons ouvert ou fermé, ou modifié la position - ; le montant total du compte a changé. Cela semble convenir mais, une fois encore, l'activation d'un ordre en attente ne modifiera pas le volume total.

Voyons donc une autre propriété de la position - le temps de son changement en millisecondes : l'ouverture d'une nouvelle position changera le temps total de changement de position, la fermeture partielle changera le temps de changement de position, l'ajout de volume à un compte de compensation changera le temps total de changement de position.

Laquelle de ces méthodes convient pour déterminer l'emplacement précis des changements sur le compte ? Ticket + heure du changement de position. Vérifions :

  • Ouverture d'une position - montant des billets a changé + montant du temps de changement de position a changé - il y a un changement
  • Nous avons fermé une position - le nombre de ticks a changé + le temps de changement de la position - il y a un changement.
  • Placement d'un ordre en attente - Ticket + l'heure de changement de position n' a pas changé - - il y a un changement
  • Ordre en attente supprimé - Montant du ticket modifié + Montant du temps de changement de position resté inchangé - il y a un changement
  • Ordre en suspens activé - Le montant du ticket n' a pas changé + le temps de changement de position le montant a changé - - il y a un changement
  • Fermeture partielle de la position - Montant du billet modifié + Modification de l' heure de changement de position - - Il y a un changement
  • Ajouter le volume à la position - Le montant du billet est resté inchangé + le temps de changement de position a changé - - il y a un changement
Ainsi, nous utiliserons le ticket + le temps de changement d'une position en millisecondes pour la somme de hachage.

Ici, cependant, je n'ai pas ajouté de symbole à la somme de hachage - il n'y avait pas de précédent pour cela. Mais je l'ai fait fonctionner en conjonction avec l'historique des vérifications. Par conséquent - devrait fonctionner sans erreurs. Cependant, je le vérifierai un jour.

Библиотека для простого и быстрого создания программ для MetaTrader (Часть III): Коллекция рыночных ордеров и позиций, поиск и фильтрация
Библиотека для простого и быстрого создания программ для MetaTrader (Часть III): Коллекция рыночных ордеров и позиций, поиск и фильтрация
  • www.mql5.com
В первой части данного цикла статей мы начали создавать большую кроссплатформенную библиотеку, целью которой является облегчение создания программ для платформы MetaTrader 5 и MetaTrader 4. Во второй части продолжили развитие библиотеки и сделали коллекцию исторических ордеров и сделок. В данной части повествования создадим класс для удобного...
 
Vitaly Muzichenko:

La solution est simple : introduire un autre contrôle de changement d'historique, de cette façon rien ne sera perdu et cela fonctionnera à 100%.

Et oui, il le fera. Si le nombre d'ordres ouverts ne change pas, alors le nombre dans l'historique changera. (Je ne me soucie pas des commandes en cours - je ne les utilise pas). Et nous n'aurons pas à passer en revue toute la journée pour ne retenir qu'un seul événement.

Et si l'utilisateur a reçu un SMS et a décidé d'afficher l'historique dans le terminal au lieu de tout afficher uniquement pour le dernier mois, ce sera un contrôle supplémentaire avec l'essai de toutes les commandes, ce qui n'est pas fatal.

Cela semble être une bonne solution. Et sans référence à quoi que ce soit d'autre que ce que nous avons, à savoir un compte commercial et un terminal.

 
Artyom Trishkin:

Voici un extrait de mon article n°3 :

-------

Développons le montant du dièse en tant que partie de la structure.
Il ne suffit pas de connaître le montant des ordres et des positions qui ont changé sur le compte pour pouvoir déterminer précisément ce changement - un ordre en attente peut être supprimé et dans ce cas, le montant total des ordres et des positions sur le compte changera. Mais... Un ordre en attente peut se déclencher et devenir une position. Dans ce cas, le montant total des ordres et des positions ne changerait pas (pour les comptes de couverture et MQL4) - le nombre de positions a augmenté, mais le nombre d'ordres a diminué, donc le montant total reste le même. Cela ne fonctionne pas pour nous.

Envisagez un billet. L'ajout/la suppression d'une commande en attente modifiera le nombre total de tickets sur le compte, le déclenchement d'une commande en attente ne modifiera pas le nombre total de tickets sur le compte.

Considérez le volume total. Vous avez placé ou supprimé un ordre en attente - le volume total du compte a changé, ouvert, fermé ou changé de position - le volume total du compte a changé. Cela semble convenir mais, une fois encore, l'activation d'un ordre en attente ne modifiera pas le volume total.

Voyons donc une autre propriété de la position - le temps de son changement en millisecondes : l'ouverture d'une nouvelle position changera le temps total de changement de position, la fermeture partielle changera le temps de changement de position, l'ajout de volume à un compte de compensation changera le temps total de changement de position.

Laquelle de ces méthodes convient pour déterminer l'emplacement précis des changements sur le compte ? Ticket + heure du changement de position. Vérifions :

  • Ouverture d'une position - montant des billets modifiés + durée du changement de position - il y a un changement
  • Nous avons fermé une position - le nombre de ticks a changé + le temps de changement de la position - il y a un changement.
  • Placement d'un ordre en attente - Ticket + l'heure de changement de position n' a pas changé - - il y a un changement
  • Ordre en attente supprimé - Montant du ticket modifié + Montant du temps de changement de position resté inchangé - il y a un changement
  • Ordre en suspens activé - Le montant du ticket n' a pas changé + le temps de changement de position le montant a changé - - il y a un changement
  • Fermeture partielle de la position - Montant du billet modifié + Modification de l' heure de changement de position - - Il y a un changement
  • Ajouter le volume à la position - Le montant du billet est resté inchangé + le temps de changement de position a changé - - il y a un changement
Ainsi, nous utiliserons le ticket + le temps de changement d'une position en millisecondes pour la somme de hachage.

Ici, cependant, je n'ai pas ajouté de symbole à la somme de hachage - il n'y avait pas de précédent pour cela. Mais je l'ai fait fonctionner en conjonction avec l'historique des vérifications. Par conséquent - devrait fonctionner sans erreurs. Cependant, je le vérifierai un jour.

Grosse solution, pas encore besoin d'une telle variante.

Merci !

 
Vitaly Muzichenko:

Grosse décision, pas encore besoin de cette option.

Merci !

"Audacieux" parce qu'il n'a pas été conçu comme une solution locale, mais comme une partie d'un remplacement à part entière de OnTradeXXXX. Il y a plus de travail avec de l'histoire.

Et c'est un grand avantage - nous avons des données prêtes pour la recherche et le tri de tous les ordres et positions dans le programme (nous n'avons pas besoin de rechercher à nouveau les ordres et positions pour répondre aux besoins du programme - tout est déjà dans les listes). Un autre avantage est que le programme sait quel ordre est à l'origine de la position dans MQL4, ce qui ne peut être fait dans les versions mentionnées ci-dessus.

Je le répète, la bibliothèque est faite pour faciliter les choses à ceux qui ont trop de temps et d'argent pour tout faire eux-mêmes. Je n'insiste sur rien, bien sûr :)

 
Aleksandr Volotko:

Et c'est ainsi. Si le nombre d'ordres ouverts ne change pas, le nombre dans l'historique changera.(Je ne me soucie pas des ordres en attente - je ne les utilise pas). Et vous n'avez pas besoin d'ennuyer votre grand-mère en passant en revue les ordres toute la journée pour ne retenir qu'un seul événement.

Et si l'utilisateur a reçu un SMS et a décidé d'afficher l'historique dans le terminal au lieu de tout afficher seulement pour le dernier mois, ce sera un contrôle supplémentaire avec l'essai de toutes les commandes, ce qui n'est pas fatal.

Cela semble être une bonne solution. Si vous disposez d'un compte de trading et d'un terminal, vous pouvez utiliser uniquement ce que vous avez sans être lié à quoi que ce soit.

Afin de ne pas passer toute la journée, vous pouvez vérifier seulement lorsque les conditions qui peuvent conduire à un changement, l'ouverture, la fermeture d'une position, c'est-à-dire se concentrer sur la réalisation des prix que le conseiller expert utilise pour ouvrir, TP, SL. Eh bien, cela dépend de la logique du conseiller expert, vous savez ce qui est le moins cher.

 
Aleksey Mavrin:

Pour éviter de passer par toute la journée, vous pouvez vérifier uniquement lorsque les conditions qui peuvent conduire à un changement, à l'ouverture, à la fermeture d'une position ont été remplies, c'est-à-dire se concentrer sur la réalisation des prix que le Conseiller Expert utilise pour ouvrir, TP, SL. Eh bien, oui, cela dépend de la logique du conseiller expert, vous savez ce qui est moins cher.

Un seul EA (sur un seul ordinateur, sur un seul continent) effectue des transactions. L'autre (sur un autre ordinateur, sur un autre continent) s'occupe de ses fonctions. Une solution a déjà été trouvée.

 
fxsaber:

Je vous serais reconnaissant si vous pouviez fournir un exemple reproductible (sans interroger l'historique des transactions).

Voici ce que j'ai trouvé (bien que ce soit hors sujet ici, mais la question a été posée ici).

Coupez en direct. Pas de compatibilité avec MT4 (bien sûr), pas de gestion des erreurs, etc.

Le trading est primitif, il s'ouvre à l'achat et se ferme sur le SL/TP. Le seul but est de démontrer la différence entre OnTradeTransaction() et "polling the server".

Pour moi, il m'a fallu 2,34s contre 3,06s pour passer dans le temps imparti. La différence est faible en raison de la faible charge des fonctions du serveur (une seule position, pas de vérification de la magie et du symbole). Dans l'EA réelle, la différence sera beaucoup plus grande. La différence sera légèrement lissée par le calcul des signaux et l'ajout de stops suiveurs, mais il n'est pas nécessaire de les faire à chaque tick. Mon ATR est calculé sur M1, mais pour 6 heures (c'est-à-dire qu'il y a de la place pour agrandir le TF). Et le seuil de rentabilité est calculé sur H3. Tout dépend de la stratégie.

// Test OnTradeTransaction.mqh
#property version   "1.00"
#property copyright "(c)2020 Edgar Akhmadeev"
#property link      "https://www.mql5.com/en/users/dali"
// 2020.01.27

//      Primitive expert to test OnTradeTransaction().
//      BUY only one position a time. There's no any signals.
//      Try OHLC M1 EURUSD 2016.12.19-2018.04.14 (bull trend) with default SL/TP.



//#define TESTER



#define  MT4_TICKET_TYPE
#include <MT4Orders.mqh>
#include <mql4_to_mql5.mqh>



struct PosInfoBase {
        double                  price, sl, tp;
        datetime                time;
        int                     ticket;
        ENUM_ORDER_TYPE 	 type;

        #ifndef  TESTER
                int             mn;
                string          sym;
        #endif 
};

struct PosInfo {
        PosInfoBase             base;
        int                     ticket;
};



input int       SL              = 6;
input int       TP              = 900;



MqlTick         tick;
PosInfo         posInfo         = { 0 };



#ifdef  TESTER

//*************************************************************************************************************
void 
OnTradeTransaction(const MqlTradeTransaction& trans, const MqlTradeRequest& request, const MqlTradeResult& result) {
        if (trans.type == TRADE_TRANSACTION_ORDER_DELETE && trans.order_state == ORDER_STATE_PLACED) {
                // No money
                //errFatal = true;
                return;
        }
        
        static long lastTick;

        if (trans.type == TRADE_TRANSACTION_DEAL_ADD && trans.order_state == ORDER_STATE_STARTED) {
                // Open on market step1, SL/Order triggered step1, SL/Order triggered step4
                
                if (!HistoryDealSelect(trans.deal)) {
                        //errFatal = true;
                        return;
                }
                
                ENUM_DEAL_ENTRY entry = (ENUM_DEAL_ENTRY)HistoryDealGetInteger(trans.deal, DEAL_ENTRY);
                if (entry != DEAL_ENTRY_OUT)
                        return;
                
                ENUM_DEAL_REASON reason = (ENUM_DEAL_REASON)HistoryDealGetInteger(trans.deal, DEAL_REASON);
                if (reason != DEAL_REASON_SL && reason != DEAL_REASON_TP)
                        return;
                
                if (lastTick == tick.time_msc)
                        return;

                posInfo.base.ticket = 0;
                InitPos();

                lastTick = tick.time_msc;
                return;
        }
}



#else // TESTER



//*************************************************************************************************************
bool
Support() {
        posInfo.base.ticket = 0;
        
        int cnt = PosTotal();
        if (cnt > 1)
                return false;
        
        PosInfo _posInfo;
        
        if (cnt == 0)
                _posInfo.base.ticket = 0;
        else {
                PosInfoFill(_posInfo);
                _posInfo.ticket = _posInfo.base.ticket;
        }

        //-------------------------------------------------------------------------------------------------------------
        // Position: process
        
        if (_posInfo.base.ticket != 0 && posInfo.ticket != 0 && _posInfo.base.ticket == posInfo.ticket) {
                // Ничего не произошло, та же позиция
                
                posInfo.base.ticket = _posInfo.base.ticket;
                posInfo.base.time = _posInfo.base.time;
                //posInfo.base.price = _posInfo.base.price;
                posInfo.base.sl = _posInfo.base.sl;
                posInfo.base.tp = _posInfo.base.tp;
        }

        //-------------------------------------------------------------------------------------------------------------
        // Инициализация новой позиции
        
        if (posInfo.base.ticket > 0)
                return true;
        
        return InitPos();
}

#endif // TESTER



//*************************************************************************************************************
bool
InitPos() {
        if (!SymbolInfoTick(_Symbol, tick))
                return false;
        
        posInfo.base.type = ORDER_TYPE_BUY;
        posInfo.base.sl = NormalizeDouble(tick.bid - SL * Point, Digits); 
        posInfo.base.tp = NormalizeDouble(tick.bid + TP * Point, Digits);       

        ResetLastError();
        int order = OrderSend(_Symbol, posInfo.base.type, 0.01, tick.ask, 99, posInfo.base.sl, posInfo.base.tp); 
        if (order < 0)
                return false;
        
        if (!OrderSelect(order, SELECT_BY_TICKET))
                return false;

        posInfo.base.price = OrderOpenPrice();
        posInfo.ticket = posInfo.base.ticket = order;
        posInfo.base.time = tick.time;
        return true;
}



//*************************************************************************************************************
int
PosTotal() {
        int posTotal = OrdersTotal();
        int cnt = 0;
        for (int i = posTotal - 1; i >= 0; --i) {
                if (!OrderSelect(i, SELECT_BY_POS)) {
                        //errFatal = true;
                        return -1;
                }

                if (OrderType() > OP_SELL)
                        continue;

                /*
                #ifndef TESTER
                        if (OrderMagicNumber() != MagicNum)
                                continue;
                        if (OrderSymbol() != symInfo.sym)
                                continue;
                #endif 
                */
                        
                ++cnt;
        } // for
        
        return cnt;
}


        
//*************************************************************************************************************
void
PosInfoFill(PosInfo& _posInfo) {
        ZeroMemory(_posInfo);

        _posInfo.base.ticket = (int)PositionGetInteger(POSITION_TICKET);
        _posInfo.base.type = (ENUM_ORDER_TYPE)PositionGetInteger(POSITION_TYPE);
        _posInfo.base.price = PositionGetDouble(POSITION_PRICE_OPEN);
        _posInfo.base.time = (datetime)PositionGetInteger(POSITION_TIME);
        _posInfo.base.sl = PositionGetDouble(POSITION_SL);
        _posInfo.base.tp = PositionGetDouble(POSITION_TP);

        #ifndef  TESTER
                _posInfo.base.mn = (int)PositionGetInteger(POSITION_MAGIC);
                _posInfo.base.sym = PositionGetString(POSITION_SYMBOL);
        #endif 
}



//*************************************************************************************************************
void 
OnTick() {
        ResetLastError();
        if (!SymbolInfoTick(_Symbol, tick)) {
                int LE = GetLastError();
                //errFatal = true;
                return;
        }
        
        #ifdef  TESTER

                if (posInfo.base.ticket > 0)
                        return;
                
                if (!InitPos()) {
                        //errFatal = true;
                        return;
                }

        #else  // TESTER
                
                if (!Support()) {
                        //errFatal = true;
                        return;
                }
        
        #endif // TESTER
}



//*************************************************************************************************************
int 
OnInit() {
        return INIT_SUCCEEDED;
}



//*************************************************************************************************************
void 
OnDeinit(const int reason) {
}
 
prostotrader:

Vous êtes désespérément en retard sur votre temps !

Ces événements sont garantis depuis longtemps !

Supposons qu'un événement se produise dans OnTradeTransaction() après lequel une action doit être effectuée, mais qu'une erreur se produise lors de la première tentative d'exécution de cette action. Que faire ? Évidemment, elle doit être répétée, et pour cela il est nécessaire d'enregistrer quelque part des données sur la nécessité de répéter cette action - le plus souvent, ces données sont enregistrées dans les variables globales habituelles du Conseiller Expert ou dans des fonctions statiques. Et soudain, j'ai dû redémarrer le terminal... les données ont disparu.

Et quand on analyse la situation actuelle et l'histoire - rien ne va nulle part.

Raison: