English Русский 中文 Deutsch 日本語 Português
Usando los recursos computacionales de MATLAB 2018 en MetaTrader 5

Usando los recursos computacionales de MATLAB 2018 en MetaTrader 5

MetaTrader 5Ejemplos | 21 mayo 2019, 15:20
1 407 0
Roman Korotchenko
Roman Korotchenko

Introducción

El presente artículo supone un desarrollo del artículo de А. Emelyanov Interacción entre MetaTrader 4 y MATLAB Engine (Máquina virtual MATLAB), y ofrece información sobre la solución a una tarea semejante para versiones modernas de 64 bits de todas las plataformas utilizadas por los usuarios. Durante la existencia del paquete MATLAB, se ha modernizado sustancialmente el propio método de creación de bibliotecas dll de uso común. Por eso, el método analizado en el artículo original requiere de modificaciones. Esto ha sucedido así porque ahora, en lugar de MATLAB Compiler, debemos usar MATLAB Compiler SDK o MATLAB Coder. Además, ha cambiado la forma de trabajar con la memoria dinámica en MATLAB, lo cual presupone determinadas correcciones del código programático que obtiene acceso a la biblioteca escrita en el lenguaje MATLAB. 

Por el nombre del artículo, podemos entender que este trabajo tiene la intención de facilitar a los desarrolladores la tarea de vincular los recursos computacionales de MATLAB con los programas escritos en MQL5. Para ello, tomaremos como ejemplo la creación de un indicador de pronóstico basado en el modelo Seasonal Autoregression Integrated Moving Average (SARIMA) para la serie temporal de precios, donde MATLAB tiene la tarea de seleccionar un modelo adecuado y extrapolar los datos. 

Para mostrar los detalles de la combinación de los recursos computacionales del entorno MATLAB 2018 con MQL5, en este artículo analizaremos en concreto MATLAB Compiler SDK, así como la creación de la biblioteca-adaptador Visual C++ para vincular la biblioteca MATLAB con MQL5. Esto nos permitirá obtener una breve guía de creación de programas para evitar los típicos errores con los que hemos topado. 

Los tipos de datos simples y complejos, descritos en el primer capítulo del artículo de А. Emilyanov, no han cambiado, y para no duplicar un material ya expuesto, sería deseable familiarizarse con la descripción ofrecida en dicho epígrafe. Las diferencias comienzan en la etapa de creación de la biblioteca С++ general del entorno MATLAB. 

La exposición del material en el artículo se ha construido de la forma siguiente:

  1. Usando como base un conjunto de módulos MATLAB preparado para el indicador, se forma una C++ Shared Library (biblioteca dll) que contiene la funcionalidad del filtrado de Kalman y el pronóstico de datos basado en el modelo Seasonal Autoregression Integrated Moving Average
  2. A continuación, se ejecuta la conexión del módulo de cálculos al programa MQL5. Para ello, se crea adicionalmente una biblioteca intermediaria que soluciona la tarea de la transmisión de datos entre MQL5, (con la memoria organizada en el estilo C/C++), y MATLAB (con la memoria organizada en forma de matriz).
  3. Se describe el modelo de pronóstico implementado en el indicador creado y se muestra su rendimiento.

1. Creando un biblioteca compartida С++ a partir de funciones MATLAB con la ayuda de MATLAB Compiler SDK

En 2015, tuvieron lugar varios cambios en el proceso creativo de las bibliotecas DLL en MATLAB. En lo que respecta a la tarea de la integración con programas en MQL5, la esencia se resume en que MATLAB Compiler ya no está enfocado en la creación de bibliotecas, sino que está orientado a la generación de archivos ejecutables autónomos. La funcionalidad de la creación de bibliotecas dll desde 2015 se ha transmitido a MATLAB Compiler SDK. MATLAB Compiler SDK ha ampliado las posibilidades funcionales de MATLAB Compiler, permitiendo crear las bibliotecas compartidas C/C ++, assemblies Microsoft.NET y las clases Java de programas MATLAB.

Como sucedía anteriormente, las aplicaciones creadas usando componentes programáticos del paquete MATLAB Compiler SDK se pueden distribuir gratuitamente entre los usuarios que no requieren de MATLAB. Estas aplicaciones usan MATLAB Runtime y un conjunto de bibliotecas compartidas que utilizan aplicaciones compiladas o componentes de MATLAB.

