«

»

Oct 13

Tool zur Auswertung aller Trades des MetaTrader-Accounts

Performance_in_MetaTrader

Performance overview all trades in MetaTrader

Heute möchten wir ein Tool vorstellen, welches es ermöglicht, alle geschlossenen Trades auszuwerten und anschließend die Ergebnisse auf dem Chart darzustellen.
Insbesondere für die MetaTrader Anwender, die verschiedene Expert-Advisor verwenden ist dieses Tool ein absolutes Muss, denn MetaTrader selber bietet leider keine Möglichkeit ohne dieses Plugin vernünftige Auswertungen zu erstellen.
MetaTrader bietet standardmäßig nur die Möglichkeit die Trades in einer html Historie rein chronologisch anzuzeigen. Bei dieser Auswertung erfolgt aber keine Filterung nach MagicNumber. Es ist eine rein chronologische Auflistung aller Trades, ohne die Möglichkeit irgend einer weiteren sinnvollen Filterung.

Die MagicNumber ist eine Zahl, die bei jeder OrderEröffnung durch einen Expert-Advisor oder ein Skript an den Broker geroutet werden kann. Sie ist eine Art Erkennungsmarke, an der ein Expert-Advisor aus vielen verschiedenen offenen Trades seine Trades wieder herausfindet!

Das vorgestellte Tool filtert also alle Trades nach der bereits erwähnten MagicNumber und legt je MagicNumber eine Auswertung in einem mehrdimensionalen Array an. Am Ende erfolgt auf dem Chart eine Darstellung der Anzahl der Trades je MagicNumber, unter Ausweisung von Profit/Loss in Cash je Richtung (Long / Short) und des Profit-Faktors!
Die Auswertungen sind beliebig erweiterbar, denn wie immer können alle registrierten User den MQL-Quellcode kostenlos herunterladen.
Wenn Sie also neben dem Profit-Faktor noch weitere Kennzahlen je MagicNumber haben möchten, ist dies auf Basis des vorhandenen Quellcodes sehr schnell möglich.

Aber nun zum Tool, wie haben wir das Problem gelöst?

Das Wichtigste bei einer solchen Auswertung in der man nicht weiß, wie viele Elemente (verschiedene MagicNumber Einträge) am Ende benötigt werden, ist das Arbeiten mit flexiblen Speichern. MQL ist dabei leider recht begrenzt, es gibt für solche Probleme fast ausschließlich Arrays. In C# könnten Sie auch mit Listen arbeiten, oder sogar mit Jagged-Arrays, was sich im vorliegenden Fall anbieten würde… Aber MQL ist (noch) nicht C#, bzw. enthält einfach viele komfortable Features der Programmierung nicht.
Das vorliegende 3-dimensionale Array ist wie folgt definiert

#define _taMagicNumber        0
#define _taTotalProfit        1
#define _taTotalLoss          2
#define _taTotalDuration      3
#define _taTotalTradeCounter  4
#define _taTotalTradeVolume   5

#define arrayDimensionsForDifferentTradeTypes 2
#define arrayDimensionsForDifferentParas 6
double tradeArray[1][arrayDimensionsForDifferentTradeTypes][arrayDimensionsForDifferentParas];

Ich habe also das sogenannte tradeArray angelegt und drei Dimensionen vergeben.
Die erste Dimension [1] ist der Counter, jedesmal wenn wir eine MagicNummer finden, die noch nicht im Array verwendet wird, legen wir einen neuen Array-Platz an und speichern ab dann alle Daten zu dieser MagicNummer.
Die zweite Dimension [arrayDimensionsForDifferentTradeTypes] speichert die Ergebnisse der Trades für Long und Short getrennt. Da ENUM OP_BUY in MQL für 0 steht und ENUM OP_SELL für 1, wird im gesamten Skript die Belegung auch direkt unter Verwendung von OP_BUY und OP_SELL vorgenommen.
Die dritte Dimension [arrayDimensionsForDifferentParas] speichert dann die Details der Trades zu einer gefilterten MagicNumber. Also zum Beispiel die Anzahl der Trades, oder die Summe des Volumens. Außerdem ist hier auch der Platz für die verwendete MagicNummer = _taMagicNumber

