Les erreurs typiques et la façon de les traiter dans l'environnement de négociation

 
Dans ce fil, nous discuterons des erreurs courantes commises lors de l'utilisation de l'environnement de trading du terminal dans certains algorithmes, des méthodes pour les éliminer et les éviter à l'avenir.
 
OK.
En guise d'introduction :
L'Expert Advisor analyse la direction (ou le profit, ... ) du dernier ordre clôturé. La dernière commande a été clôturée il y a 2 jours.
Le trader a fixé la profondeur de l'historique à 1 jour.
OrdersHistoryTotal() ne voit pas cette commande.
La solution ?
 
Andrei Fandeev:
Ok.
En guise d'introduction :
L'Expert Advisor analyse la direction (ou le profit, ... ) du dernier ordre clôturé. La dernière commande a été clôturée il y a 2 jours.
Et le trader a défini la profondeur de l'historique à 1 jour.
OrdersHistoryTotal() ne voit pas cette commande.
La solution ?

Pour MT4 - à mon avis, sans ambiguïté, donner à l'utilisateur un avertissement lors du lancement de l'EA pour utiliser la profondeur d'historique requise.

MT5 permet de charger l'historique à la profondeur requise.

 
Artyom Trishkin:

Pour MT4 - à mon avis, sans ambiguïté, donner à l'utilisateur un avertissement lors du lancement de l'EA pour utiliser la profondeur d'historique requise.

S'en remettre à l'utilisateur est une mauvaise idée. Il doit y avoir un contrôle.
Artem, dans MT4, je n'ai pas trouvé de Get pour obtenir la valeur de la profondeur de l'historique défini.
Est-il vraiment impossible de l'obtenir par voie programmatique ?

 
Andrei Fandeev:

S'en remettre à l'utilisateur est une mauvaise idée. Vous avez besoin d'un chèque.
Artem, dans MT4 je n'ai pas pu trouver le Get pour obtenir la valeur de la profondeur de l'historique défini.
Est-il vraiment impossible de l'obtenir par voie programmatique ?

En effet.

 

Il existe deux paradigmes pour travailler avec l'environnement de trading et écrire des EAs.

  1. Les entrées d'événements (OnTick, OnTimer, etc.) dépendent les unes des autres. Il y a des informations qui DOIVENT se trouver entre les événements (pas pour la vitesse, comme le cache, mais pour la convivialité). Par exemple, nous devons sauvegarder le résultat de OrderSendAsync et l'utiliser dans OnTradeTransaction. Les caches ne sont PAS des informations obligatoires et ne sont utilisés que pour accélérer le processus. C'est pourquoi nous ne les considérons pas tout de suite.
  2. Les entrées d'événements (OnTick, OnTimer, etc.) ne sont PAS dépendantes les unes des autres. Chaque entrée est faite à partir de zéro. En gros, c'est comme un script que vous exécutez vous-même à chaque événement.
Dans MT4, vous pourriez probablement tout résoudre grâce à la deuxième option. Le cas de MT5 n'est pas aussi tranché.


Avantages de la deuxième option par rapport à la première

  • Vous pouvez interrompre l'algorithme à tout moment (normal et anormal).
  • Vous pouvez commencer/continuer l'algorithme à n'importe quel endroit.
  • Haute fiabilité.


Inconvénients

  • In Tester sera inférieur à la première variante en termes de performances.
  • La logique "from scratch" vous oblige à écrire un code quelque peu "illogique", auquel il faut s'habituer dans un premier temps.

 

Comment comparer les API des environnements de négociation ? Présentez une grande variété de TS différents. Et imaginons notre API virtuelle idéale, qui permettrait avec un effort minimal d'incarner le TS dans un code fiable.

S'il est possible de créer cette API virtuelle idéale en tant qu'enveloppe d'une API réelle, alors l'API originale est excellente. Malgré tout l'effort et le temps qu'il faut pour créer un wrapper.


MT4 et MT5 sont d'excellentes API selon ce critère. Seules les API sources sont difficiles, mais elles permettent (sans contraintes architecturales/techniques) d'écrire un excellent wrapper, et sont donc bonnes.

Ainsi, lorsqu'ils disent que MT5 est plus complexe que MT4, ils veulent dire qu'ils n'ont pas encore rencontré de wrapper MT5 (peut-être n'a-t-il pas encore été écrit) qui soit aussi convivial que le wrapper MT4 qu'ils utilisent.


D'une manière générale, les deux plateformes vous permettent de créer une seule API de haut niveau (wrapper) à partir d'API de bas niveau. La complexité des API de leur environnement commercial est donc égale !

 

MT4 dispose d'une API de très haut niveau, de sorte que peu de personnes essaient d'écrire une enveloppe plus conviviale pour tous. Mais ce n'est pas le cas avec MT5 - l'API de bas niveau d'origine nécessite simplement d'écrire une sorte de wrapper. Il n'y a donc pas beaucoup d'intérêt à discuter des caractéristiques de chaque wrapper dans ce fil de discussion. Il est plutôt important de montrer qu'un wrapper sera toujours nécessaire. Quelles caractéristiques d'une API de bas niveau doivent être prises en compte lors de l'écriture d'une API de haut niveau.

В общем, обе платформы позволяют из низкоуровневых API создать единый высокоуровневый API (обертка). Так что сложности API торговых окружений у них равны!

Sur la base de cette affirmation, nous devons apprendre à écrire du code MT5 qui n'est pas inférieur au code MT4 en termes de convivialité. Les enveloppes d'API peuvent être différentes (syntaxe généralement), mais l'architecture de MT5 ne devrait pas être inférieure à celle de MT4, sinon la déclaration mise en évidence est perdue. Par conséquent, le code plus lourd de MT5 ne doit pas être considéré comme une raison de critiquer, mais comme une aide pour l'intégrer dans un emballage non moins convivial que MT4.

 
Prenons un simple modèle MT4 TS

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.15 23:19

// Шаблон большинства ТС

#property strict // обязательно

// Сигнал на покупку
bool BuySignal( const string Symb ) { return(true); }

// Сигнал на продажу
bool SellSignal( const string Symb ) { return(false); }

// Находит ордер соответствующего типа
bool OrdersScan( const string Symb, const int Type )
{
  for (int i = OrdersTotal() - 1; i >= 0; i--)
    if (OrderSelect(i, SELECT_BY_POS) && (OrderType() == Type) && (OrderSymbol() == Symb))
      return(true);    
    
  return(false);  
}

// Торговое действие на сигнал
bool Action( const string Symb, const int Type, const double Lots = 1 )
{
  bool Res = true;    
  
  // Закрыли противоположные сигналу позиции
  while ((OrdersScan(Symb, 1 - Type)) && (Res = OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), 100)));

  // Открыли позицию по сигналу
  return(Res && !OrdersScan(Symb, Type) && OrderSend(Symb, Type, Lots, SymbolInfoDouble(Symb, Type ? SYMBOL_BID : SYMBOL_ASK), 100, 0, 0));
}

// Шаблон торговой стратегии
void Strategy( const string Symb )
{
  if (BuySignal(Symb))
    Action(Symb, OP_BUY);
  else if (SellSignal(Symb))
    Action(Symb, OP_SELL);
}

void OnTick()
{
  Strategy(_Symbol);
}

Cela ne montre pas du tout la commodité de MT4, mais sert simplement de point de comparaison de base. C'est ce niveau inférieur de convivialité qu'une enveloppe MT5 devrait être en mesure d'atteindre. Le modèle est écrit sur la base du deuxième paradigme.


Il semblerait que nous écrivions la même chose sur MT5

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

Organiser un cycle de débordement des commandes

fxsaber, 2018.02.15 22:30

// Шаблон большинства ТС

#include <Trade/Trade.mqh>

// Сигнал на покупку
bool BuySignal( const string Symb ) { return(true); }

// Сигнал на продажу
bool SellSignal( const string Symb ) { return(false); }

// Находит позицию соответствующего типа
bool PositionsScan( const string Symb, const ENUM_POSITION_TYPE Type )
{
  for (int i = PositionsTotal() - 1; i >= 0; i--)
    if ((PositionGetSymbol(i) == Symb) && (PositionGetInteger(POSITION_TYPE) == Type))
      return(true);    
    
  return(false);  
}

// Торговое действие на сигнал
bool Action( const string Symb, const ENUM_POSITION_TYPE Type, const double Lots = 1 )
{
  static CTrade Trade;    
  bool Res = true;    
  
  // Закрыли противоположные сигналу позиции
  while ((PositionsScan(Symb, (ENUM_POSITION_TYPE)(1 - Type))) && (Res = Trade.PositionClose(PositionGetInteger(POSITION_TICKET))));

  // Открыли позицию по сигналу
  return(Res && !PositionsScan(Symb, Type) && (Type ? Trade.Sell(Lots, Symb) : Trade.Buy(Lots, Symb)));
}

// Шаблон торговой стратегии
void Strategy( const string Symb )
{
  if (BuySignal(Symb))
    Action(Symb, POSITION_TYPE_BUY);
  else if (SellSignal(Symb))
    Action(Symb, POSITION_TYPE_SELL);
}

void OnTick()
{
  Strategy(_Symbol);
}

Pour une raison quelconque, certaines personnes écrivent plus de code pour le même TS. Mais en fait, ce code fait tout aussi bien l'affaire. La plupart des CT ne nécessitent que l'écriture de BuySignal et SellSignal. Rien d'autre n'est nécessaire.

L'exemple de modèle est spécifiquement écrit avec SB. Alors question aux experts MT5, le code est-il correct ?


La fonction qui montre la nécessité d'un wrapper est marquée en rouge. Son problème est décrit ici. Quelqu'un se souviendra qu'il s'agit d'un ancien problème de réouverture de position qui a été résolu en utilisant Sleep dans les temps anciens, en attendant que la position s'ouvre après OrderSend. Mais en fait, ce problème n'a rien à voir avec OrderSend. Vous devez savoir comment lire correctement l'environnement de négociation.

 
fxsaber:

Vous devez être capable de lire correctement l'environnement commercial.

Un exemple simple pour bien faire les choses

// Возвращает количество позиций по символу
int GetAmountPositions( const string Symb )
{
  int Res = 0;
  
  for (int i = PositionsTotal() - 1; i >= 0; i--)
    if (PositionGetSymbol(i) == Symb)
      Res++;
      
  for (int i = OrdersTotal() - 1; i >= 0; i--)
    if (OrderGetTicket(i) && (OrderGetInteger(ORDER_TYPE) <= ORDER_TYPE_SELL) &&
        !OrderGetInteger(ORDER_POSITION_ID) && (OrderGetString(ORDER_SYMBOL) == Symb))
      Res++;  

/*
  for (int i = OrdersTotal() - 1; i >= 0; i--)
    if (OrderSelect(i, SELECT_BY_POS) && (OrderType() <= OP_SELL) && (OrderSymbol() == Symb))
      Res++;
*/      
  return(Res);
}

En résumé, le point est le suivant : s'il y a un ordre au marché, considérez-le également comme une "position". Entre guillemets, parce que c'est une position enveloppée. Le code mis en évidence n'apparaît généralement nulle part. Mais il évite de rouvrir des positions. La chose la plus intéressante ici est surlignée en rouge. La nécessité de cette puce n'est pas immédiatement apparente.

Le fait est qu'il existe des ordres de clôture du marché. Le même SL/TP. Il est évident que nous ne souhaitons pas que ces ordres de marché soient considérés comme des "positions". Et nous ne voudrions pas que les commandes que nous avons passées soient également fermées. La condition mise en évidence est donc le filtre approprié.


ZZZ collez ce code ici et vérifiez le résultat sur le serveur de démonstration.

 
fxsaber:

La bonne option à l'aide d'un exemple simple

En résumé, le point est le suivant : s'il y a un ordre au marché, considérez-le également comme une "position". Entre guillemets, parce que c'est une position enveloppée. Le code mis en évidence n'apparaît généralement nulle part. Mais il évite de rouvrir des positions. La chose la plus intéressante ici est surlignée en rouge. La nécessité de cette puce n'est pas immédiatement apparente.

Le fait est qu'il existe des ordres de clôture du marché. Le même SL/TP. Il est évident que nous ne souhaitons pas que ces ordres de marché soient considérés comme des "positions". Et nous ne voudrions pas que les commandes que nous avons passées soient également fermées. La condition mise en évidence est donc le filtre approprié.


HZ collez ce code ici et vérifiez le résultat sur le serveur de démonstration.

Question : que se passe-t-il si après avoir envoyé un ordre de transaction jusqu'au prochain tick l'ordre de marché n'est pas placé par le serveur ?

Raison: