Die rechnerische Fähigkeiten von MATLAB 2018 im MetaTrader 5 nutzen

14 Mai 2019, 08:47
Roman Korotchenko
1
151

Einführung

Dieser Artikel ist eine Weiterentwicklung des Artikels "Die Wechselwirkung zwischen MеtaTrader 4 und der MATLAB Engine" von A. Emelyanov und enthält Informationen zur Lösung einer ähnlichen Aufgabe für moderne 64-Bit-Versionen aller von Anwendern verwendeten Plattformen. Im Laufe der letzten Zeit wurde die Methode zur Erstellung gemeinsamer DLL-Bibliotheken im MATLAB-Paket erheblich verbessert. Daher muss die im Originalartikel beschriebene Methode geändert werden. Dies geschah, weil das SDK des MATLAB-Compilers oder der MATLAB-Coder nun anstelle des MATLAB-Compilers verwendet werden muss. Darüber hinaus hat sich die Praxis des Arbeitens mit dynamischem Speicher in MATLAB geändert, was bestimmte Anpassungen des Quellcodes erfordert, der eine in der MATLAB-Sprache geschriebene Bibliothek adressiert. 

Der Name dieses Artikels besagt, dass die Arbeit hier darauf abzielt, die Aufgabe der Entwickler zu erleichtern, die Rechenfähigkeiten von MATLAB mit MQL5-Programmen zu verschmelzen. Zu diesem Zweck verwendet der Artikel ein Beispiel für die Erstellung eines prädiktiven Indikators auf der Grundlage des Modells der saisonalen Autoregression Integrierter Gleitender Durchschnitt (SARIMA) für eine Preiszeitreihe, bei der die Aufgabe der Auswahl eines geeigneten Modells und der Hochrechnung von Daten auf MATLAB gelegt wird. 

Um die Details der Verbindung der Rechenleistung der MATLAB 2018-Umgebung mit MQL5 zu demonstrieren, konzentriert sich dieser Artikel auf das SDK des MATLAB-Compiler sowie auf die Erstellung einer Adapterbibliothek unter Visual C++ zur Kopplung der MATLAB-Bibliothek mit MQL5. Dies ermöglicht es, eine kurze Anleitung zur Erstellung von Programmen zu erhalten und häufige Fehler zu vermeiden. 

Einfache und komplexe Datentypen, die im Kapitel 1 des Artikels von A. Emelyanov beschrieben sind, werden nicht verändert. Um das mit hoher Qualität beschriebe Material nicht zu duplizieren, ist es ratsam, sich mit der dort vorgestellten Beschreibung vertraut zu machen. Unterschiede ergeben sich bei der Erstellung einer gemeinsamen C++-Bibliothek aus der MATLAB-Umgebung. 

Dieser Artikel stellt das Material nach dem folgenden Schema dar:

  1. Eine C++ Shared Library mit der Kalman-Filterung und Datenvorhersage basierend auf dem Modell Seasonal Autoregression Integrated Moving Average wird mit einer Reihe von MATLAB-Modulen erstellt, die für den Indikator vorbereitet sind. 
  2. Anschließend wird das Berechnungsmodul in das MQL5-Programm aufgenommen. Dazu wird zusätzlich eine Zwischenbibliothek erstellt, die das Problem des Datentransfers zwischen MQL5 (mit im Stile von C/C++ organisiertem Speicher) und MATLAB (mit matrixförmig organisiertem Speicher) löst.
  3. Es wird ein prädiktives Modell beschrieben, das dann in den erstellten Indikator eingebettet wird und dessen Leistung demonstriert wird.

1. Erstellen einer gemeinsamen C++-Bibliothek aus MATLAB-Funktionen mit dem SDK des MATLAB-Compilers

Im Jahr 2015 hat sich das Verfahren zur Erstellung von DLL-Bibliotheken in MATLAB geändert. Was die Integration mit MQL5-Programmen betrifft, so ist das Problem darauf zurückzuführen, dass der MATLAB Compiler nicht mehr für die Erstellung von Bibliotheken gedacht ist und nun auf die Erzeugung autonomer ausführbarer Dateien ausgerichtet ist. Seit 2015 werden die Funktionen zur Erstellung von DLL-Bibliotheken auf das SDK des MATLAB-Compilers übertragen. Das SDK des MATLAB-Compilers hat die Funktionalität des MATLAB Compilers erweitert, so dass er C/C++ Shared Libraries, Microsoft.NET Assemblies und Java-Klassen aus dem MATLAB-Programmen erstellen kann.

Wie bisher können Anwendungen, die mit Programmkomponenten aus dem MATLAB Compiler SDK-Paket erstellt wurden, kostenlos an Benutzer weitergegeben werden, die MATLAB nicht benötigen. Diese Anwendungen verwenden MATLAB Runtime und eine Reihe von gemeinsamen Bibliotheken, die kompilierte Anwendungen oder MATLAB-Komponenten verwenden.

Die zuvor der MATLAB Compiler-Anwendung zugewiesene Aufgabe wurde an das Programm Library Compiler delegiert. Um ein vollständiges Bild zu vermitteln, betrachten wir die Vorgehensweise zur Erstellung einer C/C++ Shared Library aus der MATLAB-Umgebung. Das dem Artikel beigefügte ZIP-Archiv enthält Dateien mit der Erweiterung .m, die für die Erstellung der Bibliothek verwendet wurden. In MATLAB wird die Anwendung Library Compiler gestartet (auf der Registerkarte APPS), das Projekt LibSARIMA.prj wird geöffnet und eine Struktur gebildet, ähnlich der in der folgenden Abbildung gezeigten.

Abb. 1. Die Schnittstelle des Library Compilers

Abb. 1. Die Schnittstelle des Library Compilers

 

Dabei ist es wichtig, auf die in Abbildung 1 hervorgehobenen Positionen mit den Linien und Nummern 1-4 zu achten. 

  1. Eine gemeinsame Bibliothek des C++-Standards wird erstellt.
  2. Die in ForecastSARIMA.m vorgestellte Funktion wird exportiert, während die anderen Funktionen nicht exportiert werden und keinen Zugriff auf externe Programme erhalten.
  3. Es werden Dateien für die Verknüpfung in der Standardschnittstelle erzeugt (matlabsarima.dll, matlabsarima.h, matlabsarima.lib). 
  4. Die Schnittstelle für den Zugriff auf die MATLAB-Matrix wird über mwArray Strukturen realisiert.

Nach dem Drücken der Schaltfläche "Package" wird die Bibliothek generiert. Es ist möglich, den Generierungsmodus der Bibliothek auszuwählen, der die Benutzer auffordert, die MATLAB Engine aus dem Internet herunterzuladen, oder der die notwendigen Komponenten der MATLAB Engine in den Paketinhalt aufnimmt. 

In diesem Stadium wird eine Bibliothek erstellt, die ein Programm zum Filtern einer Zeitreihe, zum Erstellen eines SARIMA-Modells und zur Prognose enthält. Das Archiv MatlabSArima.zip bietet eine Reihe von Quellcodes und den daraus resultierenden Bibliotheksaufbau.

2. Erstellen einer Zwischenbibliothek in Microsoft Visual C++

Sobald die Hauptbibliothek erstellt ist, ist die nächste Aufgabe, sich mit ihr zu verbinden, die Daten weiterzugeben und die Ergebnisse nach Berechnungen zu sammeln. Dazu wird eine Adapterbibliothek erstellt, die die Datenübersetzung zwischen MQL5 (mit im C/C++-Stil organisiertem Speicher) und MATLAB (mit im Matrixformat organisiertem Speicher) ermöglicht.

In neueren Versionen von MATLABx64 gehört der Visual C++-Compiler zu den wichtigsten, für die die gesamte notwendige Software vorbereitet ist. Daher ist die schnellste, bequemste und zuverlässigste Methode zur Erstellung der Hilfsadapterbibliothek die Verwendung von Visual C++ in Studio 2017.

 

MetaTrader 5 und MATLAB 2018 Interaktion

Abb. 2. Diagramm der Interaktion von MetaTrader 5 und MATLAB 2018 über eine Adapter-DLL

Eine wichtige Innovation im Jahr 2017 war die Einführung von Strukturen wie mwArray API in MATLAB, die die Erstellung und Integration von gepackten Funktionen in C++-Anwendungen ermöglichen. Das bisher verwendete mxArray wurde auf eine neue Matrixschnittstelle aufgerüstet. Es gibt noch eine weitere Option zur Integration einer Shared Library — die Schnittstelle MATLAB Data API, die in unserem Fall jedoch irrelevant ist.

Um mit dem Schreiben des Adapters für Daten zu beginnen, ist es wünschenswert, drei Systemumgebungsvariablen im Betriebssystem vorzubereiten und zu registrieren. Dies kann beispielsweise im Explorer über die "Systemeigenschaften" unter "Erweiterte Systemeinstellungen" und "Umgebungsvariablen" erfolgen.

  1. Die erste Variable — MATLAB_2018 sollte auf ein Verzeichnis mit installierter MATLAB oder MATLAB Runtime zeigen; 
  2. Die zweite Variable — MATLAB_2018_LIB64 sollte auf ein Verzeichnis mit externen Bibliotheken verweisen: <MATLAB_2018>\extern\lib\lib\win64;
  3. Die dritte Variable — MATLIB_USER sollte auf ein Verzeichnis zeigen, in dem die Originalbibliotheken abgelegt werden sollen. Dieses Verzeichnis muss auch der Systemvariablen "Path" hinzugefügt werden, um das Problem der Suche nach den ursprünglichen Benutzerbibliotheken zu lösen.  

2.1 Schreiben eines Adapters in Visual Studio 2017

