Diagramme in HTML

Victor | 14 März, 2016

Einleitung

Höchstwahrscheinlich ist MetaTrader 5 ein vollständig autarkes Produkt und braucht keine Erweiterungen. MetaTrader 5 bietet eine Verbindung zum Broker, zeigt Gebote an, ermöglicht die Nutzung einer Vielzahl von Indikatoren für die Marktanalyse und gibt dem Händler natürlich die Möglichkeit, Handelstätigkeiten auszuführen. Da MetaTrader 5 vor allem darauf abzielt, den Handel bequemer zu machen, kann und soll er natürlich kein universell einsetzbares Werkzeug sein, das forscht, mathematische Methoden analysiert, Multimedia-Inhalte erstellt und so weiter.

Außerdem führt die universelle Einsatzfähigkeit eines Softwareprodukts unweigerlich zu abnehmender Effizienz, Zuverlässigkeit und Sicherheit. Andererseits braucht der Benutzer vielleicht in bestimmten Fällen zusätzliche Funktionen, insbesondere, weil Händler unterschiedliche Fachgebiete und Bildungshintergründe haben. Deshalb können Zusatzfunktionen die Attraktivität der Handelsplattform steigern, vorausgesetzt, sie sind einfach umzusetzen und bedeuten keine Einbußen in puncto Zuverlässigkeit und Sicherheit.

In diesem Beitrag betrachten wir eine solche Erweiterung, die die Möglichkeit bietet, Diagramme auf Basis der Daten aus dem Terminal zu erstellen und anzuzeigen.

Jedes Programm muss tun, was es am besten kann. Lassen Sie uns dieses Prinzip befolgen und MetaTrader 5 den Handel mit dem Broker und das Sammeln und Verarbeiten eingehender Informationen überlassen und für die grafische Darstellung dieser Informationen ein anderes Programm benutzen, das für diese Zwecke vorgesehen ist.

Web-Browser

Es ist heutzutage schwierig, einen Computer zu finden, auf dem kein Web-Browser installiert ist. Browser werden seit langer Zeit weiterentwickelt und ständig verbessert. Moderne Browser sind ziemlich zuverlässig, stabil und vor allem kostenlos. Ebenso sind Web-Browser praktisch das grundlegende Tool für den Zugriff auf das Internet, die meisten Benutzer sind mit ihnen vertraut und stoßen bei ihrer Verwendung kaum auf Schwierigkeiten.

Die Fähigkeiten moderner Browser sind so weit gefächert, dass wir uns daran gewöhnt haben, Videos anzusehen, Musik anzuhören, Spiele zu spielen und noch viele andere Sachen in einem Web-Browser zu tun. Also ist ein Web-Browser heute ein hochentwickeltes Tool zum Anzeigen verschiedener Arten von Informationen, die in unterschiedlichen Formaten präsentiert werden können.

Es sollte auch nicht unerwähnt bleiben, dass es derzeit mehrere beliebte Web-Browser gibt: Internet Explorer, Mozilla Firefox, Google Chrome, und Opera. Diese Browser mögen sich in ihrer Softwareumsetzung und ihren Oberflächen stark voneinander unterscheiden. Allerdings sollten sie theoretisch die grundlegenden Standards des Netzwerks für den Informationsaustausch vollständig unterstützen. Dies betrifft hauptsächlich die Standards der Sprache HTML.

In der Praxis haben Browser trotz den Bemühungen der Entwickler immer noch ihre eigenen Besonderheiten bei der Umsetzung bestimmter Protokolle oder Technologien. Wenn wir zu dem Schluss kommen, dass ein bestimmter Browser für uns aufgrund seiner besonderen Merkmale nicht geeignet ist, lässt sich dieses Problem einfach durch die Installation eines oder mehrerer anderer Web-Browser auf unserem Computer beheben. Sogar die begeistertsten Anhänger von Browsern wie Firefox haben gleichzeitig zumindest Internet Explorer auf ihrem System installiert.

Obwohl Web-Browser als Clients entwickelt wurden, die mit einem entfernten Server interagieren, können sie auch zur Anzeige lokaler Informationen auf Ihrem Computer genutzt werden. Ein Beispiel dafür kann die Betrachtung von Webseiten sein, die Sie vorher auf Ihrem Computer gespeichert haben. Der Browser benötigt keinen Internetzugriff, um mit lokalen Seiten arbeiten zu können.

Somit ist ein offline betriebener Web-Browser ein sehr attraktiver Kandidat für die Rolle eines Programms zur Erweiterung der Grafikfähigkeiten des MetaTrader 5 Client Terminals. Für seine Nutzung müssen Sie keine teuren Käufe tätigen und mühseligen und langatmigen Installationen vornehmen oder lernen, mit einem neuen Softwareprodukt umzugehen.

Deshalb betrachten wir im weiteren Verlauf dieses Beitrags die Möglichkeiten der Nutzung von Web-Browsern für die Erstellung von Diagrammen auf Basis der Daten aus MetaTrader 5.

HTML und JavaScript

Nachdem wir entschieden haben, einen Web-Browser als unsere Erweiterung zu nutzen, definieren wir eine Grundregel, an die wir uns ab hier strikt halten werden: Die Darstellung der erstellten HTML-Seiten muss ohne lokalen oder entfernten Webserver erfolgen. Das heißt, wir installieren keine Serversoftware auf unserem Computer und die Darstellung unserer Seiten erfordert keinen Netzwerkzugriff. Die HTML-Seiten, die wir erstellen, sollten nur durch den Web-Browser dargestellt werden und müssen sich auf unserem Computer befinden. Diese Regel vermindert das Risiko potenzieller Sicherheitseinbußen durch den Zugriff auf ein äußeres Netzwerk.

Indem wir für die Darstellung von Informationen ausschließlich die Funktionen von HTML 4 nutzen, können wir Webseiten mit Tabellen, formatiertem Text und Bildern erstellen, doch diese Möglichkeiten können uns nicht vollständig zufriedenstellen, da es unser Ziel ist, vollwertige Diagramme auf Basis der Daten aus MetaTrader 5 aufzubauen.

In den meisten Fällen wird das, was wir sehen, wenn wir uns verschiedene Seiten im Web-Browser ansehen, mithilfe der Erweiterungen von HTML erstellt. Im allgemeinen werden diese Erweiterungen serverseitig ausgeführt und sind deshalb für unsere Zwecke ungeeignet. Technologien, die auf der Browserseite funktionieren und keine Serversoftware benötigen, zum Beispiel Macromedia Flash, JavaScript und Java, könnten für uns interessant sein.

Während wir für die Ausführung der browserseitigen Anwendungen Macromedia Flash und Java mindestens zusätzliche Plugins installieren müssen, werden die in JavaScript geschriebenen Anwenderprogramme direkt vom Browser ausgeführt. Alle gebräuchlichen Web-Browser verfügen über eingebaute JavaScript-Interpreter. Wählen wir JavaScript, um keine zusätzlichen Programme oder Plugins installieren zu müssen.

Somit verwenden wir nachfolgend nur MetaTrader 5 mit MQL5 und einen Web-Browser mit HTML und JavaScript. Es ist keine zusätzliche Software erforderlich. Denken Sie daran, dass eine HTML-Seite nichts weiter ist als eine Textdatei. Deshalb können wir zur Erstellung eines HTML-Dokuments jeden beliebigen Texteditor nutzen. Beispielsweise können wir HTML-Code in MetaEditor 5 erstellen und bearbeiten. Beim Schreiben dieses Beitrags wurde die Bearbeitung des HTML-Codes in Opera@USB v10.63 vorgenommen, in dem Sie Seiteninhalte bearbeiten, die veränderte Seite speichern und eine Voransicht dessen laden können, was letztendlich angezeigt wird.

Jemand, der mit den Sprachen HTML und JavaScript nicht vertraut ist, hat möglicherweise Bedenken angesichts der potenziellen Schwierigkeiten beim Erlernen dieser Sprachen. Um unsere Aufgabe zu erleichtern und vertiefte Studien von HTML und JavaScript zu vermeiden, versuchen wir, vorgefertigte, auf dieser Technologie basierende Lösungen zu nutzen. Da unser Ziel gemäß dem Umfang dieses Beitrags auf die Konstruktion von Diagrammen beschränkt ist, nutzen wir vorgefertigte JavaScript-Bibliotheken, die speziell für diesen Zweck erstellt wurden.

Emprise JavaScript Charts ist eine ziemlich fortschrittliche Grafikbibliothek. Möglicherweise möchte sich der Leser über den angegebenen Link mit ihr vertraut machen, doch die Bibliothek ist nicht ganz kostenlos. Betrachten wir also kostenlose Bibliotheken, zum Beispiel Dygraphs JavaScript Visualization Library und Highcharts charting library. Dygraphs ist durch seine Kompaktheit und Einfachheit attraktiv. Highcharts bietet wiederum mehr Funktionen und sieht universeller aus. Obwohl die Highcharts-Bibliothek etwa 75 KB groß ist und eine zusätzliche jQuery-Bibliothek mit zusätzlichen etwa 70 KB benötigt, wählen wir sie als Bibliothek unserer Wahl.

Auf der Webseite http://www.highcharts.com/ im Abschnitt "Demo Gallery" können Sie sich mit der Highcharts-Bibliothek vertraut machen. Für jedes Beispiel können Sie mit einem Klick auf "View options" den JavaScript-Quellcode ansehen. Detaillierte Dokumentationen zur Bibliothek finden Sie im Bereich "Documentation/Options Reference", in dem Sie auch zahlreiche Beispiele für die Nutzung der verschiedenen Optionen finden. Die Verwendung der Bibliothek mag auf den ersten Blick aufgrund des vielen JavaScript-Codes und der für MQL-Programmierer ungewöhnlichen Syntax ziemlich kompliziert erscheinen. Doch es ist überhaupt nicht so kompliziert. Betrachten Sie das erste Beispiel einer einfachen HTML-Datei, die mithilfe der durch die Bibliothek zur Verfügung gestellten Mittel das Diagramm anzeigen wird.

Erstellen wir als Beispiel eine Textdatei mit dem Namen Test_01.htm im Editor und kopieren das folgende einfache Beispiel für die Nutzung der Bibliothek.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Example</title>
<!-- - -->
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"
             type="text/javascript"></script>
<script src="/js/highcharts.js" type="text/javascript"></script>
<!-- - -->
<script type="text/javascript">
var chart1;
$(document).ready(function(){
  chart1 = new Highcharts.Chart({
    chart: {renderTo: 'container1'},
    series: [{data: [29.9, 71.5, 106.4, 129.2, 144.0, 176.0, 135.6, 148.5, 216.4, 194.1, 95.6, 54.4]}]
  });
});
</script>
<!-- - -->
</head>
<body>
<div id="container1" style="width: 700px; height: 400px "></div>
</body>
</html>

Der Beispielcode ist durch die Kommentare in vier Bereiche unterteilt.

Der erste, obere Teil des Codes beinhaltet die gewohnten Tags der HTML-Seite. Dieser Teil des Codes ist für uns im Moment nicht besonders interessant.

Auf ihn folgt ein weiterer Teil, der zwei <script>-Tags enthält. Im ersten Fall geben wir dem Browser den Befehl zum Herunterladen des Bibliothekscodes jquery.min.js von der Webseite ajax.googleapis.com. Der zweite Fall nimmt an, dass der Katalog /js/ auf der Serverseite die Bibliothek highcharts.js enthält, die der Browser herunterladen muss. Da wir zuvor entschieden haben, dass für die Anzeige unserer Seiten kein Zugriff auf externe Quellen nötig sein darf, muss dieser Teil des Codes geändert werden.

Nach den Änderungen sieht dieser Teil des Codes so aus

<script src="jquery.min.js" type="text/javascript"></script>
<script src="highcharts.js" type="text/javascript"></script>

In diesem Fall geben wir den Befehl, beide Bibliotheken aus dem Katalog herunterzuladen, der unsere HTML-Datei beinhaltet, das heißt, aus dem aktuellen Katalog. Damit die Bibliotheken vom Browser heruntergeladen werden, müssen sie zuerst von ajax.googleapis.com und http://www.highcharts.com heruntergeladen und in denselben Katalog kopiert werden, in dem sich auch unsere HTML-Datei befindet. Sie finden diese beiden Bibliotheken auch in den Anhängen am Ende dieses Beitrags.

Im nächsten Codeabschnitt wird ein Objekt der Klasse Highcharts.Chart erstellt. Der Parameter "renderTo: 'container1'" bedeutet, dass das Diagramm im HTML-Element mit dem Namen "container1" angezeigt wird, und der Parameter "data" definiert die im Diagramm anzuzeigenden Daten. Wie wir in diesem Beispiel sehen können, werden die Daten auf die gleiche Weise definiert wie die Parameter – während der Erstellung eines Objekts der Klasse Highcharts.Chart. Durch einige simple Änderungen verschieben wir die Definition der angezeigten Daten in einen separaten Teil des Codes. In Fällen, in denen wir mehrere Diagramme anzeigen müssen, ermöglicht uns dies die Gruppierung ihrer Daten.

Im letzten Teil unseres Beispiels deklariert das Tag <div> ein HTML-Element mit dem Namen "container1" und es werden die Abmessungen dieses Elements angezeigt. Wie bereits erwähnt, ist das das HTML-Element, das für die Konstruktion des Diagramms verwendet werden wird, dessen Größe durch die im Tag <div> festgelegte Größe des Elements "container1" bestimmt wird.

Unter Berücksichtigung der vorgenommenen Änderungen sieht der Code unseres Beispiels so aus:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Example</title>
<!-- - -->
<script src="jquery.min.js" type="text/javascript"></script>
<script src="highcharts.js" type="text/javascript"></script>
<!-- - -->
<script type="text/javascript">
var dat1 = [29.9, 71.5, 106.4, 129.2, 144.0, 176.0, 135.6, 148.5, 216.4, 194.1, 95.6, 54.4];
</script>
<!-- - -->
<script type="text/javascript">
var chart1;
$(document).ready(function(){
  chart1 = new Highcharts.Chart({
    chart: {renderTo: 'container1'},
    series: [{data: dat1}]
  });
});
</script>
<!-- - -->
</head>
<body>
<div id="container1" style="width: 700px; height: 400px "></div>
</body>
</html>

Dieser Testfall und alle Bibliotheken können aus den Anhängen am Ende dieses Beitrags kopiert werden. Die Beispieldatei Test_01.htm und die Dateien der Bibliotheken befinden sich ebenfalls im Ordner \Test. Deshalb doppelklicken wir einfach auf die HTML-Datei Test_01.htm, um die Ergebnisse unserer Arbeit zu sehen.

