下载MetaTrader 5

MеtaTrader 4 和 MATLAB Engine 的交互(虚拟 MATLAB 机)

12 四月 2016, 13:27
Andrey Emelyanov
0
3 595

简介

MetaTrader 4 和 MATLAB 数学包由于其良好的特性(包括在创建复杂计算系统中的“灵活性”),非常受用户的欢迎。 MATLAB 跟外部应用程序连接有三种主要方式,但我只推荐其中的一种 - 使用虚拟桌面 MATLAB Engine。 这种方法保证跟完整的 MATLAB 包完全兼容。 很多程序员出于以下原因回避这种方法:

  • 很多用户发现它较慢。 如果跟从 MATLAB 的 DLL 库直接调用函数相比,的确比较慢。 主要延迟发生在调用虚拟机的操作开始时,因为调用大量的库,需要将其上传到调用过程的虚拟空间(本例中是 MetaTrader 4)。
  • 项目的可转移性 这种问题的确存在,当把项目转移到另一台计算机时(以及使用直接调用时),所有的 MATLAB DLL 库也必须转移,以了解后者(即启动队列)之间的“关系”。
  • 必须了解 C++ 或 Fortran。 不过,如果你了解 MQL4,就可以轻松学习 C++,反之亦然。

我推荐这种方法的原因:

  1. 这是跟外部程序连接的方法中最可靠和不受 MATLAB 版本影响的一个。 你可以更改 MATLAB 的版本,而你的指标或 Expert Advisor 根本不会注意到这点。 这是最重要的优势。
  2. 它具有相对快速的开发方法。 不需要调试程序,并且编写 DLL 包装程序也不困难。
  3. 多个指标和/或 Expert Advisor 的“普通桌面”。 当我们需要基于多个指标的数据进行决策或在实现金字塔交易时,我认为这种方法非常有用。

本文描述了连接 MetaTrader 4 和 MATLAB(ver.7.4.0(R2007a))的方法, 通过在 Borland C++ Builder 6 编写的“DLL 包装程序”来实现。 喜欢 Microsoft 产品的程序员必须使示例适应他们的编译器(考虑到任务的复杂性,祝你好运!)



I.设定任务

首先,需要确定从哪里着手启动项目。 我们将开发过程分为三部分:

  1. 开发 MATLAB 中实现指标/EA 计算的 M-函数。
  2. 开发连接 MATLAB 和 MetaTrader 4 的“DLL-包装程序”。
  3. 开发 MQL 程序。


II. 开发 M-函数

这可能是最有趣和运行时间较长的过程,包含以下操作:

1. 将数据从 MetaTrader 4 预导出到 MATLAB。

上图显示了手动将数据导出到 MATLAB 的过程。 当导出结束时,在 MATLAB 桌面将创建变量。

2. 查找正确的公式、公式参数的范围等等。

该过程很有创造性,也很重要,但指标和/或 Expert Advisor 的数学算法开发并非本文讨论的内容。 你可以在关于 MATLAB 的文献中找到相关信息。

3. MATLAB 中的 M-函数创建

了解 C++和/或 MQL4 的程序员在创建该函数时都没有困难 - 另外,所有的变量都具有相同的数据类型 - “矩阵”。 也就是说,清晰的定义一个变量为数组还是多维数组并不重要 - 语言自己会完成定义。 我认为数据类型的选择过程并不重要。 我始终使用 mxREAL。 虽然使用了更多的内存,但却没有造成任何困惑。 更多详情可见于参考文献 1 和 2。 在给出的示例中,使用了高频过滤器。



III. 开发“DLL-包装程序”

我们对这一点进行详细的阐述,因为它就像空气之于人一样重要。 每个后期绑定的 DLL 库必须符合以下条件:

  • 必须具有用于运行后进行“废品”收集和清除内存的内部函数。
  • 必须支持多线程,即同时支持超过一个线程的运行。
  • 必须位于一定的目录下,请参阅:项目文件的位置。

“DLL-包装程序”的主要外部函数是 MATLAB Engine 的 API 界面和标准 C++ 输入/输出库的一个函数。 MATLAB Engine MATLAB Engine ,只包含 8 个函数:

Engine *pEng = engOpen(NULL) – 调用 MATLAB 桌面的函数,该参数始终为 NULL,返回指针到桌面描述符,它对于其他函数的运行是不可缺少的,变量被设定为全局变量。

int exitCode = engClose(Engine *pEng) – 关闭桌面的函数,到桌面描述符的 pEng 指针,返回一个不重要的值,因为该函数在 DLL 关闭时调用且并不重要,返回 MATLAB 桌面“用户”的数量。

mxArray *mxVector = mxCreateDoubleMatrix(int m, int n, int ComplexFlag) – 为 MATLAB 桌面创建矩阵的函数,返回指针到变量矩阵。 需要创建跟 MATLAB 兼容的变量。 一般的数据数组和/或简单的数据类型无法发送到 MATLAB!

