Caractéristiques du langage mql5, subtilités et techniques - page 70

 

Forum sur le trading, les systèmes de trading automatisés et les tests de stratégies de trading

Comment identifier un remplacement de carte ?

fxsaber, 2018.02.08 12:39

void OnTick()
{  
  const long Chart = ChartID();
  string PrevSymbol = _Symbol;
  ENUM_TIMEFRAMES PrevTF = _Period;
    
  while (!IsStopped())
  {
    if ((PrevSymbol != ChartSymbol(Chart)) || (PrevTF != ChartPeriod(Chart))) // ноль указывать НЕЛЬЗЯ!
    {      
      PrevSymbol = ChartSymbol(Chart);
      PrevTF = ChartPeriod(Chart);
      
      Alert(PrevSymbol + " " + EnumToString(PrevTF));      
    }
    
    Sleep(0);
  }
}

Le paramètre d'entrée ChartID zéro dans certaines fonctions n'entraîne pas le recalcul des valeurs. Si vous voulez les données réelles du graphique actuel, vous devez utiliser l'ID complet.

 

Forum sur le trading, les systèmes de trading automatisés et les tests de stratégie

POSITION_TICKET != POSITION_IDENTIFIER

fxsaber, 2018.02.12 20:14

Conclusions

Si nous supposons qu'il s'agit d'un comportement normal de MT5 et non d'une particularité du hack du courtier, alors

  • ORDER_STATE_PARTIAL n'apparaît pas dans les ordres historiques.
  • Les ordres exécutés ont toujours le statut ORDER_STATE_FILLED.
  • Lorsqu'un ordre est partiellement exécuté, un nouvel ordre de marché correspondant est créé par le serveur de négociation (ORDER_REASON_CLIENT - même si l'ordre initial est placé automatiquement (EXPERT)).
  • L'ancien ordre en direct (le ticket n'est pas modifié) reste en attente avec un volume réduit (ORDER_VOLUME_CURRENT).
  • Dans ce cas, l'ancienne commande en direct reçoit le statut ORDER_STATE_PARTIAL. En fait, cet indicateur est le résultat de la comparaison de ORDER_VOLUME_CURRENT et ORDER_VOLUME_INITIAL.
  • Toutes les positions ouvertes reçoivent un ID == OrderTicket. Où OrderTicket est le ticket généré par le serveur commercial.
  • Une transaction a toujours exactement un ordre historique et son statut est ORDER_STATE_FILLED.
  • Chaque ordre historique exécuté comporte exactement une transaction.
  • Le ORDER_VOLUME_INITIAL de tout ordre exécuté est égal au volume pour lequel il a été exécuté. C'est-à-dire que même l'ordre initial qui a été annulé a un ORDER_VOLUME_INITITAL qui est égal au volume de la transaction qu'il a engendrée.
  • L'heure de l'ordre initial (qui a été partiellement exécuté) ne change pas et n'est pas égale à l'heure de sa transaction.
  • Le tableau historique est trié par heure de commande (ORDER_TIME_SETUP) mais pas par heure de transaction. Ainsi, si nous faisons HistorySelect à partir de DEAL_TIME, nous ne pouvons pas obtenir la commande correspondante dans la table d'historique.
  • HistorySelectByPosition renvoie toujours l'ensemble des transactions/ordres nécessaires.
  • Vous pouvez calculer le slippage pour n'importe quelle transaction.

Faiblesses

  • Les éléments ORDER_REASON_PARTIAL, DEAL_REASON_PARTIAL et POSITION_REASON_PARTIAL sont manquants. Ces indicateurs doivent être placés immédiatement après REASON_EXPERT dans les listes respectives.
  • Les ordres au marché correspondants, lorsqu'ils exécutent partiellement des ordres à cours limité, peuvent par nature avoir un slippage négatif. Il semble s'agir d'une erreur dans le type d'ordre uniquement et il n'y a pas vraiment d'ordre de marché - il est seulement créé à l'intérieur de MT5 et ne sort pas.

ZZY Hypothèse entièrement confirmée.

Forum sur le trading, les systèmes de trading automatisés et les tests de stratégies de trading

POSITION_TICKET != POSITION_IDENTIFIER

Pavel Kolchin, 2018.02.12 13:31

