«

Apr 05

Erweiterung des MetaTrader Tools zur Speicherung der Trade-Historie

tradeLoggingInXlsSample

MetaTrader Trade Logging Sample

Wer viel und regelmäßig mit MetaTrader tradet, egal ob automatisch mit einem Expert-Advisor oder rein manuell, der weiß um die Schwäche der fehlenden Auswertemöglichkeiten in MetaTrader. Bereits vor einiger Zeit habe ich ein Tool zur Auswertung der Tradehistorie hier im Blog vorgestellt. Dieses Tool wurde inzwischen sehr oft heruntergeladen und es gab zahlreiche Nachfragen zu möglichen Erweiterungen. Einige dieser Vorschläge habe ich nun implementiert und möchte ich hier vorstellen.

Update am 05.04.2017: Einführung einer Sortierfunktion zum Loggen der Tradehistorie nach einem gewünschten Sortierkriterium.

Damit lassen sich die Trades vor dem finalen Loggen noch nach OpenTime oder CloseTime oder Profit sortieren (beliebig erweiterbar)! ArraySort() funktioniert nur für die erste Dimension eines Arrays. Das Array /arrayForSorting/ ist deshalb ein zweidimensionales Array, das auf dem ersten Platz die Größe speichert nach der später sortiert werden soll und auf dem zweiten Platz jeweils die dazugehörige Ticketnummer. Dieses Array kann also über ArraySort() in MQL sehr komfortabel sortiert werden (aufsteigend / absteigend ebenfalls einstellbar). Nach dem Sortieren werden die Trades in die finale Log-Datei dann in genau dieser Reihenfolge geloggt.
Wer eine weitere Sortierdimension benötigt, der kann einfach die Enum und den Switch-Case Filter erweitern.

Die Enum Dimensionierung sieht aktuell wie folgt aus:

enum ENUM_SORT {_sortByProfit, _sortByOpenTime, _sortByCloseTime};
extern   ENUM_SORT sortByElement = _sortByOpenTime;

Hier lassen sich in den geschweiften Klammern beliebige weitere Dimensionen einführen.

In der Switch-Case Anweisung dann einfach entsprechend die gewünschte Filterdimension erweitern. Ich habe das mal als case xxx hier im Blog symbolisch dargestellt. Im Quellcode der runter geladen werden kann ist das nicht vorhanden.

switch (sortByElement)
   {
      case _sortByProfit: arrayForSorting[placeToBeUsed][_defSort_SortingElement] = (double)OrderProfit();
      case _sortByCloseTime: arrayForSorting[placeToBeUsed][_defSort_SortingElement] = (double)OrderCloseTime();
      case _sortByOpenTime: arrayForSorting[placeToBeUsed][_defSort_SortingElement] = (double)OrderOpenTime();
      case _xxx: arrayForSorting[placeToBeUsed][_defSort_SortingElement] = (double)SORTIER_DIMENSION();
   }

Berechnung des Profit / Loss für Forex-Symbole in Points

In der ersten Version hat das Tool zwar den Profit / Loss in Accountwährung angezeigt, aber es gab keine weiterführende Berechnung des PnL in Points. Die Ausgabe der absoluten Points ist jedoch für die neutrale Auswertung von Trades sehr wichtig, denn der Profit in Accountwährung kann sehr verzerrend sein, insbesondere dann wenn Trades mit sehr unterschiedlichen Lotgrößen gehandelt wurden.

Ich habe dazu den Bereich der Konstanten, die ich für die Adressierung im Array eingeführt habe, um zwei Felder erweitert.

#define  _closePrice          25
#define  _profitLossInPoints  26 

Einerseits hat in der ersten Version der Close-Price gefehlt, andererseits gibt es nun einen neuen Array-Platz für den PnL in Points.

Ich habe anschließend für alle Forex-Symbole eine weitere Funktion gebaut, die eine Umrechnung des PnL in Points vornimmt. Ein EURUSD Trade, der beispielsweise bei 1,20253 eröffnet und bei 1.20307 geschlossen wurde, hätte ohne diese Umrechung einen PnL von 0,00054. Wenn man das auf ganze Points umrechnet dann sind das wesentlich verständlichesre 5,4 Points.

Diese Umrechung muss während des Loggings für jeden Trade separat erfolgen, denn erstens funkioniert die Umrechnung nur für Forex-Symbole (CFDs / Indizes müssen ignoriert werden) und zweitens muss für jedes FX-Symbol individuell geprüft werden, ausgehend von welcher Kommastelle eine Umrechung erfolgen muss.

Die beiden Funktionen zur Ermittlung des absoluten PnL und zur Umrechnung in Points sehen wie folgt aus:

void f_getProfitLossInPoints(int placeToBeUsed)
{
   double thisTradePnlInPoints;
   double thisFxSymbolPoints = 1;
   
   thisTradePnlInPoints = OrderClosePrice() - OrderOpenPrice();
   
   if (convertPipsForForexPairs && MarketInfo(OrderSymbol(), MODE_MARGINCALCMODE) == 0)
      f_getThisSymbolPointsToConvertPnL(thisFxSymbolPoints);
   
   thisTradePnlInPoints = thisTradePnlInPoints / thisFxSymbolPoints;
   
   if (OrderType() == OP_BUY)
      allTradesInHistory[placeToBeUsed][_profitLossInPoints] = (string)(thisTradePnlInPoints);
   else
      allTradesInHistory[placeToBeUsed][_profitLossInPoints] = (string)(- 1 * thisTradePnlInPoints);
}

In dieser Funktion wird erstmal der absolute PnL ermittelt, wobei er für Short Trades vom Vorzeichen her falsch herum ist (es müsste eigentlich OpenPrice mit ClosePrice gerechnet werden). Später wird dieser temporäre Fehler durch die Multiplikation mit -1 wieder korrigiert.

Nachdem der absolute PnL ermittelt wurde, erfolgt die Überprüfung, ob eine Umrechung erfolgen soll (convertPipsForForexPairs ist eine externe Variable, mit der beim Start des Tools auch die Umrechung deaktiviert werden kann) und es erfolgt die Prüfung, ob es sich überhaupt um ein Forex-Symbol handelt.

MarketInfo(OrderSymbol(), MODE_MARGINCALCMODE) gibt an, ob es sich um Forex (0), oder CFD (1) oder Futures (2) oder CFD for indices (3) handelt. Die Umrechnung kann aber nur erfolgen, wenn es sich um ein Forex-Symbol handelt, denn zumindest in der Welt des Forex-Tradings folgen die MetaTrader Broker eine einheitlichen Konvention. Im Bereich der CFDs sind der Kreativität der Broker kaum Grenzen gesetzt. Auf wie viele Kommastellen ein Broker beispielsweise seinen DAX-CFD taxiert und welche Tickvalue hinter einem Dax-Punkt steckt und in welchen Sprüngen der DAX-CFD getaxt wird ist jedem Broker selber überlassen. Eine (weitgehend) einheitliche Systematik wie bei FX Symbolen gibt es bei CFDs nicht.
Im Forex-Bereich werden JPY Währungen bisher auf 2 oder 3 Kommastellen gehandelt und Nicht-JPY Währungen auf 4 oder 5 Kommastellen.
Da sich im FX-Bereich der Point Standard jedoch auf die 2 und 4 Kommastelle durchgesetzt hat, ist es möglich, den absoluten Trade-Gewinn in Points auszurechnen, indem man den die MarketInfo MODE_POINT des Brokers ausliest und ggf. etwas anpasst.

Die nachfolgende Funktion zeigt die Anpassung des POINT-Wertes für die Umrechnung des Trade PnL von einem absoluten Wert in einen standardisierten Point-Wert.

void f_getThisSymbolPointsToConvertPnL(double& thisFxSymbolPoints)
{
   if (MarketInfo(OrderSymbol(), MODE_DIGITS) == 3 || MarketInfo(OrderSymbol(), MODE_DIGITS) == 5)
      thisFxSymbolPoints =  MarketInfo(OrderSymbol(), MODE_POINT) * 10;
   else
      thisFxSymbolPoints = MarketInfo(OrderSymbol(), MODE_POINT);
}

MarketInfo(OrderSymbol(), MODE_POINT) für einen Broker mit 5 Digits beträgt 0,00001 und muss entsprechend auf 0,0001 korrigiert werden.
Aus einem PnL von 0,00054 wird so durch Division dann ein Wert in verständlichen Points (0,00054/0,0001 = 5,4).

Ausgabe eines virtuellen Kontostandes und Berechnung des prozentualen Profit / Loss pro Trades

In der ersten Version dieses Tools habe ich zwar die chronologische Auflistung der Trades vorgenommen, aber es fand kein Kumulation des Profit / Loss bezogen auf einen Kontostand statt. Das habe ich nun behoben. Beim Starten des Tools kann man einen virtuellen Ausgangskontostand eingeben. Beim Loggen der Tradehistorie wird nun ausgehend von diesem Kontostand ein fortlaufender Endkontostand gebildet.

Darüber hinaus rechnet das Tool nun bei jedem neuen Trade die prozentuale Veränderung aus. Dazu wird der absolute PnL in Kontowährung ins Verhältnis zum Kontostand vor dem Trade gesetzt. Eine Veränderung von +5% bedeutet also, dass der Trade nach Abschluss eine Veränderung von 5%, bezogen auf den Kontostand vor Trade-Eröffnung hatte.

Erweiterte Anzeige auf dem Chart

Bisher wurde auf dem Chart nur die Anzahl der Trades angezeigt nachdem das Tool fertig war mit seiner Datenermittlung und dem Schreiben der Daten in die Log-Datei. Das habe ich um eine paar kleinere Statistiken erweitert. Nun wird auch noch nach Long und Short getrennt eine kleine Übersicht von PnL und Tradezahl und Lots vorgenommen.

tradeResultChartOverview

short trade result overview

Da es für die detaillierte Auswertung der Trade-Performance auf dem Chart jedoch bereits ein anderes Tool gibt, möchte ich an dieser Stelle gerne darauf verweisen: MetaTrader Tool zur Darstellung der Performance direkt auf dem Chart.

Darüber hinaus gibt es noch ein Tool zur Auswertung der Performance je Symbol direkt auf dem Chart.

Zum Schluss findet sich wie immer der MetaTrader 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, Mail-Adresse nach Antwort vom Server bestätigen und schon steht sämtlicher Quellcode aller Blog-Einträge zum Download zur Verfügung.

Wir übernehmen wie immer keine Garantie für die korrekte Funktionsweise dieses Tools 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.

MQL-Quellcode zum erweiterten Tool zur Speicherung der MetaTrader Trade-Historie

Viel Erfolg beim selber ausprobieren
Thomas @ ForexInnovation

2 comments

  1. fatlemming

    Hallo Thomas,
    Danke für die Erweiterung und deine Mühe, echt Tolle Arbeit

    Ich bräuchte mal Deinen Rat für mein Problem.
    Dein Tool sortiert nach der _ticketNummer und ich wollte nach _openTime sortieren.
    _openTime
    01.02.2017 10:20 <- 6.
    01.02.2017 07:49 <- 4.
    31.01.2017 16:39 <- 1.
    31.01.2017 18:29 <- 2.
    31.01.2017 20:25 <- 3.
    01.02.2017 08:50 <- 5.
    01.02.2017 12:10 <- 8.
    01.02.2017 11:32 <- 7. Stelle
    Gibt es da eine Lösung?

    Gruß
    fatlemming

    P.s. Du hast geschrieben:
    Zeile 109) #define _cmd 21
    Zeile 196) allTradesInHistory[placeToBeUsed][_cmd] = f_getTradeTypeDescription(OrderType());

    aber im Eifer des Gefechts vergessen

    unter Zeile 352) string thisTradeString = StringConcatenate(
    allTradesInHistory[placeToBeUsed][_cmd],";",
    und
    unter Zeile 399) string header = StringConcatenate("_ticketNumber" , ";",
    "_long/short", ";",

    einzufügen

    1. Thomas Rosenkranz

      Ich habe mal eine Erweiterung vorgenommen, bei der ich 3 Sortierfunktionen eingebaut habe. Kannst Du beliebig erweitern.

      Quellcode habe ich direkt im Beitrag upgedated, kannst Du wie immer einfach direkt runterladen.

      Viele Grüße
      Thomas

      PS: Danke für den Hinweis mit dem fehlenden Long/Short flag. Habe es eingefügt.

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>

*