Das ganze Tool wird wieder in der Init abgespielt, es läuft also nur einmal und belastet den Rechner nicht dauerhaft.
Die Hauptstruktur des Tool sieht dabei wie folgt aus

void OnInit()
{
   newPlacesPerDimension = arrayDimensionsForDifferentTradeTypes * arrayDimensionsForDifferentParas;

   f_readAllTradesInHistoryAndFillArray();

   f_showAllInfosOnScreen();
}

Als erstes wird einmalig berechnet, wie viele Plätze zu jeder Dimension gehören. Das ist in unserem Fall die Multiplikation der zweiten und dritten Dimension. Diese Zahl wird später immer wieder benötigt, um die Dimensionierung und Platzierung der Einträge korrekt vornehmen zu können.

Die beiden folgenden Funktionen sind von Namen her eigentlich selbsterklärend, f_readAllTradesInHistoryAndFillArray ließt die gesamte Trade-Historie und füllt das Array mit den entsprechenden Werten. f_showAllInfosOnScreen plottet am Ende all Daten auf den Bildschirm.

Ein paar Anmerkungen zur Hauptfunktion, welche wie folgt aussieht

void f_readAllTradesInHistoryAndFillArray()
{
   int thisMagicNumberIsOnThisPlace = -1;
   int amountOfTradesInHist = OrdersHistoryTotal();
   for (int thisTrade = 0; thisTrade < OrdersHistoryTotal(); thisTrade++)
   {
      // ### STEP 01: selecting the trade out of the bunch of closed trades
      if (!f_selectThisTrade(thisTrade, fName, SELECT_BY_POS, MODE_HISTORY))
        continue;

      if (OrderType() != OP_BUY && OrderType() != OP_SELL)
         continue;

      totalVolumeAllTrades[OrderType()]+=OrderLots();
      totalPLAllTrades[OrderType()]+= OrderProfit() + OrderSwap() + OrderCommission();
      totalTrades[OrderType()]++;

      // ### STEP 02: we check, if the MagicNumber that this trade has, is allready in use in our array
      f_checkIfThisMNIsAllreadyAvailableAndReturnArrayPlaceByRef(OrderMagicNumber(), thisMagicNumberIsOnThisPlace);

      // ### STEP 03: if this MagicNumber is new, we enlarge the array, to fill this trade into the new place
      if (thisMagicNumberIsOnThisPlace == -1)
      {
         f_resizeTradeArrayAndReturnNewPlaceByRef(thisMagicNumberIsOnThisPlace);
         if (thisMagicNumberIsOnThisPlace == -1)
         {
            // ... this is critical. something went very wrong...
            Comment("ARRAY RESIZE NOT APPLICABLE. STOP THIS SCRIPT");
            break;
         }
      }

      // ### STEP 04: the proper array place for the first dimension was selected, fill in all data
      f_fillAllTradeDetailsIntoThisArrayPlace(thisMagicNumberIsOnThisPlace);
   }
}

Um keine Ein-Auszahlungen oder sonstige Buchungen zu berücksichtigen, wird ausschließlich nach Trades mit OP_BUY oder OP_SELL Flag gefiltert. Sollten Sie auch andere Trades / Buchungen mit auswerten wollen, müssen Sie die zweite Dimension erweitern! Dann muss arrayDimensionsForDifferentTradeTypes nicht 2 sein, sondern vielleicht 3, oder 4, je nachdem was Sie noch so ausweisen möchten.

Ansonsten ist der Ablauf wie folgt:
Für jeden Trade der erfolgreich selected wurde, wird geschaut, ob die MagicNumber schon im Array gespeichert ist.

void f_checkIfThisMNIsAllreadyAvailableAndReturnArrayPlaceByRef(uint thisMN, int &thisMagicNumberIsOnThisPlace)
{
   thisMagicNumberIsOnThisPlace = -1;
   int arrayPlacesToBeChecked = ArraySize(tradeArray) / newPlacesPerDimension;
   int thisPlace = 0;
   while (thisMagicNumberIsOnThisPlace == -1 && thisPlace < arrayPlacesToBeChecked)
   {
      if ((uint)tradeArray[thisPlace][OP_BUY][_taMagicNumber] == thisMN || (uint)tradeArray[thisPlace][OP_SELL][_taMagicNumber] == thisMN)
      {
         // ... this MagicNumber is allready in use, we don't need to create a new place
         thisMagicNumberIsOnThisPlace = thisPlace;
         // ... as soon as thisMagicNumberIsOnThisPlace becomes != -1, the while loop is ended and we return the place with the MagicNumber
      }

      thisPlace++;
   }
}

WICHTIG DABEI: die Variable thisMagicNumberIsOnThisPlace wird per Referenz zurück übergeben >>> int &thisMagicNumberIsOnThisPlace.
Per Referenz übergeben bedeutet, dass die Variable während der Laufzeit der Funktion verändert werden kann und jede Änderung erhalten bleibt. Die aufrufende Funktion erhält also eine Variable zurück, die unter Umständen verändert wurde. Die Variable thisMagicNumberIsOnThisPlace ist für jedes Ticket das gewählt wurde dauerhaft gültig, muss also die ganze Zeit gespeichert und natürlich ggf. angepasst werden.

Ist die MagicNumber noch nicht vergeben, wird -1 zurück gegeben. Dann erfolgt anschließend die Vergrößerung des tradeArray und ebenfalls wieder die Übergabe des thisMagicNumberIsOnThisPlace per Referenz!

Ganz zum Schluss, egal ob das tradeArray vergrößert werden musste, oder ob es schon einen Eintrag mit dieser MagicNumber gab, erfolgt die Speicherung / Aufaddierung der Werte auf dem dann endgültig vorliegenden Wert thisMagicNumberIsOnThisPlace. Die Eintragung der Werte sieht dann wie folgt aus:

void f_fillAllTradeDetailsIntoThisArrayPlace(int thisMagicNumberIsOnThisPlace)
{
   tradeArray[thisMagicNumberIsOnThisPlace][OrderType()][_taTotalTradeCounter]++;
   tradeArray[thisMagicNumberIsOnThisPlace][OrderType()][_taMagicNumber] = OrderMagicNumber();
   if ( (OrderProfit() + OrderSwap() + OrderCommission()) > 0)
      tradeArray[thisMagicNumberIsOnThisPlace][OrderType()][_taTotalProfit]+= OrderProfit() + OrderSwap() + OrderCommission();
   else
     tradeArray[thisMagicNumberIsOnThisPlace][OrderType()][_taTotalLoss]+= OrderProfit() + OrderSwap() + OrderCommission();

   tradeArray[thisMagicNumberIsOnThisPlace][OrderType()][_taTotalDuration]+= (OrderCloseTime() - OrderOpenTime())/60;
   tradeArray[thisMagicNumberIsOnThisPlace][OrderType()][_taTotalTradeVolume]+= OrderLots();
}

Wenn ein Trade selected wurde, sind alle Werte dieses Trades so lange abrufbar, bis ein neuer Trade gewählt wurde. OrderType() oder OrderMagicNumber() sind also lokale Werte dieses Trades, die nicht übergeben werden müssen. Der Trade ist selected und es kann jederzeit auf diese Werte zugegriffen werden. Die recht kurze Erläuterung zur OrderSelect auf der Seite von MetaQuotes finden Sie hier.

Damit später der Profit-Faktor berechnet werden kann (Summe aller Gewinne / Summe aller Verluste) muss an dieser Stelle eine separate Erfassung von Gewinnen und Verlusten erfolgen. An dieser Stelle können dann bei Bedarf noch weitere Werte gespeichert werden, also zum Beispiel eine Auswertung der Trades je Eröffnungstag, oder Schließtag. Oder eine Erfassung nach Eröffnungs-Stunde / Schließ-Stunde usw.

Last but not least die Ausgabe aller Infos auf dem Screen. Ich habe die Funktion hier ein wenig gekürzt, da ich nur auf 2 Dinge eingehen möchte (im Quellcode findet man natürlich die komplette Funktion …)

for (int thisPlace = 0; thisPlace < ArrayRange(tradeArray, 0); thisPlace++)
   {
// ...
      string pf[2];
      for (int cmd = 0; cmd <= OP_SELL; cmd++)
      {
         pf[cmd] = "99";
         if (tradeArray[thisPlace][cmd][_taTotalProfit] == 0)
            pf[cmd] = "0";
         else
            if (tradeArray[thisPlace][cmd][_taTotalLoss] < 0)
               pf[cmd] = DoubleToString(tradeArray[thisPlace][cmd][_taTotalProfit]/ (-1*tradeArray[thisPlace][cmd][_taTotalLoss]),2);
      }

// ...

   }

