English 中文 Español Deutsch 日本語 Português
Использование вычислительных возможностей MATLAB 2018 в MetaTrader 5

Использование вычислительных возможностей MATLAB 2018 в MetaTrader 5

MetaTrader 5Примеры | 4 марта 2019, 08:47
4 764 11
Roman Korotchenko
Roman Korotchenko

Введение

Настоящая статья является развитием статьи А. Емельянова "Взаимодействие MetaTrader 5 И MATLAB", предоставляя информацию о решении подобной задачи для современных 64-х разрядных версий всех платформ, применяемых пользователями. За истекший период в пакете MATLAB существенно модернизирован  сам метод создания dll-библиотек совместного использования. Поэтому рассмотренный в исходной статье метод требует модификации. Это произошло потому, что теперь вместо MATLAB Compiler нужно применять MATLAB Compiler SDK или MATLAB Coder. Кроме того, изменилась практика работы с динамической памятью в MATLAB, что предполагает определенные корректировки программного кода, получающего доступ к библиотеке, написанной на языке MATLAB. 

Из названия статьи становится ясным, что данная работа направлена на то, чтобы облегчить разработчикам задачу сопряжения вычислительных возможностей MATLAB с программами, написанными на MQL5. Для этого в работе в качестве примера проводится создание прогностического индикатора на основе модели Seasonal Autoregression Integrated Moving Average (SARIMA) для временного ряда цен, где на MATLAB возложена задача подбора адекватной модели и экстраполирование данных. 

Чтобы продемонстрировать подробности подключения вычислительного потенциала среды MATLAB 2018 к MQL5 в данной статье рассматривается конкретно MATLAB Compiler SDK, а также создание библиотеки-адаптера на Visual C++ для сопряжения MATLAB-библиотеки к MQL5. Это позволяет получить краткое руководство для создания программ, чтобы избегать типичных ошибок, с которыми пришлось столкнуться. 

Простые и сложные типы данных, описанные в 1-й главе статьи А. Емельянова, не изменились, и чтобы не дублировать качественно изложенный материал, желательно ознакомиться с представленным там описанием. Различия начинаются на этапе создания общей С++ библиотеки из среды MATLAB. 

Изложение материала в статье построено по следующей схеме:

  1. На основании подготовленного для индикатора набора MATLAB-модулей формируется C++ Shared Library (dll-библиотека), которая содержит функционал калмановской фильтрации и прогнозирования данных на основе модели Seasonal Autoregression Integrated Moving Average
  2. Затем выполняется подключение расчетного модуля к MQL5-программе. Для этого дополнительно создается библиотека-посредник, которая решает задачу передачи данных между MQL5, с памятью организованной в стиле C/C++, и MATLAB с памятью, организованной в матричной форме.
  3. Описывается модель прогнозирования, заложенная в создаваемый индикатор и демонстрируется его работоспособность.

1. Создание общей библиотеки С++ из функций MATLAB с помощью MATLAB Compiler SDK

В 2015 году произошли изменения в процедуре создания DLL-библиотек в MATLAB. Что касается задачи интеграции с программами на MQL5, суть дела сводится к тому, что MATLAB Compiler больше не предназначен для создания библиотек, а ориентирован на генерацию автономных исполняемых файлов. Функционал создания dll-библиотек с 2015 года передан MATLAB Compiler SDK. MATLAB Compiler SDK расширил функциональные возможности MATLAB Compiler, позволяя создавать общие библиотеки C/C ++, сборки Microsoft.NET и классы Java из программ MATLAB.

Как и прежде, приложения, созданные с использованием программных компонентов из пакета MATLAB Compiler SDK, можно бесплатно распространять среди пользователей, которым не требуется MATLAB. Эти приложения используют MATLAB Runtime и набор общих библиотек, которые используют скомпилированные приложения или компоненты MATLAB.

Задача, которая возлагалась на приложение MATLAB Compiler, был делегирована программе Library Compiler. Для полноты картины рассмотрим процедуру создания C/C++ shared library из среды MATLAB. В zip-архиве, прилагаемом к статье, содержатся файлы с расширением .m, которые использовались для создания библиотеки. На MATLAB (на вкладке APPS) запускается приложение Library Compiler, открывается проект LibSARIMA.prj и организуется структура, подобная изображенной на рисунке.

Рис.1. Интерфейс Library Compiler

Рис.1. Интерфейс Library Compiler.

 

Здесь важно обратить внимание на позиции, выделенные на рис. 1 линиями и цифрами 1-4. 

  1. Создается общая библиотека стандарта С++
  2. Экспортируется функция, представленная в файле ForecastSARIMA.m, при этом другие функции не представлены к экспорту и доступу внешним программам.
  3. Генерируются файлы для линковки в стандартном интерфейсе (matlabsarima.dll, matlabsarima.h, matlabsarima.lib). 
  4. Используется интерфейс доступа к матричной памяти MATLAB посредством структур mwArray.

После нажатия на кнопку «Package» будет выполнена генерация библиотеки. Можно выбрать режим формирования библиотеки с запросом пользователем загрузки пакета MATLAB Engine из интернета, а можно изначально включить необходимые составляющие MATLAB Engine в содержание пакета. 

На этом этапе будет создана библиотека с программой, которая предназначена для фильтрации временного ряда, построения модели SARIMA и прогнозирования. В архиве MatlabSArima.zip предоставлен набор исходников и результат библиотечной сборки.

2. Создание библиотеки-посредника на Microsoft Visual С++

После создания основной библиотеки следующей задачей будет к ней подключиться, передать данные и забрать результаты после расчетов. Речь идет о создании библиотеки-адаптера, обеспечивающего трансляцию данных между MQL5, где память организована в стиле C/C++, и MATLAB с памятью, организованной в матричной форме.

В новых версиях MATLABx64 компилятор Visual C++ является одним из основных, для которого подготовлено все необходимое обеспечение. Поэтому наиболее быстрым, удобным и надежным способом подготовить вспомогательную библиотеку-адаптер является применение именно Visual C++ в Studio 2017.

 

Взаимодействие MetaTrader 5 с MATLAB 2018

Рис. 2. Блок-схема взаимодействия MetaTrader 5 с MATLAB 2018 посредством DLL-адаптера

Важным нововведением в 2017 году для создания и интеграции упакованных функций в приложения C++ стало внедрение в MATLAB таких структур как mwArray API. Произошла модернизация mxArray, который использовались ранее, на новый матричный интерфейс. Имеется еще один вариант интеграции совместно используемой библиотеки — интерфейс MATLAB Data API, но в нашем случае он не имеет значения.

Чтобы приступить непосредственно к программированию адаптера для данных, желательно в операционной системе подготовить и зарегистрировать три системные переменные среды. Это можно, например, сделать с помощью проводника через "свойства компьютера", зайдя в "дополнительные параметры системы" и "переменные среды".

  1. Первая переменная — MATLAB_2018 должна указывать на каталог с установленным MATLAB или MATLAB Runtime; 
  2. Вторая переменная — MATLAB_2018_LIB64 должна указывать на каталог с внешними библиотеками: <MATLAB_2018>\extern\lib\win64;
  3. Третья переменная — MATLIB_USER должна указывать на каталог, куда следует помещать оригинальные библиотеки. Этот каталог нужно также добавить в системную переменную Path, чтобы снять проблему поиска оригинальных библиотек пользователя.  

2.1 Программирование адаптера в Visual Studio 2017

После создания проекта библиотеки динамической компоновки в среде Visual Studio 2017, нужно установить ряд свойств. Чтобы было понятно, какие из них необходимо контролировать, приведем рисунки по которым легко настроить проект на сборку.

Adapter Project Options #0

Рис. 3. Страницы свойств (ABCD, E) где требуется внести изменения 

Adapter SArima Options #1

Рис. 4. Каталоги поиска необходимых файлов для проекта

На рис. 4 в поле, указанное стрелочкой "Каталоги библиотек", добавлен каталог $(MatLib_User). В эту директорию удобно помещать библиотеки общего предназначения, которые нужны и для программирования в Visual C/C++ и для расчетов в MetaTrader 5. В данном случае это matlabsarima.lib и matlabsarima.dll.

Страница макросов

Рис. 5. Установить определения препроцессора


Соглашение о вызовах

Рис. 6. Соглашение о вызовах согласно требованиям MQL5

Дополнительные зависимости (*.lib)

Рис. 7. Указать дополнительные зависимости (*.lib)

Перечислим необходимые изменения в настройках проекта:

  1. Указать каталоги, где располагаются файлы необходимых заголовков;
  2. Указать каталоги, где располагаются файлы необходимых библиотек;
  3. Установить определения препроцессора — макрос, функционал которого будет рассмотрен ниже;
  4. Указать конкретные библиотеки, необходимые для работы (подготовленные MATLAB).

Два сгенерированных с помощью MATLAB файла matlabsarima.lib и matlabsarima.dll нужно поместить в каталог общего доступа, обозначенного в системных переменных $(MATLIB_USER). А файл matlabsarima.h должен быть в директории где собирается проект. Его надо включить в состав "Файлов заголовков" проекта.

Для сборки адаптера останется создать несколько файлов, из которых стоит рассмотреть два.

1. Файл AdapterSArima.h 

#pragma once
#ifdef ADAPTERSARIMA_EXPORTS
#define _DLLAPI extern "C" __declspec(dllexport)  // для создания пары DLL и LIB - библиотек нужно такое определение
#else
#define _DLLAPI extern "C" __declspec(dllimport)  // для привязки 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);

В файле AdapterSArima.h используется макрос, установленный в настройках, чтобы указать, что процедуры  prepareSARIMA(), closeSARIMA() и goSarima(...) доступны для связки с внешними программами

2. Файл 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)
{       //
        // Память для результатов должна быть выделена заблаговременно с учетом прогноза в индикаторе
        // 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;         // окно усреднения MA                                          
                        DoFilter  = (filterOn != 0) ? 1 : 0;
                        TimeHor   = npredict; // точек предсказания
                        SeasonLag = iSeasonPeriod;     // период сезонности для модели SARIMA                   
                        
                        DoPlot = PlotOn;    // рисунок в режиме тестирования

                        nSeries = nLoad;    // фрагмент данных длиной nLoad
                                        
                        mwArray Series(nLoad,1, mxDOUBLE_CLASS, mxREAL);
                        mwArray Result; // результат (отфильтрованные (если задано filterOn!=0)) данные и прогноз
                        
                //      выполним загрузку данных в матрицу MATLAB
                        Series.SetData(&DataSeries[idx0], nLoad); // фрагмент 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;
}

Для полноты картины в zip-архиве представлены все файлы для сборки библиотеки-посредника AdapterSArima.dll. Если будет необходимость, рекомендуется архив распаковать и пересобирать адаптер в директории C:\temp.

3. Создание индикатора

3.1 Постановка задачи и метод решения

Модель авторегрессии и скользящего среднего является исключительно полезной для описания некоторых встречающихся на практике временных рядов. Эта модель соединяет в себе НЧ-фильтр в виде скользящего среднего порядка q и авторегрессию фильтрованных значений процесса порядка p. Если в качестве входных данных использовать не сами значения временного ряда, а их разность d-порядка (на практике d необходимо определять, однако в большинстве случаев d ≤ 2), то модель носит название авторегрессии проинтегрированного скользящего среднего. Подобная модель — ARIMA(p,d,q) (autoregression integrated moving average) позволяет уменьшить влияние нестационарности оригинального ряда.

Для моделирования эффектов долгопериодной изменчивости имеется модификация, которая называется Seasonal ARIMA. Такая модель соответствует временным рядам подверженным воздействию периодических факторов. В биржевых котировках присутствует влияние факторов сезонности, поэтому их учет в  модели подходит для построения прогноза цен в индикаторе. 

Чтобы снизить влияние шумовых факторов в поступающих биржевых котировках желательно предусмотреть возможность дополнительной фильтрации и очистки данных от погрешностей. Чем сильнее зашумлены данные, тем сложнее их обрабатывать. Фильтр Калмана —  эффективный алгоритм рекурсивной фильтрации, используемый в различных областях. Алгоритм состоит из двух повторяющихся фаз: предсказание и корректировка. На первом шаге рассчитывается предсказание состояния в следующий момент времени (с учетом неточности их измерения). Далее, с учетом новой информации, корректируется предсказанное значение (также с учетом неточности и зашумленности этой информации). 

3.2 Программа индикатора на MQL5

Необходимые для индикатора библиотеки AdapterSArima.dll и matlabsarima.dll должны быть помещены в директорию Libraries рабочего каталога MetaTrader 5.

Имеется некоторая специфика отладки и тестирования. В этом режиме MetaEditor запускает библиотеку из вспомогательных каталогов <MetaQuotes\Tester\....\Agent-127.0.0.1-300x>, где 300х принимает значения 3000, 3001, 3002 и т.д. При этом библиотека AdapterSArima.dll копируется автоматически, а matlabsarima.dll - нет. Чтобы это не влияло на работу индикатора, библиотека matlabsarima.dll должна быть в системном каталоге, где проводится поиск. Рекомендовалось обозначить такой каталог через $(MATLIB_USER) и указать в системном списке путей поиска или скопировать в Windows или Windows\System32. Тогда библиотека будет обнаруживаться, подключаться и индикатор запустится. 

Программа индикатора, в котором задействован прогноз по рассмотренной модели, содержится в файле ISArimaForecast.mq5 и прилагаемом архиве.

//+------------------------------------------------------------------+
//|                                              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. Иллюстрация работы индикатора

Работоспособность индикатора была опробована на данных торговли EURUSD H1, предоставленным платформой MetaTrader. Был выбран не слишком большой сегмент данных, размер которого 450 отсчетов, а варианты длиннопериодного "сезонного" лага опробованы 28, 30 и 32 отсчета, лучшим из них на рассмотренном периоде истории был лаг с периодом 32 отсчета.

Выполнялась серия расчетов для разных фрагментов истории. Длина сегмента данных в модели – 450, сезонный лаг 32 и длина прогноза 30 были установлены один раз и не менялись. Чтобы оценить качество прогноза полученные результаты для разных фрагментов сравнивались с фактическими данными.

Приведем рисунки, демонстрирующие результат работы индикатора. На всех рисунках шоколадным цветом отображено завершение фрагмента, по которому в MATLAB была подобрана модель SARIMA(2,1,2), а полученный на ее основании построен прогноз отрисован синим цветом.

EURUSDH1_450(32)-180

Рис. 8. Торговая сессия 30.12.2018. Фильтрация Калмана применяетсяМодель построена по данным со сдвигом в прошлое на 180 отсчетов 


 EURUSDH1_450(32)-170

Рис. 9. Дневная торговая сессия 30.12.2018. Фильтрация Калмана не используется. Модель построена по данным со сдвигом в прошлое на 170 отсчетов 


EURUSDH1_450(32)-140

Рис. 10. Торговая сессия 31.12.2018. Фильтрация Калмана применяется. Модель построена по данным со сдвигом в прошлое на 140 отсчетов 


EURUSDH1_450(32)-120

Рис. 11. Торговая сессия 1.02.2019. Фильтрация Калмана применяется. Модель построена по данным со сдвигом в прошлое на 120 отсчетов 


EURUSDH1_450(32)-100

Рис. 12. Торговая сессия 4.02.2019. Фильтрация Калмана применяется. Модель построена по данным со сдвигом в прошлое на 100 отсчетов 


EURUSDH1_450(32)-50

Рис. 13. Торговая сессия 6.02.2019. Фильтрация Калмана применяется. Модель построена по данным со сдвигом в прошлое на 50 отсчетов 


EURUSDH1_450(32)-20

Рис. 14. Торговая сессия 7.02.2019. Фильтрация Калмана применяется. Модель построена по данным со сдвигом в прошлое на 20 отсчетов 


EURUSDH1_450(32)-10

Рис. 15. Торговая сессия 8.02.2019. Фильтрация Калмана применяется. Модель построена по данным со сдвигом в прошлое на 10 отсчетов 

Результаты моделирования показывают неплохую вероятность совпадения значений спрогнозированных цен в первых 10-12 отсчетах и значений, наблюдавшихся в реальном времени. При чем, что интересно, от трейдера требуется немного труда для настройки модели. Для модели нужны два параметра — длина сегмента и период сезонности, которые можно выбрать методом прогонки на данных ближайшей истории. Остальная расчетная нагрузка достается MATLAB.  В дальнейшем можно рассмотреть оптимальный подбор параметров длины сегмента и период сезонности как направление для модернизации индикатора.

Заключение

В статье был продемонстрирован весь цикл разработки программного обеспечения с применением 64-х разрядных версий пакетов MQL5 и MATLAB 2018. Дополнительно показано применение Visual C++ 2017 (x64) для создания адаптера, обеспечивающего трансляцию данных между MetaTrader, где память организована в стиле C/C++, и MATLAB с памятью, организованной в матричной форме. 

Представленный индикатор с прогнозированием на основе модели SARIMA и фильтра Калмана является демонстрацией возможностей применения MATLAB в эконометрических приложениях. Он имеет большой потенциал для дальнейшего развития, если в MATLAB развить обработку полученных данных и автоматизировать определение сезонных компонент с целью оптимизации рабочей модели для прогнозирования. 

Пример индикатора является иллюстрацией применения MATLAB — пакета, который позволит эффективно и быстро подключить к торговым системам MetaTrader нейросети, алгоритмы нечеткой логики и другие сложные и современные методы обработки биржевых котировок.

В архиве к статье (MatlabSArima.zip) содержится директория MatlabSArima\LibSARIMA\for_redistribution, предполагающая установку из интернет MATLAB Runtime. Если стремиться уменьшить объем MATLAB Runtime информации для индикатора SARIMA, то для этого надо скачать набор из 10-ти файлов, затем их распаковать и объединить с помощью программы Total Commander.

Файл Путь загрузки
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 


Прикрепленные файлы |
MatlabSArima.zip (15641.33 KB)
AdapterSARIMA.ZIP (3250.28 KB)
ISArimaForecast.mq5 (15.72 KB)
Последние комментарии | Перейти к обсуждению на форуме трейдеров (11)
Stanislav Korotky
Stanislav Korotky | 11 мар. 2019 в 14:41
Roman Korotchenko:

Похоже здесь избыточная "перестраховка" для используемого шага времени. Получается, что обработка осуществилась быстрее, чем пришел новый отсчет. Это также возможно указывает на хорошее быстродействие компьютера. Поскольку условие ложно, то оно не оказывает влияния на работу алгоритма. Хуже если бы оно через чур часто было истинным). Я буду заниматься развитием индикатора и "пошевелю" условие, чтобы оно не было столь бессысленным. Спасибо за замечание.

Это предупреждение компилятора, не связанное со скоростью обработки. В условии используются беззнаковые переменные типа uint, они никогда не могут быть < 0. Замените на int, чтобы можно было получить отрицательную разность.

Roman Korotchenko
Roman Korotchenko | 17 мар. 2019 в 11:09
Stanislav Korotky:

Это предупреждение компилятора, не связанное со скоростью обработки. В условии используются беззнаковые переменные типа uint, они никогда не могут быть < 0. Замените на int, чтобы можно было получить отрицательную разность.

Благодарю за подсказку.

Lucas
Lucas | 21 июн. 2019 в 00:12
Как я могу купить, чтобы установить этот индикатор на MT5?
Если кто-нибудь может мне помочь, я ценю это.
Roman Korotchenko
Roman Korotchenko | 27 июн. 2019 в 15:58

Файловый сервер где хранились MATLAB-runtime провел глобальную чистку и удалил файлы. Я обновил загрузку и сейчас они располагаются https://pinapfile.com/qBGE .

Чтобы распаковать используйте программу 7zip. Надо выделить весь набор файлов и «Extract files...».

Lucas
Lucas | 28 июн. 2019 в 20:27
Я правильно установил эти файлы. Затем я попытался сделать процедуры в Visual Studio. Я открыл проект «AdapterSArima.vcxproj» и попытался выполнить. Ниже приведено сообщение об ошибке: «Не удается открыть файл включения:« mclmcrrt.h ': нет такого файла или каталога. »В статье говорится, что необходимо скопировать в каталог, в который присоединяется проект. Можете ли вы помочь мне установить его?

YA pravil'no ustanovil eti fayly. Zatem ya popytalsya sdelat' protsedury v Visual Studio. YA otkryl proyekt «AdapterSArima.vcxproj» i popytalsya vypolnit'. Nizhe privedeno soobshcheniye ob oshibke: «Ne udayetsya otkryt' fayl vklyucheniya:« mclmcrrt.h ': net takogo fayla ili kataloga. »V stat'ye govoritsya, chto neobkhodimo skopirovat' v katalog, v kotoryy prisoyedinyayetsya proyekt. Mozhete li vy pomoch' mne ustanovit' yego?
Библиотека для простого и быстрого создания программ для MetaTrader (Часть II): Коллекция исторических ордеров и сделок Библиотека для простого и быстрого создания программ для MetaTrader (Часть II): Коллекция исторических ордеров и сделок
В первой статье мы начали создавать большую кроссплатформенную библиотеку, целью которой является облегчение создания программ для платформ MetaTrader 5 и MetaTrader 4. Создали абстрактный объект COrder, который является базовым объектом для хранения данных исторических ордеров и сделок, а также рыночных ордеров и позиций. Теперь мы создадим все необходимые объекты для хранения данных истории счёта в коллекциях.
Исследование методов свечного анализа (Часть II): Автопоиск новых паттернов Исследование методов свечного анализа (Часть II): Автопоиск новых паттернов
В предыдущей статье были рассмотрены всего 14 паттернов, но, как известно, существуют и другие свечные модели. И чтобы монотонно не рассматривать всё великое многообразие остальных паттернов, было решено пойти другим путем. Теперь вашему вниманию предлагается система поиска и тестирования новых свечных моделей на основе известных типов свечей.
Создаем кроссплатформенный советник-сеточник (гридер) Создаем кроссплатформенный советник-сеточник (гридер)
В данной статье мы научимся писать советники, которые работают сразу и в MetaTrader 4, и в MetaTrader 5. Для этого мы попробуем написать советник, работающий по принципу создания сетки из ордеров. Сеточники или гридеры — это советники, основной принцип работы которых заключается в одновременном выставлении нескольких лимитных ордеров выше текущей цены, и такого же количества лимитных ордеров ниже текущей цены.
Библиотека для простого и быстрого создания программ для MetaTrader (Часть I): Концепция, организация данных, первые результаты Библиотека для простого и быстрого создания программ для MetaTrader (Часть I): Концепция, организация данных, первые результаты
Разбирая огромное количество торговых стратегий, множество заказов на изготовление программ для терминалов MT5 и MT4, просматривая различные сайты по MetaTrader, я пришёл к выводу, что всё это многообразие в подавляющем своём большинстве строится на фактически одних и тех же элементарных функциях, действиях и значениях, повторяющихся от программы к программе. Результатом моей работы стала кроссплатформенная библиотека "DoEasy" для быстрого и лёгкого создания программ для МetaТrader 5 и МetaТrader 4