mxArray *mxVector – 指向变量矩阵的指针;

int m – 行数;

int m – 列数;

ComplexFlag – 复数类型,为了 MetaTrader 4 的正确运行,始终使用 mxREAL。

void = mxDestroyArray(mxArray *mxVector) – 擦除 MATLAB 矩阵的函数,为清除内存所需。 经常删除不再需要的数据,否则会出现内存问题或结果的“重叠”。

mxArray *mxVector – 指向变量矩阵的指针;

int = engPutVariable( Engine *pEng, char *Name, mxArray *mxVector) – 发送变量到桌面的函数。 不能只是创建 mxArray 类型的变量,而且要发送到 MATLAB。

Engine *pEng – 指向桌面“描述符”的指针;

char *Name – 在 MATLAB 桌面的变量名称,char 类型;

mxArray *mxVector – 指向变量矩阵的指针;

mxArray *mxVector = engGetVariable(Engine *pEng, char *Name) – 从桌面接受变量的函数,是上一个函数的逆函数。 可以接收 mxArray 类型的变量。

mxArray *mxVector – 指向变量矩阵的指针;

Engine *pEng – 指向桌面“描述符”的指针;

char *Name – MATLAB 桌面字符类型的变量名称。

double *p = mxGetPr(mxArray *mxVector) – 接收指向数据数组指针的函数,用于复制数据以及 memcpy(…)。 在接收/写入 mxArray 类型的变量时,使用该函数提取/粘贴一个简单类型(int、double...)的变量。

double *p – 指向双精度类型数组的指针;

mxArray *mxVector – 指向变量矩阵的指针;

int = engEvalString(Engine *pEng, char *Command) – 发送命令到桌面的函数。 Command 行中 的命令将由 MATLAB 桌面执行。

Engine *pEng – 指向桌面“描述符”的指针;

char *Command – MATLAB 命令,字符类型行。

只有一个使用内存的函数:

void *pIn = memcpy (void *pIn, void *pOut, int nSizeByte) – 将 pOut 变量(数组)复制(克隆)至大小为 nSizeByte 字节的 pIn 变量的函数。

注意: 留意数组的维度。 它们必须相等,否则 pIn 数组应大于 pOut。

“DLL-包装程序”导出函数的要求

为了使 MetaTrader 4 能够使用 MATLAB,应该编写函数传递程序。 我们来看一下构建这种函数的要求。 从 MetaTrader 4 调用的任何函数必须是 __stdcall,即通过堆栈传递参数,函数清除堆栈。 下面是函数的声明方式:

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

extern "C" __declspec(dllexport) - 告诉 C++ 编译器函数为外部函数,在导出表中编写。

<variable_type> - 要返回变量的类型,可以是:void、bool、int、double,复合类型和指针无法传递;查看更多;

__stdcall – 关于参数传递到函数和返回的协议;

Function – 你的函数名称;

<type> <name> - 输入变量的类型和名称;变量的最大数量是 64。

这是函数定义的原型,另请注意 __stdcall

bool __stdcall Funcion (<type> <name>)

{

//……

}

除此之外,还要创建一个扩展名为 def 的文件。 这通常是一个文本文件,描述库名称和导出函数的名称。 如果该文件不存在,你的文件将会自己“编造”失真的函数名称,这样会使 DLL 的使用复杂化。 下面是文件示例:


LIBRARY NameDll

EXPORTS

NameFunctionA

NameFunctionB

LIBRARY –指向 DLL 名称的助词。

EXPORTS – 助词,表示将枚举下面的函数名称。

NameFunctionA、NameFunctionB – DLL 函数的名称。

但 MQL 对其施加了限制: 因为该语言没有指针,它没有动态内存,所以无法从 DLL 库传递数组、结构等。 但在 MetaTrader 中,数据可以写成数组,通过函数的引用进行传递。 结果可以写在由 MetaTrader 创建的数组内,DLL 接收该数组的指针。 但该数组必须是某种维度,而且不能是指标线(该限制可能跟 MetaTrader 4 中特定的内存分配有关)。

现在,在了解了如何编写和调用哪些函数后,我们来看一个“DLL-包装程序”的典型算法:

1. 在第一次调用 DLL 时,使用 engOpen() 函数启动 MATLAB Engine;

2. 从 MetaTrader 获得数据并送回,DLL 函数;

2.1. 由 mxCreateDoubleMatrix() 函数创建变量;

2.2. 复制数据到 mxVector 变量;memcpy() 和 mxGetPr() 函数;

2.3. 传递变量到 MATLAB 桌面,engPutVariable() 函数;

2.4. 传递公式/代码到 MATLAB 桌面,engEvalString() 函数;

2.5. 接收 MATLAB 桌面的反馈,engGetVariable() 函数;

2.6. 将值返回 MetaTrader,memcpy() 和 mxGetPr() 函数;

3. 使用 engClose() 函数关闭 MATLAB,当从 MetaTrader 进程的地址区加载 DLL 时删除所有的 mxDestroyArray() 变量。