Die Ausgabe erfolgt, indem durch alle verfügbaren Array-Plätze gelaufen wird. Für jeden Platz erfolgt dann die Ausgabe der Anzahl der Trades je Long/Short. Des Gesamt PL je Long/Short und auch des Profit-Faktors je Long/Short.
Wenn für eine MagicNumber in einer Richtung keinen Verlust vorliegt, ist der Profit-Faktor theoretisch unendlich groß. Für diesen Fall habe ich den PF auf 99 fixiert. Falls für eine MagicNumber in einer Richtung (Long / Short) nur Verluste vorliegen ist der PF auf 0 fixiert. ACHTUNG! ohne diese Fixierung gibt es an dieser Stelle ein 0-divide error! Alle Gewinne (0) durch alle Verluste (xxx) = 0 divide. Es muss also dieser Fall beachtet werden und vorher gehändelt.

WICHTIG: Das Tool kann nur die MetaTrader-Trade-Historie auswerten, die freigegeben wurde. Gehen Sie in MetaTrader also auf den Reiter Konto-Historie und klicken Sie mit der rechten Maustaste in die gezeigte Historie. Nun können Sie einstellen, welcher Zeitraum der Tradehistorie angezeigt werden soll! Auf genau diese Historie kann das MT4-Tool zugreifen!

So, dass war mal wieder ganz schön viel, ich denke insbesondere das dreidimensionale Array hat es ganz schön in sich. Aber Übung macht ja bekanntlich den Meister, und da mal wieder der ganze Quellcode vorhanden ist, kann jeder Interessierte sich alles in Ruhe durchlesen / durcharbeiten / reproduzieren.
In einem der nächsten Blog-Einträge werde ich das Array vielleicht auf eine 4.Dimension erweitern, und so eine Möglichkeit einbauen, das ganze noch auf verschiedene Währungspaare runter zu brechen! Das geht jetzt nämlich noch nicht, aktuell werden einfach alle Trades aller Underlyings berücksichtigt.

Zum Thema mehrdimensionale Arrays nachfolgend noch zwei Links. 1 Die Beschreibung bei MSDN. 2. Ein ganz gutes Beispiel in C/C++, was der Programmierumgebung von MQL sehr nahe kommt findet sich im Informatik Bereich der Uni Halle.

Zur Übergabe / Bearbeitung einer Variable per Referenz findet sich unter wikibooks für C++ Programmierung eine ganz gute Anleitung. Insbesondere der Bereich Call-by-Reference ist interessant, denn das habe ich in diesem MetaTrader Tool verwendet.

Zum Abschluss der gesamte MQL-Quellcode und auch die sofort verwendbare ex4-Datei hier kostenlos zum Download für alle registrierten Nutzer und natürlich wie immer für jegliche private Nutzung frei verfügbar. Wer noch keinen User hat, einfach einen eigenen USER-Registrieren, valide Mail-Adresse eingeben und schon steht sämtlicher Quellcode aller Blog-Einträge nach der Anmeldung zum Download zur Verfügung.
Wir übernehmen wie immer keine Garantie für die korrekte Funktionsweise dieses bei allen MetaTrader Brokern die es auf der Welt gibt. Bitte auch dieses MetaTrader Tool wie immer bei Ihrem Broker testen und bei Fragen gerne melden.

Download Tool-zur-Performance-Auswertung

Viel Erfolg beim selber ausprobieren
Thomas @ ForexInnovation



4 comments

Skip to comment form

  1. fatlemming

    Freu mich schon.

    1. Thomas Rosenkranz

      gerne. viel Spaß damit und bei Fragen oder Erweiterungswünschen gerne melden

      Thomas

  2. rantampla

    Hallo.
    Sorry, sicher eine Anfänger-Frage.

    Aber wie benutze ich dieses Tool?

    Danke schonmal

    1. Thomas Rosenkranz

      Moin Moin,

      was genau ist denn das Problem? Download funktioniert? Datei in korrekten Ordner platziert? Wo genau klemmt es?

      Thomas

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*