La tarea que antes se asignaba a MATLAB Compiler, ha sido delegada en Library Compiler. Para completar el cuadro, analizaremos el proceso creativo de C/C++ shared library del entorno MATLAB. En el fichero zip adjunto al artículo, están los archivos con la extensión .m que se han utilizado para crear la biblioteca. En MATLAB (en la pestaña APPS) se inicia la aplicación Library Compiler, se abre el poryecto LibSARIMA.prj y se organiza una estructura semejante a la representada en la imagen.

Fig.1. Interfaz de Library Compiler

Fig.1. Interfaz de Library Compiler.

 

Aquí, es importante prestar atención a las posiciones destacadas en la fig. 1 con las líneas y los números 1-4. 

  1. Se crea una biblioteca compartida del estándar С++
  2. Se exporta la función representada en el archivo ForecastSARIMA.m, en este caso, además, las otras funciones no están designadas para la exportación y el acceso por parte de programas externos.
  3. Se generan los archivos para la vinculación en la interfaz estándar (matlabsarima.dll, matlabsarima.h, matlabsarima.lib). 
  4. Se usa la ineterfaz de acceso a la memoria matriz MATLAB a través de las estructuras mwArray.

Después de pulsar el botón «Package», se generará la biblioteca. Podemos seleccionar el modo de formación de la biblioteca solicitado por el propio usuario para descargar el paquete MATLAB Engine de internet, o podemos incluir inicialmente los componentes necesarios de MATLAB Engine en paquete. 

En esta etapa, se creará una biblioteca que contiene un programa pensado para filtrar la serie temporal, construir el modelo SARIMA y realizar los pronósticos. El fichero MatlabSArima.zip contiene un conjunto de códigos fuente y el resultado del ensamblaje de la biblioteca.

2. Creando una biblioteca intermediaria en Microsoft Visual С++

Después de crear la biblioteca principal, la siguiente tarea consistirá en conectarse a ella, transmitir los datos y recoger los resultados de los cálculos. Estamos hablando de la creación de una biblioteca-adaptador que posibilite la transmisión de datos entre MQL5, cuya memoria está organizada en el estilo C/C++, y MATLAB, que posee una memoria organizada en forma de matriz.

En las nuevas versiones de MATLABx64, el compilador Visual C++ es uno de los principales, por lo que se ha preparado para el mismo todo el software necesario. Así, el método más rápido, cómodo y seguro para preparar la biblioteca-adaptador auxiliar es el uso precisamente de Visual C++ en Studio 2017.

 

Interacción de MetaTrader 5 con MATLAB 2018

Fig. 2. Esquema de bloques de la interacción de MetaTrader 5 con MATLAB 2018 a través de un adaptador DLL

Una novedad importante en 2017 en cuanto a la creación e integración de funciones empaquetadas en aplicaciones C++ ha sido la implementación en MATLAB de estructuras como mwArray API. mxArray, utilizada anteriormente, se ha modernizado a una nueva interfaz de matriz. Existe otra variante de integración de forma conjunta con la biblioteca utlizada, la interfaz MATLAB Data API, pero en nuestro caso no importa.

Para proceder directamente a la programación del adaptador para datos, sería deseable preparar y registrar tres variables de entorno de sistema en el sistema operativo. Esto se puede hacer, por ejemplo, con la ayuda del explorador de archivos, a través de la "propiedades de la computadora", entrando en "parámetros adicionales del sistema" y "variables de entorno".

  1. La primera variable, MATLAB_2018 , deberá indicar el catálogo con MATLAB o MATLAB Runtime instalado; 
  2. La segunda variable, MATLAB_2018_LIB64, deberá indicar el catálogo con bibliotecas externas: <MATLAB_2018>\extern\lib\win64;
  3. La tercera variable, MATLIB_USER, deberá indicar el catálogo donde debemos ubicar las bibliotecas originales. Este catálogo se debe añadir igualmente a la variable de sistema Path, para resolver el problema derivado de la búsqueda de las bibliotecas originales del usuario.  

2.1 Programando el adaptador en Visual Studio 2017

Después de crear el proyecto de la biblioteca de enlace dinámico en el entorno Visual Studio 2017, debemos establecer una serie de propiedades. Para que podamos entender cuáles de ellas debemos controlar, vamos a mostrar varias figuras que nos permitirán configurar el proyecto de montaje.

Adapter Project Options #0

Fig. 3. Páginas de propiedades (ABCD, E) donde se deben introducir los cambios 

Adapter SArima Options #1

Fig. 4. Catálogos de búsqueda de los archivos necesarios para el proyecto

En la fig. 4, en el campo indicado con la flecha "Catálogos de las bibliotecas", se ha añadido el catálogo $(MatLib_User). En este directorio, resulta cómodo ubicar las bibliotecas de uso general, que son también necesarias para programar en Visual C/C++ y realizar los cálculos en MetaTrader 5. En nuestro caso, se trata de matlabsarima.lib y matlabsarima.dll.

Página de macros

Fig. 5. Estableciendo las definiciones del preprocesador


Convención de llamada

Fig. 6. Convención de llamada de acuerdo con los requisitos de MQL5

Dependencias adicionales (*.lib)

Fig. 7. Indicando las dependencias adicionales (*.lib)

Vamos a enumerar los cambios necesarios en los ajustes del proyecto:

  1. Indicar los catálogos donde se ubican los archivos de los encabezados necesarios;
  2. Indicar los catálogos donde se ubican los archivos de las bibliotecas necesarias;
  3. Establecer las definiciones del preprocesador: la macro cuya funcionalidad se analizará abajo;
  4. Indicar las bibliotecas concretas necesarias para el trabajo (preparadas para MATLAB).

Los dos archivos generados con la ayuda de MATLAB, matlabsarima.lib y matlabsarima.dll, se deben ubicar en el catálogo de acceso compartido, designado por las variables de sistema $(MATLIB_USER). El archivo matlabsarima.h, a su vez, debe colocarse en el directorio donde se reúne el proyecto. Hay que incluirlo en los "archivos de encabezado" del proyecto.

Para montar el adaptador, solo nos quedará crear varios archivos, entre los cuales merece la pena destacar dos.

1. Archivo AdapterSArima.h 

#pragma once
#ifdef ADAPTERSARIMA_EXPORTS
#define _DLLAPI extern "C" __declspec(dllexport)  // esta definición es necesaria para emparejar bibliotecas DLL y LIB
#else
#define _DLLAPI extern "C" __declspec(dllimport)  // esta definición es necesaria para vincular bibliotecas DLL
#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);

En el archivo AdapterSArima.h se usa la macro establecida en los ajustes, para indicar que los procesos  prepareSARIMA(), closeSARIMA() y goSarima(...) están disponibles para la vinculación con los parámetros externos

2. Archivo 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)
{
        // Call the application and library termination routine 
        //if (SArimaStarted)
        {
                matlabsarimaTerminate();
                SArimaStarted = false;
        }
}
//-----------------------------------------------------------------------------------

_DLLAPI int goSarima(double *Res, double *DataSeries, int idx0, int nLoad, int iSeasonPeriod, int npredict, int filterOn, int PlotOn)
{       //
        // La memoria para los resultados deberá ser asignada por anticipado, teniendo en cuenta el pronósitico en el indicador
        // Memory for Res[] must be allocated. 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;         // ventana de media MA                                          
                        DoFilter  = (filterOn != 0) ? 1 : 0;
                        TimeHor   = npredict; // puntos de predicción
                        SeasonLag = iSeasonPeriod;     // periodo de estacionalidad para el modelo SARIMA                   
                        
                        DoPlot = PlotOn;    // dibujo en el modo de simulación

                        nSeries = nLoad;    // fragmento de datos de longitud nLoad
                                        
                        mwArray Series(nLoad,1, mxDOUBLE_CLASS, mxREAL);
                        mwArray Result; // resultado (datos filtrados (si se ha establecido filterOn!=0)) y pronóstico
                        
                //      cargamos los datos en la matriz MATLAB
                        Series.SetData(&DataSeries[idx0], nLoad); // fragmento 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;
}

Para completar, en el archivo zip se muestran todos los archivos para montar la biblioteca intermediaria AdapterSArima.dll. Si es necesario, se recomienda desempacar el archivo y reconstruir el adaptador en el directorio C:\temp.

3. Creando el indicador

3.1 Formulando la tarea y el método de solución

El modelo autorregresivo y la media móvil son extremadamente útiles para describir algunas series temporales que se encuentran en la práctica. Este modelo aúna un filtro paso bajo en forma de media mívil del orden q y autorregresión de los valores filtrados del proceso de orden p. Si usamos como datos de entrada no los propios valores de la serie temporal, sino su diferencia de orden d (en la práctica, d se debe determinar, sin embargo, en la mayoría de los casos, d ≤ 2), el modelo lleva el nombre de autorregresión de la media móvil integrada. Un modelo semejantes, ARIMA(p,d,q) (autoregression integrated moving average), permite reducir la influencia de la no estacionalidad de la serie original.

Para modelar los efectos de la variabilidad a largo plazo, existe una modificación, llamada Seasonal ARIMA. Este modelo se corresponde con las series temporales sometidas a la influencia de factores periódicos. En las cotizaciones bursátiles existe la influencia de los factores de estacionalidad, por eso, su registro en el modelo es adecuado para construir el pronóstico de precios en el indicador. 

Para reducir la influencia de los factores relacionados con el ruido en las cotizaciones bursátiles entrantes, sería deseable prever la posibilidad de filtrar los datos de manera adicional y depurarlos de errores. Cuanto mayor sea el ruido en los datos, más complicado será procesarlos. El filtro de Kalman es un algoritmo efectivo de filtrado recursivo, utilizado en diferentes esferas. El algoritmo consta de dos fases que se repiten: la predicción y la corrección. En el primer paso, se calcula la predicción del estado en el siguente momento temporal (teniendo en cuenta la imprecisión de su medición). A continuación, y considerando la nueva información, se corrige el valor predicho (teniendo igualmente en cuenta la imprecisión y el ruido de esta información). 

3.2 Programa del indicador en MQL5

Las bibliotecas AdapterSArima.dll y matlabsarima.dll, imprescindibles para el indicador, deberán ubicarse en el directorio Libraries del catálogo de trabajo de MetaTrader 5.

Existe alguna especificidad de depuración y simulación. En este modo, el MetaEditor inicia una biblioteca desde los catálogos auxiliares <MetaQuotes\Tester\....\Agent-127.0.0.1-300x>, donde 300х adopta los valores 3000, 3001, 3002, etcétera. Además, la biblioteca AdapterSArima.dll se copia automáticamente, mientras que matlabsarima.dll no lo hace. Para que ello no influya en el funcionamiento del indicador, la biblioteca matlabsarima.dll deberá encontrarse en el catálogo del sistema. Se recomendó designar el catálogo como $(MATLIB_USER) e indicar en la lista de sistema las rutas de búsqueda o copiar en Windows o Windows\System32. Entonces, la biblioteca será detectada, se conectará y el indicador se iniciará. 

El programa del indicador en el que se utiliza el pronóstico según el modelo analizado, está contenido en el archivo ISArimaForecast.mq5, así como en el fichero adjunto.

//+------------------------------------------------------------------+
//|                                              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    //---- Buffers for calculating and drawing the indicator
#property indicator_plots   1    //---- graphic constructions
#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
  };
//--- input parameters
input ENUM_TIMERECALC RefreshPeriod=TimeRecalc30;         // Recalculate period
input int      SegmentLength  = 450; // N: Data fragment
input int      BackwardShift  = 0;   // Backward shift (testing)
input int      ForecastPoints = 25;  // Point to forecast
input int      SeasonLag=32;         // Season lag of SARIMA(2,1,2)
input bool     DoFilter=true;        // Do Kalman filtering of Data Series

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

//--- indicator buffers
double   DataBuffer[],ColorBuffer[];
//double   LastTrend[],LastData[];

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

uint CalcCounter;
//
uint calc_data;
uint start_data;    // Start time to build the chart
uint now_data;      // Current time

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

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
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;
//--- indicator buffers mapping
   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);      //for Expert
// SetIndexBuffer(3,LastData,    INDICATOR_CALCULATIONS);   ArraySetAsSeries(LastData,true);       //for Expert

   PlotIndexSetInteger(0,PLOT_SHIFT,ForecastPoints-BackwardShift);

   wRKLength = ForecastPoints+ SegmentLength; // The number of elements in the array with the results
   ArrayResize(wrkResult,wRKLength,0);        // Allocates memory for function results
   ArrayResize(wrkSegment,SegmentLength,0);   // Allocates memory for input data.

//---   
   string shortname;
   StringConcatenate(shortname,"SARIMA(2,1,2). Season Lag: ",SeasonLag,"  // ");
//--- The label to display in DataWindow
   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; // Auxiliary drawing, executed by MATLAB (for testing)

   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const int begin,
                const double &price[]
                )
  {
//---
   int ShiftIdx=rates_total-SegmentLength-BackwardShift; // The starting index for the work segment data 

   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) // calculation is not needed or not completed
     {
      // ReloadBuffers(prev_calculated,rates_total);
      return(prev_calculated);
     }
   if(prev_calculated!=0 && !IsCalcFinished)
     {
      return(prev_calculated);  // New data comes faster than current calculation finished 
     }
//---------------------------------------------------------------------------     

   IsCalcFinished=false; // Block the request a new calculation until the current one is executed

   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; // Ready to make new calculation 

   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. Demostración del funcionamiento del indicador

La eficiencia del indicador se ha puesto a prueba con los datos comerciales de EURUSD H1 proporcionados por la plataforma MetaTrader. Se he elegido un intervalo de datos no demasiado grande, con un tamaño de 450 unidades, mientras que las variantes de atraso "estacional" han sido simuladas con 28, 30 y 32 unidades. El atraso con 32 unidades se ha mostrado como el mejor en el periodo de historia considerado.

Se ha realizado una serie de cálculos para distintos fragmentos de historia. La longitud del segmento en el modelo (450), el atraso estacional (32) y la longitud del pronóstico (30) se han establecido una vez y no han cambiado. Para valorar la calidad del pronóstico, los valores obtenidos para diferentes fragmentos se han comparado con los datos reales.

Vamos a mostrar varias figuras que ilustran el funcionamiento del indicador. En todas las figuras, se representa en color chocolate la conclusión del fragemento usado para elegir el modelo SARIMA(2,1,2) en MATLAB, mientras que el resultado obtenido sobre su base, se muestra en azul.

EURUSDH1_450(32)-180

Fig. 8. Sesión comercial del 30.12.2018. Filtrado de Kalman aplicadoEl modelo se ha construido según los datos con un desplazamiento en el pasado de 180 unidades 


 EURUSDH1_450(32)-170

Fig. 9. Sesión comercial diaria del 30.12.2018. Filtrado de Kalman no aplicado. El modelo se ha construido según los datos con un desplazamiento en el pasado de 170 unidades 


EURUSDH1_450(32)-140

Fig. 10. Sesión comercial del 30.12.2018. Filtrado de Kalman aplicado. El modelo se ha construido según los datos con un desplazamiento en el pasado de 140 unidades 


EURUSDH1_450(32)-120

Fig. 11. Sesión comercial del 1.02.2019. Filtrado de Kalman aplicado. El modelo se ha construido según los datos con un desplazamiento en el pasado de 120 unidades 


EURUSDH1_450(32)-100

Fig. 12. Sesión comercial del 4.02.2019. Filtrado de Kalman aplicado. El modelo se ha construido según los datos con un desplazamiento en el pasado de 100 unidades 


EURUSDH1_450(32)-50

Fig. 13. Sesión comercial del 6.02.2019. Filtrado de Kalman aplicado. El modelo se ha construido según los datos con un desplazamiento en el pasado de 50 unidades 


EURUSDH1_450(32)-20

Fig. 14. Sesión comercial del 7.02.2019. Filtrado de Kalman aplicado. El modelo se ha construido según los datos con un desplazamiento en el pasado de 20 unidades 


EURUSDH1_450(32)-10

Fig. 15. Sesión comercial del 8.02.2019. Filtrado de Kalman aplicado. El modelo se ha construido según los datos con un desplazamiento en el pasado de 10 unidades  