Nachdem Sie das Projekt der Dynamic Link Library in Visual Studio 2017 erstellt haben, ist es notwendig, eine Reihe von Eigenschaften festzulegen. Um deutlich zu machen, welche der Eigenschaften kontrolliert werden müssen, finden Sie im Folgenden Abbildungen, die die Konfiguration des Montageprojekts erleichtern.

Adapterprojekt Optionen #0

Abb. 3. Eigenschaftsseiten (A, B, C, D, E) auf denen etwa geändert werden muss

Adapterprojekt Optionen #1

Abb. 4. Verzeichnisse, in denen die benötigten Projektdateien gesucht werden sollen

In Abb. 4 wurde das Verzeichnis $(MatLib_User) in das Feld "Library Directories" aufgenommen. Dieses Verzeichnis ist praktisch für das Platzieren von Universalbibliotheken, die sowohl für die Programmierung in Visual C/C++ als auch für Berechnungen in MetaTrader 5 benötigt werden. In diesem Fall sind das matlabsarima.lib und matlabsarima.dll.

Die Makro-Seite

Abb. 5. Einstellen der Definitionen des Präprozessor


Die Calling Convention

Abb. 6. Die Calling Convention gemäß den Anforderungen von MQL5

Zusätzliche Abhängigkeiten (*.lib)

Abb. 7. Specifying additional dependencies (*.lib)

Hier ist eine Liste der erforderlichen Änderungen in den Projekteinstellungen:

  1. Geben Sie die Verzeichnisse mit den gewünschten Headerdateien an;
  2. Geben Sie die Verzeichnisse mit den erforderlichen Bibliotheksdateien an;
  3. Eintellen der Präprozessor-Definitionen — ein Makro, seine Funktionen werden im Folgenden berücksichtigt;
  4. Geben Sie die für die Arbeit benötigten spezifischen Bibliotheken an (vorbereitet von MATLAB).

Zwei Dateien, die mit MATLAB - matlabsarima.lib und matlabsarima.dll erzeugt wurden, sollten in das gemeinsame Verzeichnis verschoben werden, das in den Systemvariablen als $(MATLIB_USER) markiert ist. Die Datei matlabsarima.h sollte sich in dem Verzeichnis befinden, in dem das Projekt zusammengestellt wurde. Sie sollte in die "Header-Dateien" des Projekts aufgenommen werden.

Um den Adapter zusammenzubauen, ist es notwendig, mehrere Dateien zu erstellen, von denen zwei besprochen werden sollten.

1. Die Datei AdapterSArima.h 

#pragma once
#ifdef ADAPTERSARIMA_EXPORTS
#define _DLLAPI extern "C" __declspec(dllexport)  // diese Definition wird für die Verbindung von DLL- und LIB-Bibliotheken benötigt
#else
#define _DLLAPI extern "C" __declspec(dllimport)  // diese Definition wird für die Einbindung der DLL-Bibliotheken benötigt
#endif
_DLLAPI int prepareSARIMA(void);
_DLLAPI int goSarima(double *Res, double *DataArray, int idx0, int nLoad, int iSeasonPriod = 28, int npredict = 25, int filterOn = 1, int PlotOn = 0);
_DLLAPI void closeSARIMA(void);

Die Datei AdapterSArima.h verwendet ein in den Einstellungen angegebenes Makro, um anzuzeigen, dass die Prozeduren prepareSARIMA(), closeSARIMA(), closeSARIMA() und goSarima(...) zum Bündeln mit externen Programmen zur Verfügung stehen.

2. Die Datei GoSArima.cpp

#pragma once
#include "stdafx.h"
#include "matlabsarima.h"
#include "AdapterSArima.h"

bool  SArimaStarted = false;
bool  MLBEngineStarted = false;

//-----------------------------------------------------------------------------------
_DLLAPI int prepareSARIMA(void)
{
        if (!MLBEngineStarted)
        {
                MLBEngineStarted = mclInitializeApplication(nullptr, 0);
                if (!MLBEngineStarted)
                {
                        std::cerr << "Could not initialize the Matlab Runtime (MCR)" << std::endl;
                        return 0;
                }
        }       
        if (!SArimaStarted)
        {
                try
                {
                        SArimaStarted = matlabsarimaInitialize();
                        if (!SArimaStarted)
                        {
                                std::cerr << "Could not initialize the library properly" << std::endl;
                                return false;
                        }                       
                        return (SArimaStarted)?1:0;
                }
                catch (const mwException &e)
                {
                        std::cerr << e.what() << std::endl;
                        return -2;
                }
                catch (...)
                {
                        std::cerr << "Unexpected error thrown" << std::endl;
                        return -3;
                }
        }
        return 1;
}
//-----------------------------------------------------------------------------------

_DLLAPI void closeSARIMA(void)
{
        // Aufrufen der Anwendung un der Routine für die Beendigung der Bibliothek 
        //if (SArimaStarted)
        {
                matlabsarimaTerminate();
                SArimaStarted = false;
        }
}
//-----------------------------------------------------------------------------------