现在我们来创建“DLL-包装程序”的架构:

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

项目程序集

下图显示了如何将库和 *.def 文件添加到项目:

下面是“DLL-包装程序”项目所需的文件列表:

  1. libeng.lib – 位于: \Program Files\MATLAB\R2007a\extern\lib\win32\borland\
  2. libmx.lib – 位于: \Program Files\MATLAB\R2007a\extern\lib\win32\borland\
  3. libmex.lib – 位于: \Program Files\MATLAB\R2007a\extern\lib\win32\borland\
  4. имя_проекта.def – 该文件应如上所述在记事本中创建。

应将 engine.h 文件从 \Program Files\MATLAB\R2007a\extern\\include 复制到 \Program Files\Borland\CBuilder6\Include 文件夹 - 这样你就不必每次为编译器指定路径了。

注意: 这些说明仅限于在 Borland C++ Builder 6 中汇编项目!



IV. 开发一个 MQL4 程序

我们将考虑只跟“DLL 包装程序”函数的声明和参数传递相关的问题。 为了声明函数,需要下面的语言结构:

#import "HighPass.dll"

void ViewAnsFilter();

bool TestDllFilter();

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

void MakeBuffFilter(int nSize);

void DestrBuffFilter();

#import

其中:

#import"HighPass.dll" – DLL 库的关键词和名称;

void MakeBuffFilter(int nSize); - 函数名称、要返回的值的类型、传递值的名称和类型。

注意! “[]” 在传递数组时使用, 如果 dll 对该数据数组写下反馈时,需要使用与号字符 "&" !对该数据数组写下反馈时,需要使用与号字符 “&” !在 MQL 4 中没有其他方式从外部程序传递数组! 要传递的数组必须具有特定的维度,且不能是指标数组!



V. 文件位置

在建立项目后,所有的项目文件都应正确放置:

*.dll 和 *.m - 目录中的库文件和m-函数位于 \Program Files\MetaTrader\experts\libraries;

*.mql 位于其正常位置,也就是说,如果它是一个指标,则位于‘indicators’文件夹,如果是 EA,则位于‘experts’,如果是脚本,则位于‘scripts’文件夹。

注意: 在启动指标或 Expert Advisor 时,可能会出现服务器繁忙的警告:

这种情况下,请等待 5-10 秒钟,直到工具栏出现 Console Matlab 并单击“重试”。

附言: 我有一个 512 RAM、Celeron M 2100 的笔记本电脑,在过滤器运行、图表数量为 5(总缓冲区为 500 х 8 х 5 = 20 000 字节大小)时没感觉到延迟。 所以,最终的选择在于你! 而我已经做出了选择。 如果出现延迟,在 MATLAB 中可以轻松实现分布式计算系统,也就是说,在连接到一个局域网的不同电脑上可以启动多个桌面。



参考文献列表

  1. Built-in MATLAB Help.
  2. "Matlab 5.х Calculations, Visualization, Programing" N.N. Martynov.
  3. C++ Builder 6. Reference Manual" A.Y. Arkhangelski.
  4. Built-in MQL4 Help.


总结

本文中,我们讨论了用于绑定 MetaTrader 4 和 MATLAB 数学包的“DLL-包装程序”开发的基础知识。 我们没有涉及提供多个指标和/或 Expert Advisor 运行的问题 - 将在下一篇文章中对其进行探讨。 附件中包含了因使用高频过滤器而改进过的 MACD。

本文译自 MetaQuotes Software Corp. 撰写的俄文原文
原文地址: https://www.mql5.com/ru/articles/1567

附加的文件 |
highpas.rar (10.19 KB)
highpasFull.zip (355.1 KB)
在 MetaTrader 中使用神经网络 在 MetaTrader 中使用神经网络

本文介绍如何轻松在你的 MQL4 代码中使用神经网络,利用最佳的免费人工神经网络库 (FANN),并在 MQL4 代码中采用多个神经网络。

通道 高级模型 沃夫波浪 通道 高级模型 沃夫波浪

本文描述了标记沃夫波浪形态的规则。 你可以在这里找到构建的详情和准确标记的规则,有助于快速无误的找到正确的波浪形态。

在交易中以 MQL4 手段运用模糊逻辑 在交易中以 MQL4 手段运用模糊逻辑

本文举例说明在交易中以 MQL4 手段运用模糊逻辑。以及描述如何使用 MQL4 版本的 FuzzyNet 函数库开发指标和智能交易系统。

通过分析组件评估交易系统的效益 通过分析组件评估交易系统的效益

本文探讨了通过分析单独组件的效能来评估复杂交易系统的效益。任何分析,不论是基于指标的图形化分析还是其他,都是在金融市场上成功交易的关键组成部分,在一定程度上,本文也是一项在联合应用程序中对其中几个简单独立的交易系统进行的研究,分析了它们的有效性和可用性。