Denken Sie daran, dass die Ausführung von JavaScript im Web-Browser aktiviert sein muss, damit diese Testseite normal angezeigt wird. Da die Browser es Ihnen aus Sicherheitsgründen ermöglichen, diese Option zu deaktivieren, kann es sein, dass sie abgewählt ist. Als Ergebnis sollten wir Folgendes sehen:

Test_01.htm

Abbildung 1. Test_01.htm 

Dies ist unser erstes Testdiagramm und trotz der augenscheinlichen Komplexität dieser Technologie dauerte seine Erstellung nicht lange.

Wir sollten einige Besonderheiten der angezeigten Diagramme, die auf diese Weise erstellt wurden, beachten. Öffnen Sie im kopierten Katalog die Datei Test_01.htm. Falls Ihr Web-Browser es Ihnen ermöglicht, in die angezeigten Seiten hineinzuzoomen, werden Sie feststellen, dass sogar bei einer wesentlichen Vergrößerung die Qualität des Diagramms nicht abnimmt.

Das liegt daran, dass dieses Diagramm kein statisches Bild ist wie zum Beispiel PNG- oder JPEG-Dateien und nach dem Hinein- oder Herauszoomen aus dem für seine Zeichnung zugewiesenen Bereich neu gezeichnet wird. Deshalb kann ein solches Bild nicht auf die gleiche Weise auf eine Festplatte gespeichert werden wie sonstige Bilder, die wir gerne speichern. Da das Diagramm durch JavaScript konstruiert wurde, darf nicht unerwähnt bleiben, dass unterschiedliche Browser ihre eigenen Interpreter für diese Sprache haben, die möglicherweise nicht immer auf die gleiche Art ausgeführt werden.

Mit JavaScript erstellte Diagramme können in verschiedenen Browsern unterschiedlich aussehen. Am meisten treten diese Unterschiede im Internet Explorer auf.

Doch wir wollen hoffen, dass die Ersteller von JavaScript-Bibliotheken auf die größtmögliche Kompatibilität ihrer Codes mit den beliebtesten Web-Browsern achten.

MetaTrader 5 und MQL5

Im oben aufgeführten Beispiel wurden die im Diagramm anzuzeigenden Daten manuell während der Erstellung der HTML-Seite festgelegt. Für den Transfer von Daten aus MetaTrader 5 in das erstellte Diagramm haben wir die einfachste mögliche Methode genutzt. Lassen Sie MetaTrader 5 Daten in einer separaten Datei aufzeichnen, aus der sie beim Anzeigen des Diagramms in den Browser geladen werden. Schreiben wir ein Beispiel, das eine HTML-Seite beinhaltet, die das Diagramm anzeigen wird, indem wir Daten aus einer Datei und ein Script in MQL5 laden, das diese Datei erstellen wird.

Als HTML-Datei nutzen wir die zuvor erstellte Datei Test_01.htm, nachdem wir einige kleine Änderungen daran vorgenommen haben. Die veränderte Datei nennen wir example1.htm. Die vorgenommenen Änderungen beschränken sich darauf, dass die Zeilen:

<script type="text/javascript">
var dat1 = [29.9, 71.5, 106.4, 129.2, 144.0, 176.0, 135.6, 148.5, 216.4, 194.1, 95.6, 54.4];
</script>
durch
<script type="text/javascript">
var dat1=[0];
</script>
<script src="exdat.txt" type="text/javascript"></script>

ersetzt werden. Nun muss der Browser beim Herunterladen der HTML-Seite auch die Textdatei exdat.txt laden, in der die im Diagramm anzuzeigenden Werte dem Array dat1 zugewiesen sind. Diese Datei sollte ein JavaScript-Codefragment enthalten. Diese Datei kann in MetaTrader 5 mithilfe des entsprechenden Scripts einfach erstellt werden.

Unten sehen Sie ein Beispiel für ein solches Script.

//+------------------------------------------------------------------+
//|                                                     Example1.mq5 |
//|                        Copyright 2010, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2010, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
  int i,n,fhandle;
  double gr[25];
  string str;
  
  n=ArraySize(gr);
  for(i=0;i<n;i++)
    {
    gr[i]=NormalizeDouble(MathSin(i*3*2*M_PI/n),4);
    }

  str=DoubleToString(gr[0],4);
  for(i=1;i<n;i++)
    {
    str+=","+DoubleToString(gr[i],4);
    }
  
  ResetLastError();
  fhandle=FileOpen("exdat.txt",FILE_WRITE|FILE_TXT|FILE_ANSI);
  if(fhandle<0){Print("File open failed, error ",GetLastError());return;}
  
  FileWriteString(fhandle,"dat1=["+str+"];\n");
  
  FileClose(fhandle);
  }
//+------------------------------------------------------------------+

Zur Speicherung der angezeigten Daten verwendet dieses Script das Array gr[], das aus 25 Elementen besteht. Dieses Array wird als Beispiel mit Werten der Sinusfunktion befüllt, die auf vier Nachkommastellen gerundet werden. Natürlich kann dieses Array mit beliebigen anderen, nützlicheren Daten befüllt werden.

Im weiteren Verlauf werden diese Daten formatiert und zu einem Textstring kombiniert. Um den Umfang der erzeugten Textdatei zu reduzieren, werden die Werte der Elemente des Arrays gr[] mit nur vier Nachkommastellen im String übernommen. Zu diesem Zweck nutzen wir die Funktion DoubleToString().

Nachdem der Textstring str entstanden ist, wird er in der Datei exdat.txt gespeichert. Bei erfolgreicher Ausführung des Scripts wird die Textdatei texdat.txt im Unterordner \MQL5\Files des Client Terminals erstellt. Falls die Datei bereits existiert, wird sie überschrieben.

Die Dateien jquery.min.js, highcharts.js, Example1.mq5, Example1.htm und exdat.txt finden Sie am Ende dieses Beitrags in den Anhängen. Diese fünf Dateien befinden sich im Katalog \Example1. Um die Ergebnisse einfach anzusehen, kopieren Sie dieses Beispiel und öffnen Sie im Katalog \Example1 die Datei Example1.htm. Das Diagramm wird gemäß den Daten aus der Datei exdat.txt konstruiert.

Example1.htm 

Abbildung 2. Example1.htm

Um das Script Example1.mq5 auszuführen, muss es sich natürlich im Ordner \MQL5\Scripts des Client Terminals befinden und kompiliert sein.

Wie bereits erwähnt, wird nach dem Start des Scripts die Datei exdat.txt im Ordner \MQL5\Files erstellt, doch in unserem Beispiel müssen sich die HTML-Datei, die Dateien aus den Bibliotheken und die Datendatei alle in demselben Ordner befinden. Deshalb müssen wir die Dateien jquery.min.js, highcharts.js und Example1.htm in den Ordner \MQL5\Files oder die Datei exdat.txt in den Ordner, in dem sich diese Dateien befinden, kopieren.

In diesem Beispiel befinden sich die HTML-Datei und die Bibliotheken in unterschiedlichen Dateien. In der Konzeptionsphase kann es nützlich sein, dass verschiedene Teile des Projekts sich in verschiedenen Dateien befinden. Dadurch werden beispielsweise zufällige Änderungen im Code der Bibliotheken beim Bearbeiten der HTML-Datei verhindert. Doch nachdem die Bearbeitung der HTML-Datei abgeschlossen ist und keine weiteren Änderungen zu erwarten sind, können die Bibliotheken direkt in den Code der HTML-Datei integriert werden.

Das ist möglich, weil JavaScript-Bibliotheken nichts weiter sind als einfache Textdateien. Wenn wir jquery.min.js oder highcharts.js mit einem Texteditor öffnen, sehen wir nichts Lesbares, weil der Quellcode der Bibliotheken auf maximale Kapazität komprimiert wurde.

Die Komprimierung erfolgt durch die Entfernung von Hilfssymbolen, beispielsweise Zeilenvorschübe oder Reihen von Leerzeichen. Nach einer solchen Komprimierung ist jegliche Formatierung verloren, doch der Text bleibt ein Text, da sich der Dateityp nicht ändert. Deshalb macht es keinen Unterschied, ob sich der Browser über eine externe Datei mit der Erweiterung .js mit dem Code der Bibliothek verbindet oder ob er ihn aus der aktuellen HTML-Datei liest, die wiederum auch eine Textdatei ist.

Um die Dateien zu kombinieren, ersetzen Sie in Example1.htm die Zeilen

<script src="jquery.min.js" type="text/javascript"></script>
<script src="highcharts.js" type="text/javascript"></script>

durch

<script type="text/javascript">

</script>

Als Nächstes öffnen wir die Bibliotheksdatei jquery.min.js mit einem Texteditor wie beispielsweise dem Editor und kopieren mit dem Befehl "Alle auswählen" die Inhalte der Datei. Öffnen Sie anschließend die Datei Example1.htm und fügen Sie den kopierten Text aus der Bibliothek zwischen den Tags <script type=\"text/javascript\"> und </script> ein. Speichern Sie die so erhaltene Datei als Example2.htm. Auf die gleiche Weise kopieren Sie die Inhalte der Bibliothek highcharts.js in diese Datei, indem Sie sie zwischen dem Text der vorher kopierten Bibliothek und dem Tag </script> einfügen.

Durch das Kopieren erhöht sich die Größe der HTML-Datei, allerdings brauchen wir keine separaten Bibliotheksdateien für die korrekte Darstellung. Es reicht die Datendatei exdat.txt im Ordner \Example2, der die Dateien Example2.htm und exdat.txt beinhaltet, die sich am Ende dieses Beitrags im Abschnitt Anhänge befinden.

Bericht der Handelshistorie in grafischer Form

Für eine umfassendere Demonstration der vorgestellten Methode zur Anzeige grafischer Informationen erstellen wir einen Bericht, der die Historie des Handelskontos in einem festgelegten Zeitraum anzeigt. Als Prototyp dient der HTML-basierte Bericht, der in MetaTrader 5 erstellt wird, wenn Sie im Kontextmenü der Registerkarte "History" (Historie) die Option "Report" (Bericht) auswählen. Dieser Bericht enthält eine große Menge verschiedener Merkmale, die in einer Tabelle zusammengefasst werden. Unter der Annahme, dass diese Merkmale deutlicher zu erkennen sind, wenn sie in Diagrammform dargestellt werden, zeigen wir sie mithilfe der grafischen Bibliothek highcharts.js an.

In den oben aufgeführten Beispielen nutzten wir für die Konstruktion des Diagramms die Standard-Anzeigeparameter, die in dieser Version der Bibliothek higcharts.js festgelegt werden.

In der Praxis ist diese Option nicht erfolgsversprechend, weil wir die Ansicht des Diagramms in jedem Fall an die jeweiligen individuellen Anforderungen anpassen müssen. Für diesen Zweck bietet die Bibliothek highcharts.js zahlreiche Möglichkeiten und viele Optionen, die auf das Diagramm angewendet werden können. Wie bereits erwähnt, finden Sie die Liste der Optionen zusammen mit detaillierten Beschreibungen und Beispielen unter http://www.highcharts.com.

Wir halten uns nicht mit der Beschreibung der Optionen der Grafikbibliothek und den Besonderheiten ihrer Verwendung auf, da dieser Beitrag nur dem Zweck dient, die Möglichkeit vorzuführen, einen Web-Browser für die Anzeige von Informationen aus MetaTrader 5 zu nutzen. Insbesondere kann je nach den spezifischen Anforderungen an die Erstellung einer Webseite eine andere JavaScript-Bibliothek verwendet werden. Der Leser kann selbst die am besten geeignete Bibliothek wählen und sie genauso so tief studieren, wie es für ihren praktischen Gebrauch nötig ist.

Für die Anzeige der Handelshistorie haben wir die Datei ProfitReport.htm erstellt. Sie finden sie in den Anhängen.  Der Ordner \Report beinhaltet die Datei data.txt mit den anzuzeigenden Daten. Die Datei data.txt befindet sich als Beispiel im Ordner.

Wenn wir den Ordner \Report kopieren und die Datei ProfitReport.htm öffnen, sehen wir die Handelseigenschaften des für dieses Beispiel erstellten Testkontos in grafischer Form.

ProfitReport.htm

Abbildung 3. ProfitReport.htm

Während der Erstellung von ProfitReport.htm haben wir zuerst ein grobes Layout für die Seite erstellt und ungefähr bestimmt, welche Art von Informationen sich wo befinden soll.

Anschließend haben wir die Diagramme mit ihren Standardoptionen auf der Seite platziert.

Nach der Erstellung dieser Vorlage wählten wir die geeignetsten Optionen für jedes einzelne Diagramm. Nach der Bearbeitung kopierten wir die Texte der Bibliotheken einfach auf die Seite. Wie bereits erwähnt, muss sich die Seite im gleichen Ordner befinden wie die Datei data.txt, die die anzuzeigenden Daten enthält, um korrekt dargestellt zu werden.

Die Datei data.txt wurde mit dem Script ProfitReport.mq5 in MetaTrader 5 erstellt. Bei erfolgreicher Ausführung dieses Scripts wird die Datei data.txt im Ordner \MQL5\Files erstellt, der die Handelsmerkmale des aktuell aktiven Kontos enthält.

Wir dürfen nicht vergessen, dass das Script in den Ordner \MQL5\Scripts gelegt und kompiliert werden muss.

//-----------------------------------------------------------------------------------
//                                                                   ProfitReport.mq5
//                                          Copyright 2011, MetaQuotes Software Corp.
//                                                                https://www.mql5.com
//-----------------------------------------------------------------------------------
#property copyright   "Copyright 2011, MetaQuotes Software Corp."
#property link        "https://www.mql5.com"
#property version     "1.00"
#property script_show_inputs

#include <Arrays\ArrayLong.mqh>
#include <Arrays\ArrayDouble.mqh>
#include <Arrays\ArrayString.mqh>
#include <Arrays\ArrayInt.mqh>

//--- input parameters
input int nD=30;               // Number of days
//--- global
double   balabce_cur=0;        // balance
double   initbalance_cur=0;    // Initial balance (not including deposits to the account)
int      days_num;             // number of days in the report (including the current day)
datetime tfrom_tim;            // Date from
datetime tend_tim;             // Date to
double   netprofit_cur=0;      // Total Net Profit
double   grossprofit_cur=0;    // Gross Profit
double   grossloss_cur=0;      // Gross Loss
int      totaltrades_num=0;    // Total Trades
int      longtrades_num=0;     // Number of Long Trades
double   longtrades_perc=0;    // % of Long Trades
int      shorttrades_num=0;    // Number of Short Trades
double   shorttrades_perc=0;   // % of Short Trades
int      proftrad_num=0;       // Number of All Profit Trades
double   proftrad_perc=0;      // % of All Profit Trades
int      losstrad_num=0;       // Number of All Loss Trades
double   losstrad_perc=0;      // % of All Loss Trades
int      shortprof_num=0;      // Number of Short Profit Trades
double   shortprof_perc=0;     // % of Short Profit Trades
double   shortloss_perc=0;     // % of Short Loss Trades
int      longprof_num=0;       // Number of Long Profit Trades
double   longprof_perc=0;      // % of Long Profit Trades
double   longloss_perc=0;      // % of Long Loss Trades
int      maxconswins_num=0;    // Number of Maximum consecutive wins
double   maxconswins_cur=0;    // Maximum consecutive wins ($)
int      maxconsloss_num=0;    // Number of Maximum consecutive losses
double   maxconsloss_cur=0;    // Maximum consecutive losses ($)
int      aveconswins_num=0;    // Number of Average consecutive wins
double   aveconswins_cur=0;    // Average consecutive wins ($)
int      aveconsloss_num=0;    // Number of Average consecutive losses
double   aveconsloss_cur=0;    // Average consecutive losses ($)
double   largproftrad_cur=0;   // Largest profit trade
double   averproftrad_cur=0;   // Average profit trade
double   larglosstrad_cur=0;   // Largest loss trade
double   averlosstrad_cur=0;   // Average loss trade
double   profitfactor=0;       // Profit Factor
double   expectpayoff=0;       // Expected Payoff
double   recovfactor=0;        // Recovery Factor
double   sharperatio=0;        // Sharpe Ratio
double   ddownabs_cur=0;       // Balance Drawdown Absolute
double   ddownmax_cur=0;       // Balance Drawdown Maximal
double   ddownmax_perc=0;      // % of Balance Drawdown Maximal
int      symbols_num=0;        // Numbre of Symbols
  
string       Band="";
double       Probab[33],Normal[33];
CArrayLong   TimTrad;
CArrayDouble ValTrad;
CArrayString SymNam;
CArrayInt    nSymb;

//-----------------------------------------------------------------------------------
// Script program start function
//-----------------------------------------------------------------------------------
void OnStart()
  {
  int         i,n,m,k,nwins=0,nloss=0,naverw=0,naverl=0,nw=0,nl=0;
  double      bal,sum,val,p,stdev,vwins=0,vloss=0,averwin=0,averlos=0,pmax=0;
  MqlDateTime dt;
  datetime    ttmp,it;
  string      symb,br;
  ulong       ticket;
  long        dtype,entry;
  
  if(!TerminalInfoInteger(TERMINAL_CONNECTED)){printf("Terminal not connected.");return;}
  days_num=nD;
  if(days_num<1)days_num=1;             // number of days in the report (including the current day)
  tend_tim=TimeCurrent();                                                // date to
  tfrom_tim=tend_tim-(days_num-1)*86400;
  TimeToStruct(tfrom_tim,dt);
  dt.sec=0; dt.min=0; dt.hour=0;
  tfrom_tim=StructToTime(dt);                                            // date from
//---------------------------------------- Bands
  ttmp=tfrom_tim;
  br="";
  if(dt.day_of_week==6||dt.day_of_week==0)
    {
    Band+=(string)(ulong)(ttmp*1000)+",";
    br=",";ttmp+=86400;
    }
  for(it=ttmp;it<tend_tim;it+=86400)
    {
    TimeToStruct(it,dt);
    if(dt.day_of_week==6){Band+=br+(string)(ulong)(it*1000)+","; br=",";}
    if(dt.day_of_week==1&&br==",") Band+=(string)(ulong)(it*1000);
    }
  if(dt.day_of_week==6||dt.day_of_week==0) Band+=(string)(ulong)(tend_tim*1000);

//----------------------------------------
  balabce_cur=AccountInfoDouble(ACCOUNT_BALANCE);                          // Balance

  if(!HistorySelect(tfrom_tim,tend_tim)){Print("HistorySelect failed");return;}
  n=HistoryDealsTotal();                                           // Number of Deals
  for(i=0;i<n;i++)
    {
    ticket=HistoryDealGetTicket(i);
    entry=HistoryDealGetInteger(ticket,DEAL_ENTRY);
    if(ticket>=0&&(entry==DEAL_ENTRY_OUT||entry==DEAL_ENTRY_INOUT))
      {
      dtype=HistoryDealGetInteger(ticket,DEAL_TYPE);
      if(dtype==DEAL_TYPE_BUY||dtype==DEAL_TYPE_SELL)
        {
        totaltrades_num++;                                          // Total Trades
        val=HistoryDealGetDouble(ticket,DEAL_PROFIT);
        val+=HistoryDealGetDouble(ticket,DEAL_COMMISSION);
        val+=HistoryDealGetDouble(ticket,DEAL_SWAP);
        netprofit_cur+=val;                                         // Total Net Profit
        if(-netprofit_cur>ddownabs_cur)ddownabs_cur=-netprofit_cur; // Balance Drawdown Absolute
        if(netprofit_cur>pmax)pmax=netprofit_cur;
        p=pmax-netprofit_cur;
        if(p>ddownmax_cur)
          {
          ddownmax_cur=p;                                 // Balance Drawdown Maximal
          ddownmax_perc=pmax;
          }
        if(val>=0)              //win
          {
          grossprofit_cur+=val;                            // Gross Profit 
          proftrad_num++;                                  // Number of Profit Trades
          if(val>largproftrad_cur)largproftrad_cur=val;    // Largest profit trade
          nwins++;vwins+=val;
          if(nwins>=maxconswins_num)
            {
            maxconswins_num=nwins;
            if(vwins>maxconswins_cur)maxconswins_cur=vwins;
            }
          if(vloss>0){averlos+=vloss; nl+=nloss; naverl++;}
          nloss=0;vloss=0;
          }
        else                    //loss
          {
          grossloss_cur-=val;                                   // Gross Loss
          if(-val>larglosstrad_cur)larglosstrad_cur=-val;       // Largest loss trade
          nloss++;vloss-=val;
          if(nloss>=maxconsloss_num)
            {
            maxconsloss_num=nloss;
            if(vloss>maxconsloss_cur)maxconsloss_cur=vloss;
            }
          if(vwins>0){averwin+=vwins; nw+=nwins; naverw++;}
          nwins=0;vwins=0;
          }
        if(dtype==DEAL_TYPE_SELL)
          {
          longtrades_num++;                          // Number of Long Trades
          if(val>=0)longprof_num++;                  // Number of Long Profit Trades
          }
        else if(val>=0)shortprof_num++;               // Number of Short Profit Trades

        symb=HistoryDealGetString(ticket,DEAL_SYMBOL);   // Symbols
        k=1;
        for(m=0;m<SymNam.Total();m++)
          {
          if(SymNam.At(m)==symb)
            {
            k=0;
            nSymb.Update(m,nSymb.At(m)+1);
            }
          }
        if(k==1)
          {
          SymNam.Add(symb);
          nSymb.Add(1);
          }
        
        ValTrad.Add(val);
        TimTrad.Add(HistoryDealGetInteger(ticket,DEAL_TIME));
        }
      }
    }
  if(vloss>0){averlos+=vloss; nl+=nloss; naverl++;}
  if(vwins>0){averwin+=vwins; nw+=nwins; naverw++;}
  initbalance_cur=balabce_cur-netprofit_cur;
  if(totaltrades_num>0)
    {
    longtrades_perc=NormalizeDouble((double)longtrades_num/totaltrades_num*100,1);     // % of Long Trades
    shorttrades_num=totaltrades_num-longtrades_num;                                 // Number of Short Trades
    shorttrades_perc=100-longtrades_perc;                                           // % of Short Trades
    proftrad_perc=NormalizeDouble((double)proftrad_num/totaltrades_num*100,1);         // % of Profit Trades
    losstrad_num=totaltrades_num-proftrad_num;                                      // Number of Loss Trades
    losstrad_perc=100-proftrad_perc;                                                // % of All Loss Trades
    if(shorttrades_num>0)
      {
      shortprof_perc=NormalizeDouble((double)shortprof_num/shorttrades_num*100,1);     // % of Short Profit Trades
      shortloss_perc=100-shortprof_perc;                                            // % of Short Loss Trades
      }
    if(longtrades_num>0)
      {
      longprof_perc=NormalizeDouble((double)longprof_num/longtrades_num*100,1);        // % of Long Profit Trades
      longloss_perc=100-longprof_perc;                                              // % of Long Loss Trades
      }
    if(grossloss_cur>0)profitfactor=NormalizeDouble(grossprofit_cur/grossloss_cur,2);  // Profit Factor
    if(proftrad_num>0)averproftrad_cur=NormalizeDouble(grossprofit_cur/proftrad_num,2);// Average profit trade
    if(losstrad_num>0)averlosstrad_cur=NormalizeDouble(grossloss_cur/losstrad_num,2);  // Average loss trade
    if(naverw>0)
      {
      aveconswins_num=(int)NormalizeDouble((double)nw/naverw,0);
      aveconswins_cur=NormalizeDouble(averwin/naverw,2);
      }
    if(naverl>0)
      {
      aveconsloss_num=(int)NormalizeDouble((double)nl/naverl,0);
      aveconsloss_cur=NormalizeDouble(averlos/naverl,2);
      }
    p=initbalance_cur+ddownmax_perc;
    if(p!=0)
      {
      ddownmax_perc=NormalizeDouble(ddownmax_cur/p*100,1); // % of Balance Drawdown Maximal
      }
    if(ddownmax_cur>0)recovfactor=NormalizeDouble(netprofit_cur/ddownmax_cur,2); // Recovery Factor

    expectpayoff=netprofit_cur/totaltrades_num;                    // Expected Payoff
    
    sum=0;
    val=balabce_cur;
    for(m=ValTrad.Total()-1;m>=0;m--)
      {
      bal=val-ValTrad.At(m);
      p=val/bal;
      sum+=p;
      val=bal;
      }
    sum=sum/ValTrad.Total();
    stdev=0;
    val=balabce_cur;
    for(m=ValTrad.Total()-1;m>=0;m--)
      {
      bal=val-ValTrad.At(m);
      p=val/bal-sum;
      stdev+=p*p;
      val=bal;
      }
    stdev=MathSqrt(stdev/ValTrad.Total());
    if(stdev>0)sharperatio=NormalizeDouble((sum-1)/stdev,2);    // Sharpe Ratio

    stdev=0;
    for(m=0;m<ValTrad.Total();m++)
      {
      p=ValTrad.At(m)-expectpayoff;
      stdev+=p*p;
      }
    stdev=MathSqrt(stdev/ValTrad.Total());                      // Standard deviation
    if(stdev>0)
      {
      ArrayInitialize(Probab,0.0);
      for(m=0;m<ValTrad.Total();m++)                           // Histogram
        {
        i=16+(int)NormalizeDouble((ValTrad.At(m)-expectpayoff)/stdev,0);
        if(i>=0 && i<ArraySize(Probab))Probab[i]++;
        }
      for(m=0;m<ArraySize(Probab);m++) Probab[m]=NormalizeDouble(Probab[m]/totaltrades_num,5);
      }
    expectpayoff=NormalizeDouble(expectpayoff,2);                  // Expected Payoff  
    k=0;
    symbols_num=SymNam.Total();                                  // Symbols
    for(m=0;m<(6-symbols_num);m++)
      {
      if(k==0)
        {
        k=1;
        SymNam.Insert("",0);
        nSymb.Insert(0,0);
        }
      else
        {
        k=1;
        SymNam.Add("");
        nSymb.Add(0);
        }
      }
    }
  p=1.0/MathSqrt(2*M_PI)/4.0;
  for(m=0;m<ArraySize(Normal);m++)                             // Normal distribution
    {
    val=(double)m/4.0-4;
    Normal[m]=NormalizeDouble(p*MathExp(-val*val/2),5);
    }

  filesave();
  }
//-----------------------------------------------------------------------------------
// Save file
//-----------------------------------------------------------------------------------
void filesave()
  {
  int n,fhandle;
  string loginame,str="",br="";
  double sum;
  
  ResetLastError();
  fhandle=FileOpen("data.txt",FILE_WRITE|FILE_TXT|FILE_ANSI);
  if(fhandle<0){Print("File open failed, error ",GetLastError());return;}
  
  loginame="\""+(string)AccountInfoInteger(ACCOUNT_LOGIN)+", "+
                        TerminalInfoString(TERMINAL_COMPANY)+"\"";
  str+="var PName="+loginame+";\n";
  str+="var Currency=\""+AccountInfoString(ACCOUNT_CURRENCY)+"\";\n";
  str+="var Balance="+(string)balabce_cur+";\n";
  str+="var IniBalance="+(string)initbalance_cur+";\n";
  str+="var nDays="+(string)days_num+";\n";
  str+="var T1="+(string)(ulong)(tfrom_tim*1000)+";\n";
  str+="var T2="+(string)(ulong)(tend_tim*1000)+";\n";
  str+="var NetProf="+DoubleToString(netprofit_cur,2)+";\n";
  str+="var GrossProf="+DoubleToString(grossprofit_cur,2)+";\n";
  str+="var GrossLoss="+DoubleToString(grossloss_cur,2)+";\n";
  str+="var TotalTrad="+(string)totaltrades_num+";\n";
  str+="var NProfTrad="+(string)proftrad_num+";\n";
  str+="var ProfTrad="+DoubleToString(proftrad_perc,1)+";\n";
  str+="var NLossTrad="+(string)losstrad_num+";\n";
  str+="var LossTrad="+DoubleToString(losstrad_perc,1)+";\n";
  str+="var NLongTrad="+(string)longtrades_num+";\n";
  str+="var LongTrad="+DoubleToString(longtrades_perc,1)+";\n";
  str+="var NShortTrad="+(string)shorttrades_num+";\n";
  str+="var ShortTrad="+DoubleToString(shorttrades_perc,1)+";\n";
  str+="var ProfLong ="+DoubleToString(longprof_perc,1)+";\n";
  str+="var LossLong ="+DoubleToString(longloss_perc,1)+";\n";
  FileWriteString(fhandle,str); str="";
  str+="var ProfShort="+DoubleToString(shortprof_perc,1)+";\n";
  str+="var LossShort="+DoubleToString(shortloss_perc,1)+";\n";
  str+="var ProfFact="+DoubleToString(profitfactor,2)+";\n";
  str+="var LargProfTrad="+DoubleToString(largproftrad_cur,2)+";\n";
  str+="var AverProfTrad="+DoubleToString(averproftrad_cur,2)+";\n";
  str+="var LargLosTrad="+DoubleToString(larglosstrad_cur,2)+";\n";
  str+="var AverLosTrad="+DoubleToString(averlosstrad_cur,2)+";\n";
  str+="var NMaxConsWin="+(string)maxconswins_num+";\n";
  str+="var MaxConsWin="+DoubleToString(maxconswins_cur,2)+";\n";
  str+="var NMaxConsLos="+(string)maxconsloss_num+";\n";
  str+="var MaxConsLos="+DoubleToString(maxconsloss_cur,2)+";\n";
  str+="var NAveConsWin="+(string)aveconswins_num+";\n";
  str+="var AveConsWin="+DoubleToString(aveconswins_cur,2)+";\n";
  str+="var NAveConsLos="+(string)aveconsloss_num+";\n";
  str+="var AveConsLos="+DoubleToString(aveconsloss_cur,2)+";\n";
  str+="var ExpPayoff="+DoubleToString(expectpayoff,2)+";\n";
  str+="var AbsDD="+DoubleToString(ddownabs_cur,2)+";\n";
  str+="var MaxDD="+DoubleToString(ddownmax_cur,2)+";\n";
  str+="var RelDD="+DoubleToString(ddownmax_perc,1)+";\n";
  str+="var RecFact="+DoubleToString(recovfactor,2)+";\n";
  str+="var Sharpe="+DoubleToString(sharperatio,2)+";\n";
  str+="var nSymbols="+(string)symbols_num+";\n";
  FileWriteString(fhandle,str);

  str="";br="";
  for(n=0;n<ArraySize(Normal);n++)
    {
    str+=br+"["+DoubleToString(((double)n-16)/4.0,2)+","+DoubleToString(Normal[n],5)+"]";
    br=",";
    }
  FileWriteString(fhandle,"var Normal=["+str+"];\n");

  str="";
  str="[-4.25,0]";
  for(n=0;n<ArraySize(Probab);n++)
    {
    if(Probab[n]>0)
      {
      str+=",["+DoubleToString(((double)n-16)/4.0,2)+","+DoubleToString(Probab[n],5)+"]";
      }
    }
  str+=",[4.25,0]";
  FileWriteString(fhandle,"var Probab=["+str+"];\n");

  str=""; sum=0;
  if(ValTrad.Total()>0)
    {
    sum+=ValTrad.At(0);
    str+="["+(string)(ulong)(TimTrad.At(0)*1000)+","+DoubleToString(sum,2)+"]";
    for(n=1;n<ValTrad.Total();n++)
      {
      sum+=ValTrad.At(n);
      str+=",["+(string)(ulong)(TimTrad.At(n)*1000)+","+DoubleToString(sum,2)+"]";
      }
    }
  FileWriteString(fhandle,"var Prof=["+str+"];\n");
  FileWriteString(fhandle,"var Band=["+Band+"];\n");

  str="";br="";
  for(n=0;n<SymNam.Total();n++)
    {
    str+=br+"{name:\'"+SymNam.At(n)+"\',data:["+(string)nSymb.At(n)+"]}";
    br=",";
    }
  FileWriteString(fhandle,"var Sym=["+str+"];\n");

  FileClose(fhandle);
  }

Wie wir sehen können, ist der Scriptcode ziemlich sperrig, aber nicht etwa aufgrund der Komplexität der Aufgabe, sondern wegen der hohen Menge an Handelsmerkmalen, deren Wert bestimmt werden muss. Für die Speicherung dieser Werte werden am Anfang des Scripts die globalen Variablen mit entsprechenden Kommentaren deklariert.

Die Funktion OnStart() prüft, ob das Terminal mit dem Handelsserver verbunden ist. Falls nicht, beendet das Script seine Arbeit. Ohne Verbindung zum Server können wir kein aktives Konto definieren und Informationen dazu abrufen.

Der nächste Schritt ist die Bestimmung des Datums, ab dem die Handelsdaten für das aktuelle aktive Konto im Bericht enthalten sein werden. Als Enddatum nutzen wir den Wert des aktuellen Datums und der aktuellen Zeit zum Zeitpunkt der Ausführung des Scripts. Die Anzahl der im Bericht eingeschlossenen Tage kann beim Laden des Scripts durch eine Anpassung des Eingabeparameters "Number of days", dessen Standardwert 30 Tagen entspricht, festgelegt werden. Sobald wir die Anfangs- und Endzeit des Berichts in der String-Variable Band definiert haben, wird ein Paar von Zeitwerten geformt, das dem Anfang und Ende des Wochenendes entspricht. Diese Information wird genutzt, damit die Zeitintervalle auf dem Bilanzdiagramm, die Samstag und Sonntag entsprechen, gelb markiert werden können.

Als Nächstes wird mithilfe der Funktion HistorySelect() die Historie der Abschlüsse und Order für einen bestimmten Zeitraum verfügbar. Mit dem Aufruf der Funktion HistoryDealsTotal() bestimmen wir die Menge der Abschlüsse in der Historie. Danach wird basierend auf der Anzahl der Abschlüsse ein Zyklus eingerichtet, der Statistiken sammelt, die für die Berechnung der Handelsmerkmale benötigt werden. Am Ende des Zyklus werden deren Werte bestimmt.

Bei der Erstellung des Scripts war es unsere Aufgabe, die Bedeutung der Handelsmerkmale in Übereinstimmung mit dem in MetaTrader 5 erzeugten Bericht beizubehalten. Es wird angenommen, dass die durch das Script berechneten Merkmale der Beschreibung entsprechen müssen, die in der Hilfsdatei des Terminals zu finden ist. 

Informationen zum Zugriff auf die Kontohistorie und die Berechnungen der Handelsmerkmale finden Sie in den folgenden Beiträgen:

Die Mehrheit der Merkmale lässt sich ziemlich einfach berechnen, deshalb gehen wir in diesem Beitrag nicht auf die mit der Berechnung der Merkmale in Verbindung stehenden Verfahren ein und betrachten nur die Unterschiede vom Standardbericht und dessen Ergänzungen.

In dem vom Terminal erzeugten Bericht wird das Bilanzdiagramm durch die sequentielle Anzeige der Werte bei jeder seiner Änderungen konstruiert und die X-Skala gibt die Anzahl dieser Änderungen wieder. In unserem Fall nutzen wir für die Konstruktion des Diagramms eine Zeitskala.

Deshalb unterscheidet sich das Gewinndiagramm stark von dem vom Terminal erzeugten Diagramm. Wir haben uns für diese Option für die Diagrammkonstruktion entschieden, um die Zeit der Schließungen von Positionen auf einer Echtzeitskala abzubilden. Deshalb können wir sehen, wann sich die Handelsaktivität während des Berichtszeitraums hob oder senkte.

Bei der Konstruktion eines Diagramms muss beachtet werden, dass MQL5 mit einem Datumswert arbeitet, der als Menge der seit dem 1. Januar 1970 vergangenen Sekunden dargestellt wird, während die Grafikbibliothek diesen Wert als Menge der Millisekunden seit dem 1. Januar 1970 benötigt. Deshalb müssen die erhaltenen Datumswerte im Script mit tausend multipliziert werden, um korrekt angezeigt werden zu können.