_DLLAPI int goSarima(double *Res, double *DataSeries, int idx0, int nLoad, int iSeasonPeriod, int npredict, int filterOn, int PlotOn)
{       //
        // Der Speicher für die Ergebnisse muss unter Berücksichtigung der Vorhersage des Indikators im Vorhinein reserviert werden
        // Der Speicher für Res[] muss reserviert werden. Length = nLoad+npredict !!!
        //
        if (!SArimaStarted)
        {
                SArimaStarted = (prepareSARIMA() > 0) ? true : false;
        }
        
        mwArray nSeries(1, 1, mxDOUBLE_CLASS), TimeHor(1, 1, mxDOUBLE_CLASS), MAlen(1, 1, mxDOUBLE_CLASS);
        mwArray SeasonLag(1, 1, mxDOUBLE_CLASS), DoPlot(1, 1, mxDOUBLE_CLASS), DoFilter(1, 1, mxDOUBLE_CLASS);

        if (SArimaStarted)
        {
                try
                {               
                    MAlen  = 20;         // Glättungslänge für den MA
                        DoFilter  = (filterOn != 0) ? 1 : 0;
                        TimeHor   = npredict; // Vorhersagepunkte
                        SeasonLag = iSeasonPeriod;     // saisonale Periodenlänge für das Model SARIMA
                        
                        DoPlot = PlotOn;    // Zeichnen im Testmode

                        nSeries = nLoad;    // Datenfragment mit der Länge nLoad
                                        
                        mwArray Series(nLoad,1, mxDOUBLE_CLASS, mxREAL);
                        mwArray Result; // Ergebnis (gefiltert (wenn angegeben filterOn!=0) Daten und Vorhersage)
                        
                //      laden der Daten in die MATLAB-Matrix
                        Series.SetData(&DataSeries[idx0], nLoad); // Fragment DataSeries[idx0: idx+nLoad]
        
                        ForecastBySARIMA(1, Result, nSeries, TimeHor, Series, SeasonLag, DoFilter, MAlen, DoPlot);
                        size_t nres = Result.NumberOfElements();
                        Result.GetData(Res, nres);

                  return 0;
                }
                catch (const mwException& e)
                {
                        std::cerr << e.what() << std::endl;
                        return -2;
                }
                catch (...)
                {
                        std::cerr << "Unexpected error thrown" << std::endl;
                        return -3;
                }               
        }       
        return 0;
}

Der Vollständigkeit halber enthält das Zip-Archiv alle Dateien für die Zusammenstellung der Zwischenbibliothek AdapterSArima.dll. Bei Bedarf wird empfohlen, das Archiv zu entpacken und den Adapter unter "C:\temp" neu zusammenzusetzen.

3. Anlegen eines Indikators

3.1 Problemstellung und Lösungsverfahren

Das Modell der Autoregressions und des Gleitenden Durchschnitts ist äußerst nützlich, um einige der in der Praxis vorkommenden Zeitreihen zu beschreiben. Dieses Modell kombiniert einen Tiefpassfilter in Form eines gleitenden Durchschnitts der Ordnung q und die Autoregression von gefilterten Werten des Prozesses der Ordnung p. Verwendet das Modell nicht die Zeitreihenwerte, sondern deren Ordnungsunterschied d (in der Praxis ist es notwendig, d zu bestimmen, aber in den meisten Fällen ist d ≤ 2) als Eingabedaten, dann wird das Modell als Autoregression des integrierten gleitenden Durchschnitts bezeichnet. Ein solches Modell — ARIMA(p,d,q) (Autoregression integrierter gleitender Durchschnitt) ermöglicht es, die Nichtstationarität der ursprünglichen Serie zu reduzieren.

Um die Auswirkungen von Langzeitschwankungen zu simulieren, gibt es eine Modifikation namens Seasonal ARIMA. Dieses Modell entspricht den Zeitreihen, die periodischen Faktoren ausgesetzt sind. Aktienkurse werden durch saisonale Faktoren beeinflusst, so dass ihre Einbeziehung in das Modell geeignet ist, eine Preisprognose im Indikator zu erstellen. 

Um den Einfluss von Rauschfaktoren auf die eingehenden Bestandsangebote zu reduzieren, ist es wünschenswert, die Möglichkeit einer zusätzlichen Filterung und Bereinigung der Daten von Fehlern vorzusehen. Je verrauschter die Daten sind, desto schwieriger ist die Verarbeitung. Der Kalman Filter ist ein effektiver rekursiver Filteralgorithmus, der in verschiedenen Bereichen eingesetzt wird. Der Algorithmus besteht aus zwei sich wiederholenden Phasen: Vorhersage und Anpassung. Zunächst wird die Prognose des Zustands zum nächsten Zeitpunkt berechnet (unter Berücksichtigung der Ungenauigkeit der Messung). Anschließend wird unter Berücksichtigung der neuen Informationen der vorhergesagte Wert korrigiert (auch unter Berücksichtigung der Ungenauigkeit und des Rauschens dieser Informationen). 