(pas sûr, difficile à vérifier, similaire à la fermeture partielle de la position)

Tout fonctionne comme ceci :

1) ordre en attente déclenché partiellement - une position avec Position_ID = Order_Ticket1 est ouverte

2) le reste de l'ordre est formé en un nouvel ordre Order_Ticket2 et attend son exécution ; le nouvel Order_Ticket2 != Order_Ticket1 car il ne peut y avoir deux ordres dans l'historique avec le même Order_Ticket

3) l'ordre restant a été exécuté - une position avec Position_ID = Order_Ticket2 est ouverte.

il y a deux ordres dans l'historique, deux positions dans le terminal, tout correspond

 

Forum sur le trading, les systèmes de trading automatisés et l'essai de stratégies de trading

Discussion sur "LifeHack for trader : mixer ForEach sur les définitions (#define)"

fxsaber, 2018.02.14 10:54

Mesure de la performance

#define  BENCH(A)                                                              \
{                                                                             \
  const ulong StartTime = GetMicrosecondCount();                              \
  A;                                                                          \
  Print("Time[" + #A + "] = " + (string)(GetMicrosecondCount() - StartTime)); \
}

double GetAsk()
{
  static MqlTick tick = {0};
  
  return(SymbolInfoTick(Symbol(),tick) ? tick.ask : 0);
}

#define  AMOUNT 1 e6

void OnStart()
{
  double Sum = 0;
  
  BENCH(for (int i = 0; i < AMOUNT; i++) Sum += GetAsk())
  BENCH(for (int i = 0; i < AMOUNT; i++) Sum += SymbolInfoDouble(_Symbol, SYMBOL_ASK))
  
  Print(Sum);
}


Résultat

Time[for(inti=0;i<AMOUNT;i++)Sum+=GetAsk()] = 78952
Time[for(inti=0;i<AMOUNT;i++)Sum+=SymbolInfoDouble(_Symbol,SYMBOL_ASK)] = 162606

J'avais totalement tort ! SymbolInfoDouble est deux fois plus lent que SymbolInfoTick.

Forum sur le trading, les systèmes de trading automatisés et les tests de stratégies de trading

Discussion sur "LifeHack for trader : mixer ForEach sur les définitions (#define)"

fxsaber, 2018.02.14 11:58

Incompétent. Résultat dans le testeur.

2017.09.01 00:00:10   Time[for(inti=0;i<AMOUNT;i++)Sum+=GetAsk()] = 87424
2017.09.01 00:00:10   Time[for(inti=0;i<AMOUNT;i++)Sum+=SymbolInfoDouble(_Symbol,SYMBOL_ASK)] = 83410

Lorsque la performance est nécessaire (Optimizer), il est préférable d'utiliser SymbolInfoDouble. Dans le monde réel, cela ne fait aucune différence.


La mesure de la vitesse de la fonction ZZY doit être effectuée dans un environnement où les performances sont importantes - Testeur.

 

Forum sur le trading, les systèmes de trading automatisés et les tests de stratégies de trading

Bugs, bugs, questions

fxsaber, 2018.02.12 23:10

Ouvrir une position BUY à la main sur deux serveurs de démonstration de trading


RoboForex-MetaTrader 5

2018.02.13 00:02:08.424 '8520459': market buy 1.00 GBPUSD
2018.02.13 00:02:10.101 '8520459': accepted market buy 1.00 GBPUSD
2018.02.13 00:02:10.101 '8520459': deal #90389019 buy 1.00 GBPUSD at 1.38387 done (based on order #107426544)
2018.02.13 00:02:10.101 '8520459': order #107426544 buy 1.00 / 1.00 GBPUSD at 1.38387 done in 1683.949 ms


FXOpen-MT5

2018.02.13 00:00:25.780 '18000903': market buy 1.00 GBPUSD
2018.02.13 00:00:25.912 '18000903': accepted market buy 1.00 GBPUSD
2018.02.13 00:00:25.922 '18000903': market buy 1.00 GBPUSD placed for execution
2018.02.13 00:00:25.942 '18000903': order #896454 buy 1.00 / 1.00 GBPUSD at market done in 154.252 ms
2018.02.13 00:00:25.942 '18000903': deal #80559 buy 1.00 GBPUSD at 1.38387 done (based on order #896454)

Les lignes de la même couleur indiquent la même chose. Cependant, on voit clairement qu'ils sont dans un ordre différent. Pour Robo, le message concernant l'exécution de l'ordre arrive après l'exécution de la transaction. En ouvert, il vient AVANT ! Pour cette raison, OrderSend renvoie la chance, mais pas encore de transaction. C'est-à-dire que nous obtenons un OrderSend non synchronisé avec l'historique.

Code pour FXOpen-MT5

#define  PRINT(A) Print(#A + " = " + (string)(A))

void OnStart()
{
  MqlTradeRequest Request = {0};
  
  Request.action = TRADE_ACTION_DEAL;
  Request.symbol = _Symbol;
  Request.volume = 1;
  Request.type_filling = ORDER_FILLING_IOC;
  
  MqlTradeResult Result;
  
  PRINT(OrderSend(Request, Result));
  PRINT(Result.deal);
}


Résultat

OrderSend(Request,Result) = true
Result.deal = 0


Cette situation a l'explication suivante

Forum sur le trading, les systèmes de trading automatisés et les tests de stratégie

Bugs, bugs, questions

Rashid Umarov, 2018.02.15 06:25

Si un ordre est envoyé à un système de négociation externe, le serveur de négociation MetaTrader 5 n'attend pas de réponse de sa part et renvoie immédiatement le résultat de la demande comme "ordre passé". Pour cette raison, OrderSend retournera toujours deal=0, car il n'y a pas encore d'information sur la transaction exécutée. Attrapez-le dans OnTrade ou OnTradeTransaction.

Un exemple d'écouteur d'événement de transaction est donné dans l'article Où commencer lors de la création d'un robot de trading pour MOEX - TradeTransactionListener.mq5

OrderSend - envoie un ordre pour exécuter une transaction sur le marché.L'ordre est passé- nous devons lire Result.order. Mais personne n'attend la ou les transactions - il peut y en avoir beaucoup et le temps total de leur exécution n'est pas défini.

Cela dépend de l'implémentation spécifique de la sortie du côté du courtier. Dans le cas général, il n'est pas défini.

Je vous recommande donc vivement d'utiliser le compte de démonstration sur FXOpen-MT5 pour tester votre code, car il se distingue des autres démos.


Par exemple, je suggère d'essayer d'écrire un script en MQL5 avec la logique de trading suivante (le style MQL4 n'est utilisé que pour un affichage rapide)

void OnStart()
{
  OrderCloseBy(OrderSend(_Symbol, OP_BUY, 1, Ask, 0, 0, 0), OrderSend(_Symbol, OP_SELL, 1, Bid, 0, 0, 0));
}

Ce n'est pas facile du tout. Je recommande également le serveur de démonstration mentionné pour travailler sur l'exécution partielle.

 
fxsaber:
Suppression d'un message qui donnait une explication sur l'une des erreurs les plus courantes sur MT5.
Il ne fait pas partie de ceux qui ont été supprimés. C'est bizarre. Pouvez-vous le réafficher ?
 
fxsaber:

Le poste était important. Je ne m'attendais pas à être supprimé. J'aimerais entendre la raison de la suppression. Parce que c'est masochiste de se faire supprimer à nouveau.

Je vous le dis, ce n'est pas parmi les effacés. Peut-être qu'il y a eu un pépin ?
 

Forum sur le trading, les systèmes de trading automatisés et les tests de stratégies de trading

Organiser une boucle de commande

fxsaber, 2018.02.16 09:40

Tout ne va pas du tout bien dans MT5. Exemple montrant le problème

// Пример неправильного считывания торгового окружения на каждом тике
// Скрипт эмулирует два тика ТС, которая должна открыть одну позицию, если ее нет.

#include <Trade/Trade.mqh>

// Возвращает количество позиций по символу
int GetAmountPositions( const string Symb )
{
  int Res = 0;
  
  // Этот MQL5-код с ошибкой
  for (int i = PositionsTotal() - 1; i >= 0; i--)
    if (PositionGetSymbol(i) == Symb)
      Res++;

/*
  // В MT4 такой код выполняется без ошибки
  for (int i = OrdersTotal() - 1; i >= 0; i--)
    if (OrderSelect(i, SELECT_BY_POS) && (OrderType() <= OP_SELL) && (OrderSymbol() == Symb))
      Res++;
*/      
  return(Res);
}

// Пример OnTick
void ExampleOnTick()
{
  static CTrade Trade;
  
  // Если нет позиции, открываем
  if (!GetAmountPositions(_Symbol))
    Trade.Buy(1);    
}

// Эмуляция прихода двух Tick-событий
void OnStart()
{
  ExampleOnTick(); 
  
  Sleep(10); // Между двумя тиками ~10 мс.
  
  ExampleOnTick();
}

Pensez-vous que si vous exécutez ce script sur un symbole sans positions, qu'est-ce qui va se passer ?

La réponse correcte est qu'un ou deux postes seront ouverts.

La raison pour laquelle cela se produit. Après le premier envoi d'ordre, un ordre au marché apparaît et si un nouveau tick arrive avant le moment de son exécution, il n'y a pas encore de position et le deuxième envoi d'ordre est effectué.

Pour cette raison, un modèle MT5 apparemment normalne fonctionnera pas correctement et, par conséquent, la plupart des conseillers experts MT5 de codobase. Dans le même temps, le modèle MT4, presque identique, continuera à fonctionner sans aucun problème.

L'idée apparemment bonne de PositionsTotal est quelque peu éclipsée par la nécessité, dans MT5, d'analyser également OrdersTotal pour les ordres au marché.

Faites attention !

 
fxsaber:

Pour cette raison, un modèle MT5 apparemment normalne fonctionnera pas correctement et, par conséquent, la plupart des EA MT5 de la base kodobase.

Comme preuve de cette affirmation, nous pouvons prendre presque tous les conseillers experts de la base de données MT5. Ne choisissons pas n'importe quoi mais prenons le dernier conseiller expert du moment. Il est bon qu'il ait été écrit par un auteur ayant une grande expérience de la publication de MT5 en QB.

Le code source contient les chaînes de caractères suivantes (mes commentaires sont mis en évidence)

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//....
   int total=0; // для расчета количества открытых советником позиций
//....
//--- main cycle
   for(int i=PositionsTotal()-1;i>=0;i--)
      if(m_position.SelectByIndex(i)) // selects the position by index for further access to its properties
         if(m_position.Symbol()==m_symbol.Name() && m_position.Magic()==m_magic)
           {
            total++; // расчет количества открытых позиций
//....
   if(total==0) // Если нет открытых советником позиций
     {
      if(!RefreshRates())
        {
         PrevBars=iTime(1);
         return;
        }
      //--- open BUY 
      if(MACD_MAIN_2>MACD_SIGNAL_2 && MACD_MAIN_4<MACD_SIGNAL_4) // Сигнал на покупку
        {
         double sl=(InpStopLoss!=0)?m_symbol.Ask()-ExtStopLoss:0.0;
         double tp=(InpTakeProfit!=0)?m_symbol.Ask()+ExtTakeProfit:0.0;
         OpenBuy(sl,tp); // Отправка маркет-ордера на покупку
         return;
        }
      //--- open SELL
      if(MACD_MAIN_2<MACD_SIGNAL_2 && MACD_MAIN_4>MACD_SIGNAL_4) // Сигнал на продажу
        {
         double sl=(InpStopLoss!=0)?m_symbol.Bid()+ExtStopLoss:0.0;
         double tp=(InpTakeProfit!=0)?m_symbol.Bid()-ExtTakeProfit:0.0;
         OpenSell(sl,tp); // Отправка маркет-ордера на продажу
        }
     }
   return;
  }

Nous sommes dans une situation identique à celle décrite ci-dessus.

Forum sur le trading, les systèmes de trading automatisés et les tests de stratégie

Particularités du langage mql5, trucs et astuces

fxsaber, 2018.02.16 19:52

Après le premier envoi d'ordre, un ordre au marché apparaît et si un nouveau tick arrive avant son exécution, il n'y a pas encore de position et un deuxième envoi d'ordre est effectué.

L'idée apparemment bonne de PositionsTotal est quelque peu éclipsée par la nécessité, dans MT5, d'analyser également OrdersTotal pour les ordres au marché.

Cela signifie que dans le cas général, au lieu d'une position, le conseiller expert en ouvrira deux, trois, etc. En fonction de la fréquence de réception des ticks et de la durée d'exécution des ordres de marché.


Puisque presque tous les EAs MT5 dans kodobase sont écrits avec la même logique que le modèle MT5, ils ont aussi le même bug qui est contenu dans celui-ci. C'est le cas de presque tous les EA de MT5 dans KB, malheureusement.

MACD EA
MACD EA
  • votes : 4
  • 2018.02.15
  • Vladimir Karputov
  • www.mql5.com
При поступлении сигнала противоположная позиция закрывается. Также советник может закрывать половину позиции (параметр Profit for closing half of the position), может переводить позицию в безубыток (параметр Breakeven). Размер открываемой позиции может задавать вручную (параметр Lots) или в процентах риска от свободной маржи (параметр Risk in...
 

Sur un netting, il peut y avoir une position ouverte et plusieurs ordres de marché dans un sens ou dans l'autre sur le même symbole au même moment. Par exemple, une position BUY et un ordre BUY. C'est vrai, je n'ai pas réussi à trouver un tel compte de démonstration, car il y avait une règle avec l'asynchronie partout.

Forum sur le trading, les systèmes de trading automatisés et les tests de stratégies de trading

Bugs, bugs, questions

fxsaber, 2018.02.14 08:58

L'ensemble de la séquence d'événements OnTradeTransaction intervient après l'envoi de l'ordre.

EA

void OnTradeTransaction ( const MqlTradeTransaction &Trans, const MqlTradeRequest&, const MqlTradeResult& )
{ 
  static bool FirstRun = true;  
  static ulong StartTime;
  
  if (FirstRun)
  {
    StartTime = GetMicrosecondCount();
    
    FirstRun = false;
  }

  Print(EnumToString(Trans.type));
  Print((GetMicrosecondCount() - StartTime) / 1000);    
}

Envoi manuel d'un ordre de transaction.

Journal de bord

2018.02.14 09:41:46.671 '8854170': instant sell 1.00 EURUSD at 1.23673
2018.02.14 09:41:46.853 '8854170': accepted instant sell 1.00 EURUSD at 1.23673
2018.02.14 09:41:46.853 '8854170': deal #192088422 sell 1.00 EURUSD at 1.23673 done (based on order #208541700)
2018.02.14 09:41:46.853 '8854170': order #208541700 sell 1.00 / 1.00 EURUSD at 1.23673 done in 190.608 ms


Résultat du conseiller expert

2018.02.14 09:41:46.853 TRADE_TRANSACTION_ORDER_ADD
2018.02.14 09:41:46.853 0
2018.02.14 09:41:46.853 TRADE_TRANSACTION_DEAL_ADD
2018.02.14 09:41:46.853 1
2018.02.14 09:41:46.853 TRADE_TRANSACTION_ORDER_DELETE
2018.02.14 09:41:46.853 1
2018.02.14 09:41:46.853 TRADE_TRANSACTION_HISTORY_ADD
2018.02.14 09:41:46.853 2
2018.02.14 09:41:46.853 TRADE_TRANSACTION_REQUEST
2018.02.14 09:41:46.853 2


Nous pouvons parfaitement voir à partir de la colonne de temps et des données numériques de l'EA que la durée d'exécution de l'ordre de transaction n'a aucun effet sur la séquence des événements OnTradeTransaction. Toute l'asynchronie part en vrille ! Ils ont réussi à tout gâcher. Construire 1755.

Par exemple, lorsque l'ordre de marché OrderSendAsync est placé dans le Terminal, l'ordre de marché n'apparaîtra même pas un instant. Les développeurs ont peut-être décidé de faire cela pour accélérer un peu les choses.

 

Forum sur le trading, les systèmes de trading automatisé et les tests de stratégies de trading

Discussion de l'article "Visualisation de l'optimisation des stratégies commerciales dans MetaTrader 5".

fxsaber, 2018.02.22 08:39

En mode cadre, OnInit, OnDeinit, OnTick, OnTrade, OnTradeTransaction et OnTimer sont ignorés. Seul OnChartEvent fonctionne.

Bien sûr, en raison de l'exception OnChartEvent, il faut obligatoirement vérifier l'indicateur frame-mode.

Raison: