Typische Fehler und wie man damit umgeht, wenn man mit dem Handelsumfeld zu tun hat

 
In diesem Thread werden wir häufige Fehler bei der Arbeit mit der Handelsumgebung des Terminals in einigen Algorithmen, Methoden zu ihrer Beseitigung und Vermeidung in der Zukunft zu diskutieren.
 
GUT.
Nur zur Einführung:
Der Expert Advisor analysiert die Richtung (oder den Gewinn, ... ) der letzten geschlossenen Order. Die letzte Bestellung wurde vor 2 Tagen abgeschlossen.
Der Händler hat die Tiefe der Historie auf 1 Tag eingestellt.
OrdersHistoryTotal() sieht diese Bestellung nicht.
Die Lösung?
 
Andrei Fandeev:
Gut.
Nur zur Einführung:
Der Expert Advisor analysiert die Richtung (oder den Gewinn, ... ) der letzten geschlossenen Order. Die letzte Bestellung wurde vor 2 Tagen abgeschlossen.
Und der Händler setzt die Tiefe der Historie auf 1 Tag.
OrdersHistoryTotal() sieht diese Bestellung nicht.
Lösung?

Für MT4 - meiner Meinung nach eindeutig, geben Sie dem Benutzer eine Warnung beim Start des EA, um die erforderliche Tiefe der Geschichte zu verwenden.

MT5 ermöglicht das Laden der Historie bis zur gewünschten Tiefe.

 
Artyom Trishkin:

Für MT4 - meiner Meinung nach eindeutig, geben Sie dem Benutzer eine Warnung beim Start des EA, um die erforderliche Tiefe der Geschichte zu verwenden.

Sich auf den Nutzer zu verlassen, ist eine schlechte Idee. Es muss eine Kontrolle geben.
Artem, in MT4 habe ich keine Möglichkeit gefunden, den Wert der eingestellten Historientiefe zu ermitteln.
Ist es wirklich unmöglich, sie programmatisch zu erhalten?

 
Andrei Fandeev:

Sich auf den Nutzer zu verlassen, ist eine schlechte Idee. Sie brauchen einen Scheck.
Artem, in MT4 konnte ich nicht finden, um den Wert der eingestellten Historientiefe zu erhalten.
Ist es wirklich unmöglich, sie programmatisch zu erhalten?

In der Tat.

 

Es gibt zwei Paradigmen für die Arbeit mit der Handelsumgebung und das Schreiben von EAs.

  1. Ereigniseingänge (OnTick, OnTimer usw.) hängen voneinander ab. Es gibt Informationen, die zwischen den Ereignissen vorhanden sein MÜSSEN (nicht für die Geschwindigkeit, wie beim Cache, sondern für die Benutzerfreundlichkeit). Zum Beispiel müssen wir das Ergebnis von OrderSendAsync speichern und in OnTradeTransaction verwenden. Caches sind KEINE Pflichtangaben und dienen nur der Beschleunigung. Deshalb ziehen wir sie nicht sofort in Betracht.
  2. Ereigniseingänge (OnTick, OnTimer, usw.) sind NICHT voneinander abhängig. Jede Eingabe erfolgt von Grund auf neu. Ungefähr wie ein Skript, das Sie bei jedem Ereignis selbst ausführen.
In MT4 könnten Sie wahrscheinlich alles über die zweite Option lösen. MT5 ist nicht so eindeutig.


Vorteile der zweiten Option gegenüber der ersten

  • Sie können den Algorithmus an jeder beliebigen Stelle (normal und abnormal) beenden.
  • Sie können den Algorithmus an jeder beliebigen Stelle starten oder fortsetzen.
  • Hohe Zuverlässigkeit.


Benachteiligungen

  • In Tester wird der ersten Variante in Bezug auf die Leistung unterlegen sein.
  • Die Logik "von Grund auf" zwingt Sie dazu, etwas "unlogischen" Code zu schreiben, woran Sie sich in der ersten Zeit gewöhnen müssen.

 

Wie vergleiche ich APIs von Handelsumgebungen? Führen Sie eine große Vielfalt an verschiedenen TS ein. Und stellen wir uns unsere ideale virtuelle API vor, die es mit minimalem Aufwand ermöglichen würde, die TS in einen zuverlässigen Code einzubetten.

Wenn es möglich ist, diese sehr ideale virtuelle API als Wrapper einer realen API zu erstellen, dann ist die ursprüngliche API ausgezeichnet. Auch wenn es viel Mühe und Zeit kostet, einen Wrapper zu erstellen.


MT4 und MT5 sind nach diesem Kriterium hervorragende APIs. Nur die Quell-APIs sind schwierig, aber sie erlauben es (ohne architektonische/technische Einschränkungen), einen großartigen Wrapper zu schreiben, und sind daher gut.

Wenn sie also sagen, dass MT5 komplexer ist als MT4, meinen sie damit, dass sie noch keinen MT5-Wrapper gefunden haben (vielleicht wurde er noch nicht geschrieben), der so benutzerfreundlich ist wie der MT4-Wrapper, den sie verwenden.


Im Allgemeinen ermöglichen beide Plattformen die Erstellung einer einzigen High-Level-API (Wrapper) aus Low-Level-APIs. Die Komplexität der APIs ihrer Handelsumgebungen ist also gleich!

 

MT4 hat eine ziemlich anspruchsvolle API, so dass nur wenige Leute versuchen, einen allgemein benutzerfreundlicheren Wrapper zu schreiben. Aber das ist nicht der Fall mit MT5 - die ursprüngliche Low-Level-API gerade ERFORDERLICH, eine Art von Wrapper zu schreiben. Es macht also wenig Sinn, die Eigenschaften der einzelnen Wrapper in diesem Thread zu diskutieren. Vielmehr ist es wichtig zu zeigen, dass ein Wrapper weiterhin erforderlich ist. Welche Merkmale einer Low-Level-API müssen beim Schreiben einer High-Level-API berücksichtigt werden?

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

Ausgehend von dieser Aussage müssen wir lernen, wie man MT5-Code schreibt, der dem MT4-Code in Bezug auf die Benutzerfreundlichkeit nicht unterlegen ist. Die API-Wrapper können unterschiedlich sein (in der Regel die Syntax), aber architektonisch sollte MT5 nicht schlechter sein als MT4, da sonst die hervorgehobene Aussage verloren geht. Daher sollte der umständlichere MT5-Code nicht als Grund zur Kritik gesehen werden, sondern als Hilfe, ihn in einen nicht weniger benutzerfreundlichen Wrapper als MT4 zu packen.

 
Nehmen wir ein einfaches MT4-Template TS

Forum zum Thema Handel, automatisierte Handelssysteme und Testen von Handelsstrategien

Organisieren einer Auftragsschleife

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);
}

Das zeigt nicht die Bequemlichkeit von MT4, sondern dient nur als Vergleichsbasis. Es ist diese untere Messlatte der Benutzerfreundlichkeit, die ein MT5-Wrapper halten sollte. Die Vorlage wurde auf der Grundlage des zweiten Paradigmas erstellt.


Es scheint, dass wir auf MT5 das Gleiche schreiben

Forum zum Thema Handel, automatisierte Handelssysteme und Testen von Handelsstrategien

Organisieren eines Auftragsüberlaufs

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);
}

Aus irgendeinem Grund schreiben manche Leute mehr Code für denselben TS. Aber dieser Code funktioniert genauso gut. Die meisten TCs erfordern nur das Schreiben von BuySignal und SellSignal. Mehr ist nicht nötig.

Die Beispielvorlage ist speziell mit SB geschrieben. Also Frage an MT5-Experten, ist der Code korrekt?


Die Funktion, für die ein Wrapper erforderlich ist, ist rot markiert. Das Problem wird hier beschrieben. Manch einer wird sich daran erinnern, dass dies das uralte Problem der Wiedereröffnung von Positionen ist, das früher mit Sleep gelöst wurde, indem man darauf wartete, dass die Position nach OrderSend geöffnet wurde. Tatsächlich hat dieses Problem aber nichts mit OrderSend zu tun. Sie müssen wissen, wie Sie das Handelsumfeld richtig einschätzen können.

 
fxsaber:

Sie müssen in der Lage sein, das Handelsumfeld richtig einzuschätzen.

Mit einem einfachen Beispiel zum Ziel

// Возвращает количество позиций по символу
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);
}

Kurz gesagt: Wenn es einen Marktauftrag gibt, ist er auch als "Position" zu betrachten. In Anführungszeichen, denn es handelt sich um eine verpackte Position. Der hervorgehobene Code wird normalerweise nirgendwo angezeigt. Sie vermeidet jedoch die Wiedereröffnung von Positionen. Das Interessanteste ist hier in rot hervorgehoben. Die Notwendigkeit dieses Chips ist nicht sofort ersichtlich.

Es geht darum, dass es so genannte "closing market orders" gibt. Die gleiche SL/TP. Natürlich möchten wir solche Marktaufträge nicht als "Positionen" sehen. Und wir möchten nicht, dass diese Aufträge, die wir erteilt haben, auch noch geschlossen werden. Die hervorgehobene Bedingung ist also der geeignete Filter.


ZZZ fügen Sie diesen Code hier ein und überprüfen Sie das Ergebnis auf dem Demoserver.

 
fxsaber:

Die richtige Option anhand eines einfachen Beispiels

Kurz gesagt: Wenn es einen Marktauftrag gibt, betrachten Sie ihn auch als "Position". In Anführungszeichen, denn es handelt sich um eine verpackte Position. Der hervorgehobene Code wird normalerweise nirgendwo angezeigt. Sie vermeidet jedoch die Wiedereröffnung von Positionen. Das Interessanteste ist hier in rot hervorgehoben. Die Notwendigkeit dieses Chips ist nicht sofort ersichtlich.

Es geht darum, dass es so genannte "closing market orders" gibt. Die gleiche SL/TP. Natürlich möchten wir solche Marktaufträge nicht als "Positionen" sehen. Und wir möchten nicht, dass diese Aufträge, die wir erteilt haben, auch noch geschlossen werden. Die hervorgehobene Bedingung ist also der geeignete Filter.


HZ diesen Code hier einfügen und das Ergebnis auf dem Demoserver überprüfen.

Frage: Was passiert, wenn nach dem Senden eines Handelsauftrags bis zum nächsten Tick der Marktauftrag vom Server nicht erteilt wird?

Grund der Beschwerde: