Die Wechselwirkung zwischen MеtaTrader 4 und der MATLAB Engine (Virtual MATLAB Maschine)

Andrey Emelyanov | 6 April, 2016

Einleitung

MetaTrader 4 und das mathematische Paket MATLAB haben aufgrund ihrer positiven Eigenschaften wie zum Beispiel die "Flexibilität" bei der Erstellung komplexer Berechnungssysteme, bei den Benutzern stark an Popularität gewonnen. Es gibt drei Möglichkeiten, um eine Verbindung ziwschen MATLAB und externen Anwendungen herzustellen, aber nur eine von ihnen wird empfohlen - und zwar die Verwendung der virtuellen Desktop MATLAB Engine. Diese Methode garantiert die vollständige Kompatibilität mit dem gesamten MATLAB-Paket. Viele Programmierer vermeiden diese Methode aus den folgenden Gründen:

Warum ich diese Methode empfehle:

  1. Dies ist die zuverlässigste und unabhängigste Methode der MATLAB Version hinsichtlich einer Verbindung mit externen Programmen. Sie können die MATLAB Version ändern und Ihre Indikatoren oder Expert Advisors werden keine Notiz davon nehmen. Dies ist der wichtigste Vorteil.
  2. Sie hat eine relativ schnelle Entwicklungsmethode. Sie benötigt keine Debugger und das Schreiben des DLL-Wrapper wird keine Schwierigkeiten bereiten.
  3. "Gemeinsamer Desktop" für mehrere Indikatoren und/oder Expert Advisors. Ich betrachte diese Methode als hilfreich, wenn wir eine Entscheidung anhand von Daten mehrerer Indikatoren treffen müssen oder bei der Umsetzung eines Pyramiden-Trades.

Dieser Artikel beschreibt die Möglichkeit, über einen "DLL-Wrapper", der im Borland C++ Builder 6 geschrieben wurde, eine Verbindung zwischen MetaTrader 4 und MATLAB Version 7.4.0 (R2007a) herzustellen. Programmierer, die Microsoft-Produkte bevorzugen, müssen die Beispiele ihrem Compiler anpassen (viel Glück bei dieser komplizierten Angelegenheit!).

I. Einrichten einer Aufgabe

Zunächst müssen wir einmal festlegen, mit was wir das Projekt beginnen sollen. Lassen Sie uns den Entwicklungsprozess in drei Teile unterteilen:

  1. Die Entwicklung der M-Funktion in MATLAB, die die Berechnung eines Indikators/Expert Advisors implementiert.
  2. Die Entwicklung des "DLL-Wrapper", um MATLAB mit MetaTrader 4 zu verbinden.
  3. Die Entwicklung des MQL-Programms.

II. Die Entwicklung der M-Funktion

Die ist wahrscheinlich der interessanteste und am längsten laufende Prozess, der die folgenden Aktionen umfasst:

1. Das vorzeitige Exportieren von Daten aus MetaTrader 4 nach MATLAB.

Die Abbildungen zeigen den Prozess des manuellen Datenexports nach MATLAB. Wenn das Exportieren beendet ist, werden die Variablen im MATLAB-Desktop kreiert.

2. Die Suche nach den richtigen Formeln, den Bereichen der Formel-Parameter, usw.

Dieser Prozess ist kreativ und sehr wichtig, aber die Entwicklung des mathematischen Algorithmus eines Indikators und/oder Expert Advisors ist nicht Gegenstand unseres Artikels. In der Literatur über MATLAB können Sie Informationen darüber finden.

3. Kreierung der M-Funktion in MATLAB.

Ein Programmierer, der C++ und/oder MQL4 kennt, wird bei der Kreierung der Funktion keine Schwierigkeiten haben - zudem haben ale Variablen den gleichen Datentyp - "matrix". Es ist daher nicht von Bedeutung, eine Variable klar als Array oder mehrdimensionales Array zu definieren - die Programmiersprache übernimmt dies selbst. Ich empfinde den Prozess der Datentypauswahl als nicht signifikant. Was mich betrifft, ich benutze immer mxREAL. Nun, vielleicht wird mehr Speicher verwendet, aber es gibt in solch einem Fall keine Verwirrung. Weitere Details können Sie in den Referenzen 1, 2 finden. In dem gezeigten Beispiel ist der Filter hoher Frequenzen implementiert.

III. Die Entwicklung des "DLL-Wrapper"

Lassen Sie uns diesen Punkt genauer betrachten, da er so UNVERZICHTBAR ist wie die Luft zum Atmen. Jede DLL-Bibliothek der späten Anbindung muss also die folgenden Bedingungen erfüllen:

Die wichtigsten Merkmale des "DLL-Wrapper" sind die API-Schnittstelle der MATLAB Engine und eine Funktion der Standard C++ Eingabe/Ausgabe-Bibliothek. Die API Schnittstelle der MATLAB Engine ist einfach und kompakt; sie enthält nur 8 Funktionen:

Engine *pEng = engOpen(NULL) – Funktion, die dem MATLAB Desktop aufruft. Der Parameter ist immer NULL. Die Funktion gibt den Verweis auf den Desktop-Deskriptor zurück. Sie ist für die Funktionsweise anderer Funktionen erforderlich und die Variablen sind umfassend gemacht.

int exitCode = engClose(Engine *pEng) – Funktion, die den Desktop schließt. pEng Verweis auf den Desktop-Deskriptor. Gibt den Wert zurück, welcher unbedeutend ist, da diese Funktion bei der DLL-Schließung aufgerufen wird und nicht wichtig ist. Gibt die Anzahl der MATLAB Desktop "Benutzer" zurück.

mxArray *mxVector = mxCreateDoubleMatrix(int m, int n, int ComplexFlag) – Die Funktion erstellt eine Matrix für den MATLAB Desktop und gibt den Verweis auf die variable Matrix zurück. Sie ist zur Kreierung einer Variablen notwendig, die mit MATLAB kompatibel ist. Übliche Datenanordnungen und/oder einfache Datentypen können nicht an MATLAB gesendet werden!

mxArray *mxVector – Verweis auf die variable Matrix;

int m – Anzahl der Reihen;

int n – Anzahl der Spalten;

ComplexFlag – komplexer Nummerntyp, immer mxREAL für den korrekten Betrieb mit MetaTrader 4.

void = mxDestroyArray(mxArray *mxVector) – Die Funktion löscht die MATLAB-Matrix, was zur Löschung des Speichers benötigt wird. Löschen Sie immer Daten, wenn diese nicht mehr benötigt werden, denn ansonsten wird es zu Problemen mit dem Speicher oder zu "überlappenden" Ergebnissen kommen.

mxArray *mxVector – Verweis auf die variable Matrix.

int = engPutVariable( Engine *pEng, char *Name, mxArray *mxVector) – Die Funktion sendet eine Variable an den Desktop. Die Variablen des Typs mxArray müssen nicht nur kreiert, sondern auch an MATLAB gesendet werden.

Engine *pEng – Verweis auf den Desktop "Deskriptor";

char *Name – Name der Varialbe im MATLAB Desktop, Typ - char;

mxArray *mxVector – Verweis auf die variable Matrix.

mxArray *mxVector = engGetVariable(Engine *pEng, char *Name) – Funktion der Variablen, die vom Desktop erhalten wird. Die Funktion ist die gegensätzliche zur vorigen. Variable des Typs mxArray können erhalten werden.

mxArray *mxVector – Verweis auf die variable Matrix;

Engine *pEng – Verweis auf den Desktop "Deskriptor";

char *Name – Name der Varialbe im MATLAB Desktop, Typ - char.

double *p = mxGetPr(mxArray *mxVector) – die Funktion empfängt den Verweis auf dem Datenarray; sie wird verwendet, um gemeinsam mit memcpy(…) Daten zu kopieren. Verwenden Sie diese Funktion, wenn Sie eine Variable des Typs mxArray erhalten/schreiben, um eine Variable eines einfachen Typs zu extrahieren/einzufügen (int, double...).

double *p – Verweis auf das Array des Typs "double";

mxArray *mxVector – Verweis auf die variable Matrix.

int = engEvalString(Engine *pEng, char *Command) – Die Funktion sendet den Befehl zum Desktop. Der Befehl in der Befehlszeile wird vom MATLAB Desktop ausgeführt werden.

Engine *pEng – Verweis auf den Desktop "Deskriptor";

char *Command – Befehl für MATLAB, Zeile des char-Typs.

Es gibt nur eine Funktion zum Arbeiten mit dem Speicher:

void *pIn = memcpy (void *pIn, void *pOut, int nSizeByte) – Funktion zum Kopieren (Klonen) einer Variablen (Array) pOut in pIn Variable der nSizeByte Byte-Größe.

ACHTUNG: Achten Sie auf die Array Dimensionalität. Sie müssen entweder gleich sein, oder das Array pln sollte größter als pOut sein.

Voraussetzungen für das Exportieren der Funktionen des "DLL-Wrapper"

Damit MetaTrader 4 die MATLAB Funktionen verwenden kann, sollten Transmitter geschrieben werden. Lassen Sie uns die Voraussetzungen für die Projektion solcher Funktionen ansehen. Jede Funktion, die aus MetaTrader 4 aufgerufen wird, muss __stdcall sein – das heißt Parameter werden über Stapel übertragen, die Funktionen löschen den Stapel. Dies ist, wie die Funktion deklariert ist:

extern "C" __declspec(dllexport) <variable_type> __stdcall Funcion(<type> <name>);

extern "C" __declspec(dllexport) - informiert den C++ Compiler darüber, dass die Funktion extern ist. Dies wird in die Exporttabelle geschrieben.

<variable_type> - Typ einer Variablen zum Zurückkehren; kann sein: void, bool, int, double, gemischte Typen und Verweise können nicht übertragen werden; siehe weiter;

__stdcall – Einigung zur Parameter-Übertragung in die Funktion und zurück;

Function – Name der Funktion;

<type> <name> - Typ und Name der Eingangsvariablen; die maximale Anzahl von Variablen - 64.

Hier ist der Prototyp zum Definieren der Funktion. Richten Sie Ihre Aufmerksamkeit auch auf __stdcall

bool __stdcall Funcion (<type> <name>)

{

//……

}

Außerdem sollte eine Datei mit der Erweiterung def erstellt werden. Normalerweise ist es eine Textdatei, die den Bibliotheksnamen und die Namen der Exportfunktionen beschreibt. Wenn diese Datei nicht existiert, wird sich Ihre Datei ihre eigenen verzerrten Funktionsnamen "ausdenken", die die Verwendung von DLL erschweren. Hier ist ein Beispiel einer Datei:

LIBRARY NameDll

EXPORTS

NameFunctionA

NameFunctionB

LIBRARY – zusätzliches Wort, weist auf den DLL Namen hin.

EXPORTS – zusätzliches Wort, das besagt, dass bei der nachfolgenden Funktion die Namen aufgelistet werden.

NameFunctionA, NameFunctionB – Namen der DLL Funktionen.

Aber es gibt Einschränkungen, die durch MQL auferlegt sind: Da diese Sprache keine Verweise hat, hat sie keinen dynamischen Speicher, so dass Arrays, Strukturen, usw. nicht von einer DLL-Bibliothek übergeben werden können. In MetaTrader können Daten, die in Arrays geschrieben wurden, jedoch durch eine Funktion als Referenz übergeben werden. Das Ergebnis kann in einem Array, kreiert von MetaTrader, geschrieben werden. Der Verweis, den Ihr DLL erhalten hat. Das Array muss jedoch von einer bestimmten Dimensionalität sein und kann keine Anzeigezeile sein (diese Einschränkung hängt wohl mit der spezifischen Speicheranordnung in MetaTrader 4 zusammen).

Da wir nun wissen, wie man Funktionen schreibt und welche auzurufen sind, lassen Sie uns einen typischen Algorithmus des "DLL-wrapper" ansehen:

1. Starten der MATLAB Engine mit der Funktion engOpen() beim ersten Aufruf von DLL;

2. Erhalten der Daten von MetaTrader und zurücksenden, DLL-Funktion;

2.1. Erstellen der Variablen durch die Funktion mxCreateDoubleMatrix();

2.2. Kopieren der Daten in die mxVector Variable, Funktionen memcpy() und mxGetPr();

2.3. Übergeben der Variablen an den MATLAB Desktop, engPutVariable() Funktion;

2.4. Übergeben der Formel/des Codes an den MATLAB Desktop, engEvalString() Funktion;

2.5. Erhalten der Antwort vom MATLAB Desktop, engGetVariable() Funktion;

2.6. Zurückgeben des Werts an MetaTrader, Funktionen memcpy() und mxGetPr();

3. Schließen von MATLAB durch die Funktion engClose(), löschen aller Variablen mxDestroyArray(), wenn DLL aus dem Adressbereich des MetaTrader Prozess geladen werden.

Lassen Sie uns nun das Gerüst des "DLL-wrapper" erstellen:

/*---------------------------------------------------------------------------
** Libraries + *.lib + *.def:
** libeng.lib** libmx.lib
** libmex.lib** project_name.def
*/
#include <windows.h>#include <memory.h>#include "engine.h"
//---------------------------------------------------------------------------
extern "C" __declspec(dllexport)<variable_type>__stdcall Funcion(<type><name>);
//---------------------------------------------------------------------------
int WINAPI DllEntryPoint(HINSTANCE hinst,unsigned long reason,void *lpReserved)
  {
   /*    
** reason for DLL call    
*/
   switch(reason)
     {
      case DLL_PROCESS_ATTACH:
         /*            
** DLL uploaded into the address space of the process            
*/
         break;
      case DLL_PROCESS_DETACH:
         /*            
**DLL loaded from the address space of the process            
*/
         break;
     }
   return TRUE;
  }
//---------------------------------------------------------------------------
bool __stdcall Funcion(<type><name>)
  {
   ……
  }
//---------------------------------------------------------------------------