Los resultados del modelado muestran una buena probabilidad de coincidencia entre los valores de los precios pronosticados en las primeras 10-12 unidades, y los valores observados en tiempo real. Además, resulta interesante que no se requiera mucho trabajo de configuración del modelo por parte del tráder. El modelo necesita dos parámetros: la longitud del segmento y el periodo de estacionalidad, que se pueden seleccionar por el método del barrido en los datos históricos más recientes. El resto de la carga computacional corre a cargo de MATLAB.  En lo sucesivo, podemos analizar la selección óptima de los parámetros de longitud del segmento y el periodo de estacionalidad como una variante de modernización del indicador.

Conclusión

En el artículo se ha mostrado el ciclo completo de desarrollo de sofware usando las versiones de 64 bits de los paquetes MQL5 y MATLAB 2018. De manera adicional, se ha mostrado el uso de Visual C++ 2017 (x64) para crear un adaptador que posibilite la transmisión de datos entre MQL5, cuya memoria está organizada en el estilo C/C++, y MATLAB, que posee una memoria organizada en forma de matriz. 

El indicador presentado, con pronóstico basado en el modelo SARIMA y el filtro de Kalman, demuestra las posibilidades de uso de MATLAB en las aplicaciones econométricas. Posee un gran potencial para el desarrollo posterior, si se mejora en MATLAB el procesamiento de los datos obtenidos y se automatiza la determinación del componente estacional con el objetido de optimizar el modelo de trabajo para el pronóstico. 

Un ejemplo del indicador es la demostración del uso de MATLAB, un paquete que permite conectar de forma rápida y efectiva a los sistemas de MetaTrader redes neuronales, algoritmos de lógica difusa y otros métodos complejos y modernos de procesamiento de cotizaciones bursátiles.

El fichero adjunto al artículo (MatlabSArima.zip) contiene el directorio MatlabSArima\LibSARIMA\for_redistribution, que presupone la instalación de MATLAB Runtime desde internet. Si pretendemos reducir el volumen de información de MATLAB Runtime para el indicador SARIMA, deberemos descargar un conjunto de 10 archivos, desempacarlos y combinarlos con la ayuda del programa Total Commander.

Archivo Ruta para la descarga
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 


Traducción del ruso hecha por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/ru/articles/5572

Archivos adjuntos |
MatlabSArima.zip (15634.48 KB)
AdapterSARIMA.zip (3244.29 KB)
ISArimaForecast.mq5 (15.72 KB)
Biblioteca para el desarrollo rápido y sencillo de programas para MetaTrader (Parte II): Colección de órdenes y transacciones históricas Biblioteca para el desarrollo rápido y sencillo de programas para MetaTrader (Parte II): Colección de órdenes y transacciones históricas
En el primer artículo, comenzamos a crear una gran biblioteca multiplataforma, cuyo cometido es facilitar la creación de programas para las plataformas MetaTrader 5 y MetaTrader 4. Creamos el objeto abstracto COrder, que es el objeto básico para guardar los datos de las órdenes y transacciones históricas, así como de las órdenes y posiciones de mercado. Ahora, vamos a crear todos los objetos necesarios para guardar los datos de la historia de la cuenta en colecciones.
Estudio de técnicas de análisis de velas (Parte II): Búsqueda automática de patrones nuevos Estudio de técnicas de análisis de velas (Parte II): Búsqueda automática de patrones nuevos
En el anterior artículo, analizamos un total de 14 patrones, pero, como ya sabemos, existen otros modelos de velas. Y, para no sumergirnos en una revisión monótona de la enorme variedad de patrones restantes, hemos decidido tomar otro camino. En esta ocasión, ofrecemos al lector un sistema de búsqueda y prueba de nuevos modelos de velas basados en tipos de vela conocidos.
Desarrollando las interfaces gráficas para los Asesores Expertos e indicadores a base de .Net Framework и C# Desarrollando las interfaces gráficas para los Asesores Expertos e indicadores a base de .Net Framework и C#
Presentamos una manera simple y rápida de crear las ventanas gráficas usando el editor Visual Studio, con la integración posterior en el código MQL del Asesor Experto. Este artículo está destinado para un vasto círculo de lectores y no requiere ningunos conocimientos de C# y tecnología .Net.
Análisis sintáctico de MQL usando las herramientas de MQL Análisis sintáctico de MQL usando las herramientas de MQL
El presente artículo describe el preprocesador, escáner y el parser (analizador sintáctico) para el análisis sintáctico de los códigos fuente en el lenguaje MQL. La implementación en MQL se adjunta.