3.2 Das Indikatorprogramm in MQL5

Die für den Indikator benötigten Bibliotheken AdapterSArima.dll und matlabsarima.dll sollten im Verzeichnis Libraries des Arbeitsverzeichnisses MetaTrader 5 abgelegt werden.

Debugging und Testing haben bestimmte Besonderheiten. In diesem Modus startet MetaEditor die Bibliothek aus den Hilfsverzeichnissen "<MetaQuotes\Tester\....\Agent-127.0.0.0.1-300x>", wobei 300x die Werte 3000, 3001, 3002, etc. übernimmt. In diesem Fall wird die Bibliothek AdapterSArima.dll automatisch kopiert, nicht aber matlabsarima.dll. Um zu verhindern, dass dies die Funktion der Anzeige beeinträchtigt, sollte die Bibliothek matlabsarima.dll im Verzeichnis der Systemsuche abgelegt werden. Es wurde empfohlen, ein solches Verzeichnis als $(MATLIB_USER) zu bezeichnen und es in der Systemliste der Suchpfade anzugeben oder nach Windows oder Windows\System32 zu kopieren. Dann wird die Bibliothek erkannt, verbunden und der Indikator kann starten. 

Das Indikatorprogramm, das die Vorhersage gemäß dem betrachteten Modell implementiert, ist in der Datei ISArimaForecast.mq5 und im angehängten Archiv verfügbar.

//+------------------------------------------------------------------+
//|                                              ISArimaForecast.mq5 |
//|                                                Roman Korotchenko |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright   "Roman Korotchenko"
#property link        "https://login.mql5.com/ru/users/Solitonic"
#property description "This indicator demonstrates forecast by model SARIMA(2,1,2)."
#property description "The program actively uses MATLAB with professionally developed toolboxes and the ability to scale."
#property version   "1.00"
#property indicator_chart_window 

#import "AdapterSArima.dll"
int  prepareSARIMA(void);
int  goSarima(double &Res[],double &DataArray[],int idx0,int nLoad,int iSeasonPeriod,int npredict,int filterOn,int PlotOn);
void closeSARIMA(void);
#import

#property indicator_buffers 2    //---- Puffer zum Berechnen und Zeichnen des Indikators
#property indicator_plots   1    //---- Grafik
#property indicator_type1  DRAW_COLOR_LINE   
#property indicator_color1  clrChocolate, clrBlue // clrWhite, clrBlue
#property indicator_width1  3 
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
enum ENUM_TIMERECALC
  {
   TimeRecalc05 = 5,   // 5 sec
   TimeRecalc10 = 10,  // 10 sec
   TimeRecalc15 = 15,  // 15 sec
   TimeRecalc30 = 30,  // 30 sec
   TimeRecalc60 = 60   // 60 sec
  };
//--- Eingabeparameter
input ENUM_TIMERECALC RefreshPeriod=TimeRecalc30;         // Wiederberechnungsperiode
input int      SegmentLength  = 450; // N: Datenfragment
input int      BackwardShift  = 0;   // Rückwärts Verschub (Test)
input int      ForecastPoints = 25;  // Punkt für die Vorhersage
input int      SeasonLag=32;         // saisonale Verzögerung von SARIMA(2,1,2)
input bool     DoFilter=true;        // Mit Kalman-Filter der Datenreihe

                                     // input string   _INTERFACE_   = "* INTERFACE *"; 
//input long     magic_numb=19661021777;       // Magicnummer 

//--- Indikatorpuffer
double   DataBuffer[],ColorBuffer[];
//double   LastTrend[],LastData[];

double   wrkResult[],wrkSegment[];
static int wRKLength;

uint CalcCounter;
//
uint calc_data;
uint start_data;    // Startzeit des Charts
uint now_data;      // Aktuelle Zeit

static int libReady=0,ErrorHFRange,ErrorDataLength;
static bool   IsCalcFinished;

//+------------------------------------------------------------------+
//| Initialisierungsfunktion des nutzerdefinierten Indikators        |
//+------------------------------------------------------------------+
static int LengthWithPrediction;

static int PlotOn;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnDeinit()
  {
   closeSARIMA();
   Alert("SARIMA DLL - DeInit");
   Print("SARIMA DLL - DeInit");
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int OnInit()
  {
   if(!TerminalInfoInteger(TERMINAL_DLLS_ALLOWED))
      Alert("Check the connection permission in the terminal settings DLL!");
   else
     {
      libReady=prepareSARIMA();
      if(libReady<0)
        {
         Alert("Dll DOES NOT CONNECTED!");
         return(INIT_FAILED);
        }

     }

   LengthWithPrediction=SegmentLength+ForecastPoints;
//--- Zuweisung der Puffer des Indikators
   SetIndexBuffer(0,DataBuffer,INDICATOR_DATA);            ArraySetAsSeries(DataBuffer,true);
   SetIndexBuffer(1,ColorBuffer,INDICATOR_COLOR_INDEX);    ArraySetAsSeries(ColorBuffer,true);
// SetIndexBuffer(2,LastTrend,   INDICATOR_CALCULATIONS);   ArraySetAsSeries(LastTrend,true);      //für Expert
// SetIndexBuffer(3,LastData,    INDICATOR_CALCULATIONS);   ArraySetAsSeries(LastData,true);       //für Expert

   PlotIndexSetInteger(0,PLOT_SHIFT,ForecastPoints-BackwardShift);

   wRKLength = ForecastPoints+ SegmentLength; // Anzahl der Elemente im Array der Ergebnisse
   ArrayResize(wrkResult,wRKLength,0);        // Speicherreservierung der Funktion Ergebnisse
   ArrayResize(wrkSegment,SegmentLength,0);   // Speicherreservierung der Eingabedaten.

//---   
   string shortname;
   StringConcatenate(shortname,"SARIMA(2,1,2). Season Lag: ",SeasonLag,"  // ");
//--- Kennzeichnung für das Datenfenster
   PlotIndexSetString(0,PLOT_LABEL,shortname);
   IndicatorSetString(INDICATOR_SHORTNAME,shortname);

   now_data  = 0.001*GetTickCount();
   start_data= 0.001*GetTickCount();
   calc_data = 0;

   CalcCounter    = 1;
   IsCalcFinished = true;

   ErrorHFRange   = 0;
   ErrorDataLength= 0;

   PlotOn=0; // Hilfszeichnung, durchgeführt von MATLAB (für Tests)

   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Funktion des nutzerdefinierten Indikators                        |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const int begin,
                const double &price[]
                )
  {
//---
   int ShiftIdx=rates_total-SegmentLength-BackwardShift; // Der Startindex für die Arbeit mit dem Datensegment

   if(ShiftIdx<0)
     {
      if(!ErrorDataLength)
        {
         PrintFormat("SARIMA INDI FAULT: there are not enough data.");
         ErrorDataLength=1;
        }
      return(0);
     }

   ErrorDataLength=0;

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

   now_data=0.001*GetTickCount();

   if(now_data-calc_data<RefreshPeriod || !IsCalcFinished) // Berechnung wird nicht benötigt oder ist unvollständig
     {
      // ReloadBuffers(prev_calculated,rates_total);
      return(prev_calculated);
     }
   if(prev_calculated!=0 && !IsCalcFinished)
     {
      return(prev_calculated);  // Neue Daten kommen schneller, als das Ende der aktuellen Berechnung
     }
//---------------------------------------------------------------------------     

   IsCalcFinished=false; // Blockieren der Anforderung einer neuen Berechnung bis die aktuelle ausgeführt wurde

   int idx=0,iBnd2=ShiftIdx+SegmentLength;
   for(int icnt=ShiftIdx; icnt<iBnd2; icnt++)
     {
      wrkSegment[idx++]=price[icnt];
     }

   ErrorHFRange=0;
// MATLAB SUBROUTINE   
   goSarima(wrkResult,wrkSegment,0,SegmentLength,SeasonLag,ForecastPoints,DoFilter,PlotOn);

   ReloadBuffers(LengthWithPrediction,rates_total);

   ++CalcCounter;
   IsCalcFinished=true; // Fertig für die neue Berechnung

   calc_data=0.001*GetTickCount();

   return(rates_total);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void EmptyBuffers(int n)
  {
   for(int i=0; i<n; i++)
     {
      DataBuffer[i] = EMPTY_VALUE;
      ColorBuffer[i]= EMPTY_VALUE;
     }
  }
//+------------------------------------------------------------------+ 

void ReloadBuffers(int npoint,int ntotal)
  {
   ResetLastError();
   EmptyBuffers(ntotal); // ntotal = rates_total

   if(npoint== 0) return;
   int k=0;//BackwardShift;
   for(int i=0; i<npoint; i++) // npoint = LengthWithPrediction
     {
      if(i>=ntotal) break;
      DataBuffer [k]=wrkResult[LengthWithPrediction-1-i];
      ColorBuffer[k]=(i<ForecastPoints)? 1:0;
      k++;
     }
  }
//=============================================================================

4. Veranschaulichung des Verhaltens des Indikators

Die Performance des Indikators wurde anhand der EURUSD H1-Handelsdaten getestet, die von der MetaTrader-Plattform bereitgestellt werden. Es wurde ein nicht zu großes Datensegment ausgewählt, das 450 Einheiten entspricht. Langjährige "saisonale" Verzögerungen in Höhe von 28, 30 und 32 Einheiten wurden getestet. Die Verzögerung mit einem Zeitraum von 32 Einheiten war die beste von ihnen auf dem betrachteten Zeitraum der Geschichte.

Es wurde eine Reihe von Berechnungen für verschiedene historische Fragmente durchgeführt. Im Modell wurden die Länge der Datensegmente von 450 Einheiten, die saisonale Verzögerung von 32 Einheiten und die Vorhersagelänge von 30 Einheiten einmal festgelegt und blieben unverändert. Um die Qualität der Prognose zu beurteilen, wurden die Ergebnisse für verschiedene Fragmente mit den tatsächlichen Daten verglichen.

Nachfolgend finden Sie die Abbildungen, die das Ergebnis der Anzeigeoperation zeigen. In allen Abbildungen zeigt die Farbe Braun die Fertigstellung eines Fragments an, das zur Auswahl des Modells SARIMA(2,1,2) verwendet wird, und das auf seiner Grundlage erzielte Ergebnis wird in blau dargestellt.

EURUSDH1_450(32)-180

Abb. 8. Handelssession 30.12.2018. Es wird ein Kalman-Filter verwendet Das Modell mit Daten, die um 180 Einheiten in die Vergangenheit verschoben wurden


 EURUSDH1_450(32)-170

Abb. 9. Tägliche Handelssession 30.12.2018. Der Kalman-Filter wird nicht verwendet Das Modell mit Daten, die um 170 Einheiten in die Vergangenheit verschoben wurden


EURUSDH1_450(32)-140

Abb. 10. Handelssession 30.12.2018. Es wird ein Kalman-Filter verwendet Das Modell mit Daten, die um 140 Einheiten in die Vergangenheit verschoben wurden


EURUSDH1_450(32)-120

Abb. 11. Handelssession 30.12.2018. Es wird ein Kalman-Filter verwendet Das Modell mit Daten, die um 120 Einheiten in die Vergangenheit verschoben wurden


EURUSDH1_450(32)-100

Abb. 12. Handelssession 30.12.2018. Es wird ein Kalman-Filter verwendet Das Modell mit Daten, die um 100 Einheiten in die Vergangenheit verschoben wurden


EURUSDH1_450(32)-50

Abb. 13. Handelssession 30.12.2018. Es wird ein Kalman-Filter verwendet Das Modell mit Daten, die um 50 Einheiten in die Vergangenheit verschoben wurden 


EURUSDH1_450(32)-20

Abb. 14. Handelssession 30.12.2018. Es wird ein Kalman-Filter verwendet Das Modell mit Daten, die um 20 Einheiten in die Vergangenheit verschoben wurden 


EURUSDH1_450(32)-10

Abb. 15. Handelssession 30.12.2018. Es wird ein Kalman-Filter verwendet Das Modell mit Daten, die um 10 Einheiten in die Vergangenheit verschoben wurden

Die Modellierungsergebnisse zeigen eine gute Wahrscheinlichkeit, dass die Preise, die in den ersten 10-12 Einheiten generiert wurden, den in Echtzeit beobachteten Werten entsprechen. Außerdem ist interessanterweise nur wenig Arbeit von den Händlern erforderlich, um das Modell aufzubauen. Für das Modell sind zwei Parameter erforderlich — Segmentlänge und Saisonalität, die durch einen sukzessiven Suchlauf auf den neuesten Verlaufsdaten ausgewählt werden können. Der Rest der berechneten Last geht an MATLAB. In Zukunft ist es möglich, die optimale Auswahl der Parameter für die Segmentlänge und den Saisonalitätszeitraum zur Verbesserung des Indikators zu berücksichtigen.

Schlussfolgerungen

Der Artikel zeigte den gesamten Softwareentwicklungszyklus mit 64-Bit-Versionen von MQL5 und MATLAB 2018 Paketen. Zusätzlich wurde die Verwendung von Visual C++ 2017 (x64) zur Erstellung eines Adapters gezeigt, der die Datenübersetzung zwischen MQL5 (mit im C/C++-Stil organisiertem Speicher) und MATLAB (mit in Matrixform organisiertem Speicher) ermöglicht. 

Der vorgestellte Indikator mit Vorhersage auf Basis des SARIMA-Modells und des Kalman-Filters dient der Demonstration der Einsatzmöglichkeiten von MATLAB in ökonometrischen Anwendungen. Es hat großes Potenzial für die weitere Entwicklung, vorausgesetzt, eine MATLAB-basierte Verarbeitung der gewonnenen Daten und die automatisierte Erkennung der saisonalen Komponenten, um das funktionierende Vorhersagemodell zu optimieren. 

Der als Beispiel betrachtete Indikator veranschaulichte den Einsatz von MATLAB — dem Paket, das eine schnelle und effiziente Integration von MetaTrader-Systemen mit neuronalen Netzen, Fuzzy-Logik-Algorithmen sowie anderen komplexen und modernen Methoden zur Verarbeitung von Aktiennotierungen ermöglicht.

Das angehängte Archiv (MatlabSArima.zip) enthält das Verzeichnis MatlabSArima\LibSARIMA\for_redistribution, was das Herunterladen der MATLAB Runtime aus dem Internet beinhaltet. Um die Informationsmenge in der MATLAB Runtime für den SARIMA-Indikator zu reduzieren, ist es notwendig, einen Satz von 10 Dateien herunterzuladen, dann zu entpacken und mit Hilfe des Total Commanders zu kombinieren.

Datei Pfad zum Herunterladen
sarima_plusMCR00.zip 89.16 MB https://pinapfile.com/aKrU7 
sarima_plusMCR01.zip 94.75 MB https://pinapfile.com/fvZNS 
sarima_plusMCR02.zip 94.76 MB https://pinapfile.com/k7wB5 
sarima_plusMCR03.zip 94.76 MB https://pinapfile.com/jwehs 
sarima_plusMCR04.zip 94.76 MB https://pinapfile.com/dv8vK 
sarima_plusMCR05.zip 94.76 MB https://pinapfile.com/hueKe 
sarima_plusMCR06.zip 94.76 MB https://pinapfile.com/c4qzo 
sarima_plusMCR07.zip 94.76 MB https://pinapfile.com/eeCkr 
sarima_plusMCR08.zip 94.76 MB https://pinapfile.com/jDKTS 
sarima_plusMCR09.zip 94.76 MB https://pinapfile.com/dZDJM 


Übersetzt aus dem Russischen von MetaQuotes Software Corp.
Originalartikel: https://www.mql5.com/ru/articles/5572

Beigefügte Dateien |
MatlabSArima.zip (15634.48 KB)
AdapterSARIMA.zip (3244.29 KB)
ISArimaForecast.mq5 (15.72 KB)
Letzte Kommentare | Zur Diskussion im Händlerforum (1)
Christian
Christian | 24 Mai 2019 in 17:48

Wenn das jemand erfolgreich ausprobiert hat bitte um Meldung bei mir.

Der Autor reagiert leider im englischen Artikel nicht. Und eine Kommunikation mit dem Transer ist nicht leicht.

Bibliothek für ein leichtes und schnelles Entwickeln vom Programmen für den MetaTrader (Teil III). Erhebung (Collection) von Marktorders und Positionen Bibliothek für ein leichtes und schnelles Entwickeln vom Programmen für den MetaTrader (Teil III). Erhebung (Collection) von Marktorders und Positionen

Im ersten Teil begannen wir mit der Erstellung einer großen plattformübergreifenden Bibliothek, die die Entwicklung von Programmen für MetaTrader 5 und MetaTrader 4 Plattformen vereinfacht. Danach haben wir die Collection (Sammlung bzw. Liste) von historischen Aufträgen und Deals implementiert. Unser nächster Schritt ist das Erstellen einer Klasse für eine komfortable Auswahl und Sortierung von Aufträgen, Deals und Positionen in Collections. Wir werden das Basis-Bibliotheksobjekt Engine implementieren und der Bibliothek die Collection von Marktorders und Positionen hinzufügen.

Optimale Farben für Handelsstrategien Optimale Farben für Handelsstrategien

In diesem Artikel werden wir ein Experiment durchführen: Wir werden die Optimierungsergebnisse einfärben. Die Farbe wird durch drei Parameter bestimmt: die Werte für Rot, Grün und Blau (RGB). Es gibt noch andere Methoden der Farbcodierung, die ebenfalls drei Parameter verwenden. So können drei Prüfparameter in eine Farbe umgewandelt werden, die die Werte visuell darstellt. Lesen Sie diesen Artikel, um herauszufinden, ob eine solche Darstellung nützlich sein kann.

Entwicklung eines plattformübergreifenden Grid-EAs Entwicklung eines plattformübergreifenden Grid-EAs

In diesem Artikel werden wir lernen, wie man Expert Advisors (EAs) erstellt, die sowohl in MetaTrader 4 als auch in MetaTrader 5 arbeiten. Zu diesem Zweck werden wir ein EA entwickeln, der Auftragsraster (grids) erstellt. Raster-EAs oder Grider sind EAs, die mehrere Limit-Orders über dem aktuellen Preis und gleichzeitig die gleiche Anzahl von Limit-Orders unter ihm platzieren.

MTF-Indikatoren als Werkzeuge der technischen Analyse MTF-Indikatoren als Werkzeuge der technischen Analyse

Die meisten Händler sind sich einig, dass eine Zustandsanalyse des aktuellen Marktes mit der Bewertung höherer Zeitrahmen beginnt. Die Analyse wird nach unten auf niedrigere Zeitrahmen bis zu demjenigen durchgeführt, in dem der Handel durchgeführt wird. Diese Analysemethode scheint ein obligatorischer Bestandteil des professionellen Ansatzes für einen erfolgreichen Handel zu sein. In diesem Artikel werden wir Indikatoren auf mehreren Zeitrahmen (multi-timeframe, MTF) und ihre Erstellungswege diskutieren, sowie Codebeispiele für MQL5 liefern. Neben der allgemeinen Bewertung von Vor- und Nachteilen werden wir einen neuen Indikatoransatz mit dem MTF-Modus vorschlagen.