Zusammenbau des Projekts

Die folgende Abbildung zeigt, wie Bibliotheken und *.def Dateien dem Projekt hinzugefügt werden:

Hier ist die Liste der Dateien, die für das Projekt "DLL-Wrapper" notwendig sind:

  1. libeng.lib – befindet sich in: \Program Files\MATLAB\R2007a\extern\lib\win32\borland\
  2. libmx.lib – befindet sich in: \Program Files\MATLAB\R2007a\extern\lib\win32\borland\
  3. libmex.lib – befindet sich in: \Program Files\MATLAB\R2007a\extern\lib\win32\borland\
  4. имя_проекта.def – diese Datei sollte wie oben beschrieben, mit Hilfe von Notepad erstellt werden.

Die Datei engine.h sollte aus \Program Files\MATLAB\R2007a\extern\\include in den Ordner \Program Files\Borland\CBuilder6\Include kopiert werden - dadurch müssen Sie nicht jedes Mal den Pfad zum Compiler angeben.

Achtung: Diese Anleitung ist nur für den Zusammenbau des Projekts mit dem Borland C++ Builder 6 bestimmt!

IV. Entwickeln eines MQL4 Programms

Wir werden uns nun Fragen ansehen, die sich ausschließlich mit der Deklaration von "DLL Wrapper" Funktionen und der Übergabe von Parametern befassen. Um also eine Funktion zu deklarieren, ist der folgende Programmiersprachenaufbau erforderlich:

#import "HighPass.dll"

void ViewAnsFilter();

bool TestDllFilter();

bool AdaptiveHighFilter(double& nInVector[], int nSizeVector, double nSizeWind, double dAmplit);

void MakeBuffFilter(int nSize);

void DestrBuffFilter();

#import

wo:

#import "HighPass.dll" – Schlüsselwort und der Name einer DLL-Bibliothek;

void MakeBuffFilter(int nSize); - Funktionsname, Typ eines Werts, der zurückgeschickt wird, Name und Typ eines übergebenen Werts.

NB ! "[]" wird beim Übergeben von Arrays verwendet, das Sonderzeichen "&" ist notwendig, wenn dll eine Antwort in dieses Datenarray schreibt! Es gibt keine andere Möglichkeit zur Übergabe eines Arrays von externen Programmen nach MQL 4! Das Array, das übergeben werden soll, muss von einer bestimmten Dimensionalität sein und kann kein Indikator-Array sein!

V. Ort der Dateien

Nach dem Projektaufbau sollten sich alle Projektdateien an ihrem korrekten Ort befinden:

*.dll und *.m - Bibliotheksdateien und m-Funktionen im Ordner \Program Files\MetaTrader\experts\libraries;

*.mql befindet sich an seinem üblichen Platz, das heißt, wenn es sich um einen Indikator handelt - im Ordner 'Indikatoren', wenn es sich um einen EA handelt - im Ordner 'Experts', und im Falle eines Skrips - im Ordner 'Skripte'.

Achtung: Beim Starten eines Indikators oder Expert Advisors kann eine Warnung über einen ausgelasteten Server erscheinen:

Warten Sie in solch einem Fall 5-10 Sekunden bis die Matlab Konsole in der Taskleiste erscheint und klicken Sie dann auf "Wiederholen".

P.S. Ich habe ein Notebook mit 512 RAM, Celeron M 2100; Ich konnte keine Verzögerungen bei den Filteroperationen feststellen. Anzahl der Charts war 5 mit einem Gesamtpuffer von 500 х 8 х 5 = 20 000 Bytes. Die Wahl liegt also bei Ihnen! Was mich betrifft, habe ich sie schon getroffen. Falls Verzögerungen auftreten, kann ganz einfach ein dezentrales Rechensystem in MATLAB implementiert werden, das heißt mehrere Desktops können auf verschiedenen PCs gestartet werden, die an einem lokalen Netzwerk angeschlossen sind.

Referenzliste

  1. Eingebaute MATLAB Hilfe.
  2. "Matlab 5.х Berechnungen, Visualisierung, Programmieren" N.N. Martynov.
  3. "C++ Builder 6. Referenzhandbuch" A.Y. Arkhangelski.
  4. Eingebaute MQL4 Hilfe.

Fazit

In diesem Artikel haben wir über die Grundlagen der "DLL-Wrapper" Entwicklung für die Einbindung von MetaTrader 4 mit dem MATLAB mathematischen Paket gesprochen. Wir sind nicht auf die Fragen hinsichtlich des Verwendens mehrerer Indikatoren und/oder Expert Advisors eingegangen - diese werden im nächsten Artikel behandelt. Die angehängte Datei enthält MACD, allerdings verbessert aufgrund der Verwendung eines Hochfrequenzfilters.