前言
matlab中具有很多丰富的函数,可以很方便地进行统计分析和科学计算,而MT4/MT5有很好的回测平台和可扩展的MQL语言,但是缺少很多分析函数库。在MT5的社区上有很多将matlab引擎封装成dll与MT4/MT5连接起来,但是这些文章的调用都比较过时,这其中涉及到许多的错误问题。目前MT4调用的dll只能是Visual studio2008/2010,本文采用2010版本。经过测试,发现MT4只能调用32位的matlab,而MT5可以调用64位的matlab,且在X64的平台下编译成Dll运行。关于Dll的其他问题可以参考前一个博文。
一、matlab引擎介绍
需要详细了解MT4与matlab交互的理论,可以参看https://www.mql5.com/zh/articles/44 ,其中有关数组反转和字符串的编码方式不同,在编写dll的时候需要特别注意。这里介绍主要从matlab自带的一个engine的例子来详细说明,关于matlab与c/c++之间的混合编程的方法有很多,具体也包括使用mex函数,但是使用engine虽然速度相对较慢一些,不过主要能够完成将matlab的代码直接在C++中调用,并且更加稳定。此处使用的matlab版本是64位的2014a。
1.1 在Visual studio2010中的环境配置问题
详细过程可以根据
http://jingyan.baidu.com/article/60ccbceb6e862e64cab1978e.html 中的内容进行配置,如果出现下图的错误,应该将debug的平台改为x64:
1.2 engine例子代码解读
// MQL5DLLSamples.cpp : 定义 DLL 应用程序的导出函数。
//例子是利用matlab引擎绘制竖直自由落体的时间与位移变化关系图
#include "stdafx.h"
#include "engine.h" //注意必须先按照1.1中的说明来进行matlab文件的配置
#include <stdio.h>
#define BUFSIZE 256
_DLLAPI bool __stdcall EngBegin(void)
{
Engine *ep; //引擎对象指针
mxArray *T = NULL, *a = NULL, *d = NULL; //声明三个变量的数组
char buffer[BUFSIZE+1]; //从matlab输出的数据的缓存数组
double *Dreal, *Dimag;
double time[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
/*
* 启动 MATLAB engine
*/
if (!(ep = engOpen(NULL))) {
MessageBox ((HWND)NULL, (LPCWSTR)"Can't start MATLAB engine",
(LPCWSTR) "Engwindemo.c", MB_OK);
exit(-1);
}
/*
*第一部分
*
* 将数据传输给matlab,并计算数据,绘图
*
*/
/*
* 建立一个double型的实数矩阵对象,关于这些函数可以从matlab的帮助文档中找到
*/
T = mxCreateDoubleMatrix(1, 10, mxREAL);
//将数组time的数赋值给T对象
memcpy((char *) mxGetPr(T), (char *) time, 10*sizeof(double));
/*
* 将变量 T 传送到 MATLAB 的工作空间
*/
engPutVariable(ep, "T", T);
/*
* 计算位移,其中9.8是重力加速度g
*/
engEvalString(ep, "D = .5.*(-9.8).*T.^2;");
/*
* 绘制结果,也可以将matlab的代码封装成一个函数脚本调用,但是脚本文件必须在MT5\Libaray\下面
*/
engEvalString(ep, "plot(T,D);");
engEvalString(ep, "title('Position vs. Time for a falling object');");
engEvalString(ep, "xlabel('Time (seconds)');");
engEvalString(ep, "ylabel('Position (meters)');");
/*
* 第二部分
- * 这部分例子是计算一个矩阵A的特征值
*
*/
a = mxCreateDoubleMatrix(3, 2, mxREAL);
memcpy((char *) mxGetPr(a), (char *) time, 6*sizeof(double));
engPutVariable(ep, "A", a);
/*
* 计算特征值
*/
engEvalString(ep, "d = eig(A*A')");
/*
*使用 engOutputBuffer来获得 MATLAB 的输出. 但是必须确保缓存区间开始是空的
*/
buffer[BUFSIZE] = '\0';
engOutputBuffer(ep, buffer, BUFSIZE);
/*
*显示输出缓存区的信息
*/
engEvalString(ep, "whos");
MessageBox ((HWND)NULL, (LPCWSTR)buffer, (LPCWSTR) "MATLAB - whos", MB_OK);
/*
* 获得输出结果的数据
*/
d = engGetVariable(ep, "d");
engClose(ep);
if (d == NULL) {
MessageBox ((HWND)NULL, (LPCWSTR)"Get Array Failed", (LPCWSTR)"Engwindemo.c", MB_OK);
}
else {
Dreal = mxGetPr(d);
Dimag = mxGetPi(d);
if (Dimag)
sprintf(buffer,"Eigenval 2: %g+%gi",Dreal[1],Dimag[1]);
else
sprintf(buffer,"Eigenval 2: %g",Dreal[1]);
MessageBox ((HWND)NULL, (LPCWSTR)buffer, (LPCWSTR)"Engwindemo.c", MB_OK);
mxDestroyArray(d);
}
/*
* 最后要销毁mxArray变量
*/
mxDestroyArray(T);
mxDestroyArray(a);
return true;
}
二、在MT5中的调用
//+------------------------------------------------------------------+
//| DllTest.mq5 |
//| Copyright 2016, DaiXiaoRong. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2016, MetaQuotes Software Corp."
#property link "https://www.mql5.com"
#property version "1.00"
#import "MQL5DLLSamples.dll"
bool EngBegin(void);
#import
//+------------------------------------------------------------------+
//| Script program start function |
//+------------------------------------------------------------------+
void OnStart()
{
//---
EngBegin();
//---
}
//+------------------------------------------------------------------+