Zur Speicherung des Werts des Gewinns und der Schließungszeit des Abschlusses nutzt das Script die Klassen CArrayDouble und CArrayLong aus der Standardbibliothek. Jedes Mal, wenn ein Abschluss als Ergebnis in der Schleife ermittelt wird, werden Informationen darüber mithilfe der Methode Add() im Element platziert, das am Ende des Arrays eingefügt wird. Dies hebt die Notwendigkeit auf, die benötigte Anzahl von Elementen vorab bestimmen zu müssen. Die Größe des Arrays steigt einfach mit der Anzahl der in der Abschlusshistorie gefundenen Abschlüsse.

Jeder Abschluss wird darauf geprüft, auf welchem Symbol er getätigt wurde. Dabei bleiben der Name des Symbols und die Anzahl der darauf getätigten Abschlüsse erhalten. Wie beim Gewinndiagramm sammeln sich diese Daten beim Betrachten der Historie an, indem sie in einem Element aufgezeichnet werden, das am Ende des Arrays eingefügt wird. Zur Speicherung des Namen des Symbols und der Anzahl der Abschlüsse nutzen wir die Klassen CArrayString und CArrayInt der Standardbibliothek.

Die einzelne Säule im Diagramm wäre in dem Fall, dass die Abschlüsse auf einem Symbol getätigt wurden, zu breit. Um das zu vermeiden, enthält das Daten-Array immer mindestens 7 Elemente. Ungenutzte Elemente werden nicht im Diagramm angezeigt, da sie den Wert Null haben, und vermeiden somit, dass die Säule zu breit wird. Um sicherzustellen, dass bei einer geringen Anzahl an Symbolen die Säulen sich etwa in der Mitte der X-Achse befinden, werden die unwesentlichen Elemente des Arrays sequentiell am Anfang oder am Ende des Arrays eingefügt.

Der nächste Unterschied zum Standardbericht ist der Versuch, das Diagramm der Wahrscheinlichkeitsverteilung für die Abfolge der Gewinnwerte pro Abschluss zu konstruieren.

Wahrscheinlichkeitsdichte

Abbildung 4. Wahrscheinlichkeitsdichte

Dieses Diagramm wird meistens als Histogramm dargestellt. In unserem Fall wird das Wahrscheinlichkeitsdiagramm durch die Konstruktion einer Spline-Kurve auf Basis der bestehenden Säulenwerte dieses Histogramms erstellt. Die berechneten Werte der Wahrscheinlichkeitsdichte werden links und rechts, außerhalb des Diagramms, durch Null-Werte ergänzt. Das ist notwendig, damit das durch die Spline-Kurve konstruierte Diagramm nicht beim letzten bekannten Wert unterbrochen wird und sich über das Diagramm hinaus gegen Null fortsetzt.

Zum Vergleich wird im Diagramm der Wahrscheinlichkeitsdichte Grau genutzt, um das Diagramm der Normalverteilung zu kennzeichnen, das dahingehend normalisiert wurde, dass die Summe seiner Werte gleich eins ist, genauso wie das Diagramm, das auf Basis der Werte des Histogramms konstruiert wurde. Im bereitgestellten Musterbericht reicht die Anzahl der Abschlüsse nicht aus, um eine mehr oder weniger zuverlässige Schätzung der Wahrscheinlichkeitsverteilung der Werte des Gewinns der Abschlüsse zuzulassen. Wir können annehmen, dass das Diagramm authentischer aussieht, wenn die Historie eine große Menge an Abschlüssen enthält.

Sobald alle Handelsmerkmale berechnet sind, wird am Ende des Scripts die Funktion filesave() aufgerufen. Diese Funktion öffnet die Datei data.txt, in der die Namen und Werte der Variablen im Textformat aufgezeichnet werden. Die Werte dieser Variablen entsprechen den berechneten Parametern und ihre Namen entsprechen den Namen, die während der Übertragung der Parameter an die Funktionen der Grafikbibliothek in der HTML-Datei benutzt werden.

Um die Menge der Festplattenzugriffe beim Schreiben der Datei zu reduzieren, werden kurze Zeilen zu einer längeren Zeile verschmolzen, bevor sie in die Datei geschrieben werden. Wie es in MetaTrader 5 gebräuchlich ist, wird die Datei data.txt im Ordner MQL5\Files erstellt. Falls diese Datei bereits existiert, wird sie überschrieben. Zur Arbeitserleichterung können Sie die Datei ProfitReport.htm in diesen Ordner kopieren und sie von dort ausführen.

Beim Speichern eines Berichts im MetaTrader-5-Terminal im HTML-Format wird dieser Bericht automatisch durch den festgelegten Standardbrowser geöffnet. In dem in diesem Beitrag vorgestellten Beispiel war diese Möglichkeit nicht implementiert.

Für einen Autostart müssen Sie die folgenden Zeilen am Anfang des Scripts ProfitReport.mq5 einfügen:

#import "shell32.dll"
int ShellExecuteW(int hwnd,string lpOperation,string lpFile,string lpParameters,
                  string lpDirectory,int nShowCmd);
#import

Am Ende, nach dem Aufruf der Funktion filesave(), fügen Sie

string path=TerminalInfoString(TERMINAL_DATA_PATH)+"\\MQL5\\Files\\ProfitReport.htm";
ShellExecuteW(NULL,"open",path,NULL,NULL,1);

ein. Falls die Datei ProfitReport.htm unter dem in der Variable angegebenen Pfad existiert, wird sie durch einen Browser geöffnet, wenn die Funktion ShellExecuteW() aufgerufen wird. Die Funktion ShellExecuteW() befindet sich in der Systembibliothek shell32.dll. Die Deklaration dieser Funktion wird zur Ermöglichung des Zugriff am Anfang der Datei eingefügt.

Fazit

Durch den Gebrauch von Web-Browsern können wir zahlreiche verschiedene Informationen gleichzeitig anzeigen, was beispielsweise bei der Einrichtung einer Sichtkontrolle über den internen Zustand einzelner Module des Expert Advisors, die im Client Terminal ausgeführt werden, hilfreich sein kann.

Kapitalverwaltungsdaten, Handelssignale, Trailing Stop und sonstige Moduldaten können bequem und gleichzeitig angezeigt werden. Falls zu viele Informationen angezeigt werden sollen, können die mehrseitigen HTML-Berichte genutzt werden.

Es sollte beachtet werden, dass die JavaScript-Sprache weit mehr Möglichkeiten bietet als nur das Zeichnen von Diagrammen. Mit dieser Sprache können wir wirklich interaktive Webseiten erstellen. Im Internet finden Sie zahlreiche fertige JavaScript-Codes, die in Webseiten enthalten sind, und diverse Beispiele für den Gebrauch dieser Sprache.

Beispielsweise kann das Terminal direkt über das Browserfenster verwaltet werden, wenn der zweiseitige Datenaustausch zwischen dem Terminal und dem Browser eingerichtet ist.

Wir hoffen, dass sich die in diesem Beitrag beschriebene Methode als hilfreich erweist.

Dateien

JS_Lib.zip            - highcharts.js und jquery.min.js
librariesTest.zip   - highcharts.js, jquery.min.js und Test_01.htm
Example1.zip       - highcharts.js, jquery.min.js, Example1.htm, Example1.mq5 und exdat.txt
Example2.zip       - Example2.htm und exdat.txt
Report.zip           - ProfitReport.htm und data.txt
ProfitReport.mq5 - Script für das Sammeln von Statistiken und die Erstellung der Datei data.txt