Diskussion zum Artikel "Fortgeschrittene Algorithmen für die Auftragsausführung in MQL5: TWAP, VWAP und Eisberg-Aufträge"

 

Neuer Artikel Fortgeschrittene Algorithmen für die Auftragsausführung in MQL5: TWAP, VWAP und Eisberg-Aufträge :

Ein MQL5-Framework, das den Algorithmus der Ausführung auf institutionellem Niveau (TWAP, VWAP, Iceberg) über einen einheitlichen Ausführungsmanager und einen Performance-Analysator für eine reibungslosere, präzisere Auftragsaufteilung und -analyse für Einzelhändler bereitstellt.

„Sicher“, könnten Sie mit den Schultern zucken, „aber ich werde keine institutionellen Summen verschieben“. Der Clou: Das müssen Sie nicht. Ganz gleich, ob Sie ein halbes Los oder eine Handvoll Minilose einsetzen, die Volatilität kann Ihre Ausführung immer noch beeinträchtigen. Diese Werkzeuge helfen Ihnen:

  • Eingrenzen des Slippage: Selbst bescheidene Aufträge können sich in unruhigen Märkten verschieben.
  • Schärfen Sie Ihre Kanten: Bei gestaffelten Ausführungen erzielen Sie oft einen günstigeren Durchschnittspreis als bei einem einmaligen Glücksspiel.
  • Ruhig bleiben: Automatisierte Arbeitsabläufe nehmen der Versuchung, in Panik zu kaufen oder zu verkaufen, den Schrecken.
  • Geschmeidig skalieren: Auch wenn Ihr Konto wächst, bleibt die Ausführung knackig - egal wie umfangreich Ihre Aufträge werden.
  • Fliegen Sie unter dem Radar: Vor allem Eisberg-Aufträge verschleiern Ihre wahre Auftragsgröße und lassen neugierige Algos im Dunkeln.

Die heutige demokratisierte Landschaft bedeutet, dass die gleiche Ausführungstechnologie, die früher Millionenbudgets erforderte, jetzt auf Ihrer persönlichen Handelsstation laufen kann. Indem Sie den ausgefeilten MQL5-Code für TWAP-, VWAP- und Iceberg-Strategien in Ihre Plattform einfügen, rüsten Sie sich mit institutioneller Feuerkraft aus - ohne jemals den Einzelhandelsbereich zu verlassen.


Autor: N Soumik

 

Toller Artikel!

Welche Paare empfehlen Sie für diesen Algo?

Welche Zeitrahmen? M5, M30 usw.

Welche Session?

Vielen Dank und herzliche Grüße

 
Great Article
Testing your algo.
IN file, ExecutionAlgorithm.mqh, added this line request.type_filling = ORDER_FILLING_IOC; in placing order to fix order placing issue.
Zurück getestet es auf M5, es öffnete nur 1 Handel für 2 Monate Zeitraum, keine partielle Bestellung geöffnet.
Getestet es auf H1, es nie angewendet, die SL oder TP und alle Trades geschlossen in Verlust.

auch während der Kompilierung erzeugt es Warnungen
möglicher Datenverlust aufgrund der Typkonvertierung von 'long' zu 'double' VWAP.mqh 271 41
möglicher Datenverlust aufgrund der Typumwandlung von 'long' in 'double' VWAP.mqh 272 22
möglicher Datenverlust durch Typkonvertierung von 'long' nach 'double' VWAP.mqh 449 17
möglicher Datenverlust durch Typkonvertierung von 'long' nach 'double' PerformanceAnalyzer.mqh 222 17
möglicher Datenverlust durch Typkonvertierung von 'long' in 'double' ExecutionManager.mqh 418 17


schlagen Sie vor, wie der Algo getestet werden soll,
Zeitrahmen. und andere Empfehlungen.
 
um die Warnungen zu beheben
auch beim Kompilieren werden Warnungen erzeugt
möglicher Datenverlust aufgrund der Typkonvertierung von 'long' nach 'double' VWAP .mqh 271 41
möglicher Datenverlust aufgrund der Typkonvertierung von 'long' nach 'double' VWAP .mqh 272 22
möglicher Datenverlust durch Typkonvertierung von 'long' nach 'double' VWAP .mqh 449 17
möglicher Datenverlust durch Typkonvertierung von 'long' nach 'double' PerformanceAnalyzer .mqh 222 17
möglicher Datenverlust durch Typkonvertierung von 'long' nach 'double' ExecutionManager .mqh 418 17


Ich habe die Codezeile
m_volumeProfile[intervalIndex] += rates[i].tick_volu

in
geändert.
m_volumeProfile[intervalIndex] += (double)rates[i].tick_volume;

Es behebt die Warnungen
Jetzt brauchen Sie guidence in Bezug auf meine anderen Fragen, wie
Zeitrahmen
und auch
warum alle Trades während Backtest Ergebnis in Verlust
wie man diese große Arbeit von Ihnen zu testen.
 
i_vergo möglicher Datenverlust aufgrund der Typkonvertierung von 'long' zu 'double' VWAP.mqh 271 41
möglicher Datenverlust aufgrund der Typumwandlung von 'long' in 'double' VWAP.mqh 272 22
möglicher Datenverlust durch Typkonvertierung von 'long' nach 'double' VWAP.mqh 449 17
möglicher Datenverlust durch Typkonvertierung von 'long' nach 'double' PerformanceAnalyzer.mqh 222 17
möglicher Datenverlust durch Typkonvertierung von 'long' in 'double' ExecutionManager.mqh 418 17


schlagen Sie vor, wie der Algo getestet werden soll,
Zeitrahmen. und andere Empfehlungen.

Die Warnungen sind nicht das Problem, könnten aber schnell behoben werden. Aber ja, es wäre toll, wenn der Autor Schritt für Schritt zeigen könnte, welche Einstellungen und Eingaben er für den Backtest verwendet hat.

 

Ich stimme Dominic zu, da die Warnungen nur Warnungen sind. Die Ergebnisse von I_Virgo sind wahrscheinlich darauf zurückzuführen, dass er den falschen Zeitrahmen und das falsche Währungspaar verwendet hat. Aus dem Backtest-Bericht mit fast 2000 Bars geht hervor, dass es entweder M1 oder M5 als Zeitrahmen mit einem unbekannten Paar war.

Es wäre schön, wenn MQ den Zeitrahmen und das Währungspaar oder die Währungspaare hinzufügen und auch die Paar-Ergebnisse in mehr Details zum Back-Test-Bericht trennen würde, so dass wir die Back-Test-Ergebnisse des Autors genauer replizieren und seine Anwendbarkeit auf die Forex-Paare bestimmen könnten. Außerdem wäre es äußerst hilfreich, wenn der EA Text auf das Diagramm schreiben könnte, während er läuft.


Ich denke auch, dass es ein großartiger Artikel ist und plane, ihn gründlich zu studieren, um seine Techniken auf andere EAs zu übertragen.


CapeCoddah

 
//+------------------------------------------------------------------+
//| Basisklasse für alle Ausführungsalgorithmen|
//+------------------------------------------------------------------+
class CExecutionAlgorithm
{
protected:
   string            m_symbol;           // Handelssymbol
   double            m_totalVolume;      // Gesamtvolumen für die Ausführung
   double            m_executedVolume;   // Volumen bereits ausgeführt
   double            m_remainingVolume;  // Verbleibendes Volumen zur Ausführung
   datetime          m_startTime;        // Startzeitpunkt der Ausführung
   datetime          m_endTime;          // Endzeitpunkt der Ausführung
   int               m_slippage;         // Erlaubter Schlupf in Punkten
   bool              m_isActive;         // Ist der Algorithmus derzeit aktiv
   
   // Statistik
   double            m_avgExecutionPrice; // Durchschnittlicher Ausführungspreis
   int               m_totalOrders;       // Gesamtzahl der erteilten Aufträge
   int               m_filledOrders;      // Anzahl der ausgeführten Aufträge
   
public:
   // Konstrukteur
   CExecutionAlgorithm(string symbol, double volume, datetime startTime, datetime endTime, int slippage);
   
   // Destruktor
   virtual ~CExecutionAlgorithm();
   
   // Virtuelle Methoden, die von abgeleiteten Klassen implementiert werden müssen
   virtual bool      Initialize();
   virtual bool      Execute() = 0;
   virtual bool      Update() = 0;
   virtual bool      Terminate() = 0;
   
   // Gemeinsame Methoden
   bool              IsActive() { return m_isActive; }
   double            GetExecutedVolume() { return m_executedVolume; }
   double            GetRemainingVolume() { return m_remainingVolume; }
   double            GetAverageExecutionPrice() { return m_avgExecutionPrice; }
   
   // Hilfsmethoden
   bool              PlaceOrder(ENUM_ORDER_TYPE orderType, double volume, double price = 0.0);
   bool              ModifyOrder(ulong ticket, double price, double sl, double tp);
   bool              CancelOrder(ulong ticket);
   void              UpdateAverageExecutionPrice(double price, double volume);
   
   // Hilfsmethode zur Ermittlung des geeigneten Füllmodus
   ENUM_ORDER_TYPE_FILLING GetFillingMode();
};

//+------------------------------------------------------------------+
//| Konstruktor|
//+------------------------------------------------------------------+
CExecutionAlgorithm::CExecutionAlgorithm(string symbol, double volume, 
                                       datetime startTime, datetime endTime, 
                                       int slippage)
{
   m_symbol = symbol;
   m_totalVolume = volume;
   m_executedVolume = 0.0;
   m_remainingVolume = volume;
   m_startTime = startTime;
   m_endTime = endTime;
   m_slippage = slippage;
   m_isActive = false;
   
   m_avgExecutionPrice = 0.0;
   m_totalOrders = 0;
   m_filledOrders = 0;
}

//+------------------------------------------------------------------+
//| Destruktor|
//+------------------------------------------------------------------+
CExecutionAlgorithm::~CExecutionAlgorithm()
{
   // Ressourcen bereinigen, falls erforderlich
}

//+------------------------------------------------------------------+
//| Initialisierung des Algorithmus|
//+------------------------------------------------------------------+
bool CExecutionAlgorithm::Initialize()
{
   // Eingaben validieren
   if(m_symbol == "" || m_totalVolume <= 0.0)
   {
      Print("Invalid inputs for execution algorithm");
      return false;
   }
   
   // Prüfen, ob das Symbol existiert
   if(!SymbolSelect(m_symbol, true))
   {
      Print("Symbol not found: ", m_symbol);
      return false;
   }
   
   // Statistik zurücksetzen
   m_executedVolume = 0.0;
   m_remainingVolume = m_totalVolume;
   m_avgExecutionPrice = 0.0;
   m_totalOrders = 0;
   m_filledOrders = 0;
   
   return true;
}

//+------------------------------------------------------------------+
//| Geeigneten Füllmodus für das Symbol holen |
//+------------------------------------------------------------------+
ENUM_ORDER_TYPE_FILLING CExecutionAlgorithm::GetFillingMode()
{
   // Abrufen von Symbolfüllmodi
   int filling_modes = (int)SymbolInfoInteger(m_symbol, SYMBOL_FILLING_MODE);
   
   // Prüfen Sie die verfügbaren Befüllungsmodi in der Reihenfolge ihrer Präferenz
   if((filling_modes & SYMBOL_FILLING_FOK) == SYMBOL_FILLING_FOK)
      return ORDER_FILLING_FOK;
   else if((filling_modes & SYMBOL_FILLING_IOC) == SYMBOL_FILLING_IOC)
      return ORDER_FILLING_IOC;
   else
      return ORDER_FILLING_RETURN;
}

//+------------------------------------------------------------------+
//| Eine Bestellung aufgeben|
//+------------------------------------------------------------------+
bool CExecutionAlgorithm::PlaceOrder(ENUM_ORDER_TYPE orderType, double volume, double price = 0.0)
{
   // Eingaben validieren
   if(volume <= 0.0)
   {
      Print("Invalid order volume");
      return false;
   }
   
   // Vorbereiten der Anfrage
   MqlTradeRequest request;
   MqlTradeResult result;
   ZeroMemory(request);
   
   request.symbol = m_symbol;
   request.volume = volume;
   request.type = orderType;
   request.deviation = m_slippage;
   request.magic = 123456; // Magische Zahl zur Identifizierung
   
   // Geeignete Aktion und Preis je nach Auftragsart festlegen
   if(orderType == ORDER_TYPE_BUY || orderType == ORDER_TYPE_SELL)
   {
      // Marktauftrag
      request.action = TRADE_ACTION_DEAL;
      request.type_filling = GetFillingMode();
      
      if(orderType == ORDER_TYPE_BUY)
         request.price = SymbolInfoDouble(m_symbol, SYMBOL_ASK);
      else
         request.price = SymbolInfoDouble(m_symbol, SYMBOL_BID);
   }
   else
   {
      // Schwebende Bestellung
      request.action = TRADE_ACTION_PENDING;
      if(price <= 0.0)
      {
         Print("Price must be specified for pending orders");
         return false;
      }
      request.price = price;
   }
   
   // Senden Sie die Bestellung
   if(!OrderSend(request, result))
   {
      Print("OrderSend error: ", GetLastError());
      return false;
   }
   
   // Prüfen Sie das Ergebnis
   if(result.retcode != TRADE_RETCODE_DONE)
   {
      Print("OrderSend failed with code: ", result.retcode, " - ", result.comment);
      return false;
   }
   
   // Statistiken aktualisieren
   m_totalOrders++;
   
   // Bei Marktaufträgen wird die Ausführungsstatistik sofort aktualisiert.
   if(orderType == ORDER_TYPE_BUY || orderType == ORDER_TYPE_SELL)
   {
      m_filledOrders++;
      UpdateAverageExecutionPrice(request.price, volume);
      m_executedVolume += volume;
      m_remainingVolume -= volume;
   }
   
   Print("Order placed successfully. Ticket: ", result.order, " Volume: ", volume, " Price: ", request.price);
   
   return true;
}

//+------------------------------------------------------------------+
//| Ändern einer bestehenden Bestellung|
//+------------------------------------------------------------------+
bool CExecutionAlgorithm::ModifyOrder(ulong ticket, double price, double sl, double tp)
{
   // Vorbereiten der Anfrage
   MqlTradeRequest request;
   MqlTradeResult result;
   ZeroMemory(request);
   
   request.action = TRADE_ACTION_MODIFY;
   request.order = ticket;
   request.price = price;
   request.sl = sl;
   request.tp = tp;
   
   // Senden Sie die Änderungsanfrage
   if(!OrderSend(request, result))
   {
      Print("OrderModify error: ", GetLastError());
      return false;
   }
   
   // Prüfen Sie das Ergebnis
   if(result.retcode != TRADE_RETCODE_DONE)
   {
      Print("OrderModify failed with code: ", result.retcode, " - ", result.comment);
      return false;
   }
   
   Print("Order modified successfully. Ticket: ", ticket);
   
   return true;
}

//+------------------------------------------------------------------+
//| Stornieren einer bestehenden Bestellung|
//+------------------------------------------------------------------+
bool CExecutionAlgorithm::CancelOrder(ulong ticket)
{
   // Vorbereiten der Anfrage
   MqlTradeRequest request;
   MqlTradeResult result;
   ZeroMemory(request);
   
   request.action = TRADE_ACTION_REMOVE;
   request.order = ticket;
   
   // Senden Sie die Stornierungsanfrage
   if(!OrderSend(request, result))
   {
      Print("OrderCancel error: ", GetLastError());
      return false;
   }
   
   // Prüfen Sie das Ergebnis
   if(result.retcode != TRADE_RETCODE_DONE)
   {
      Print("OrderCancel failed with code: ", result.retcode, " - ", result.comment);
      return false;
   }
   
   Print("Order cancelled successfully. Ticket: ", ticket);
   
   return true;
}

//+------------------------------------------------------------------+
//| Aktualisierung des durchschnittlichen Ausführungspreises|
//+------------------------------------------------------------------+
void CExecutionAlgorithm::UpdateAverageExecutionPrice(double price, double volume)
{
   // Berechnen Sie den neuen durchschnittlichen Ausführungspreis
   if(m_executedVolume > 0.0)
   {
      // Gewogener Durchschnitt der alten und neuen Preise
      m_avgExecutionPrice = (m_avgExecutionPrice * m_executedVolume + price * volume) / 
                           (m_executedVolume + volume);
   }
   else
   {
      // Erste Ausführung
      m_avgExecutionPrice = price;
   }
}
//+------------------------------------------------------------------+