标签:
某塔的PEL里提供了许多的函数,但是也会存在某些情况下需要自行扩展的情况,某塔提供了集中扩展的方式,其中一种是使用DLL公式(VC的DLL编程)进行扩展,方便整合原有的公式。
而matlab里面提供了许多的信号,序列等处理方法,可以很方便的进行一些策略,计算等等。
现在需要使用matlab的自定函数(M函数)对金字塔的函数进行扩展。
VC与MATLAB交互的几种方式,见前篇:http://blog.csdn.net/fonjames/article/details/51554385
首先Matlab引擎(Engine)的方法据说效率比较低下,不推荐,依次尝试了 C++ shared library --> com组件 --> Matlab coder 的方式。
某塔中要求的DLL方式,参照某塔提供的 “栗子”项目FmlDevelope 位于 ...\WeiSoft所在目录\fmldevelop.zip
自己生成的dll放于 ...\WeiSoft所在目录\FmlDLL
然后在某塔的公式编辑器里 使用 “mydll@myfun"(arg1,arg2) 即可,注意双引号是必须存在的。
/* /////////////////////////////////////////////////////////////////////////// xxx塔“C语言接口”扩展程序调用接口规范V1.0 1.扩展函数可用于实现系统公式函数不能实现的特殊算法. 2.扩展函数用windows 32位动态链接库实现,建议使用Microsoft Visual C++编程. 3.调用时在公式编辑器中书写"动态库名称@函数名称"(参数表)即可,例如下面函数可以写为"STOCKFUNC@MYMACLOSE"(5) 4.动态链接库名称和函数名称可以自己定义. 5.使用时必须将动态库文件放置在与*.stk文档相同目录下使用. //原文错误,应该是fmldll目录 6.请注意所运行xx塔的版本,如果是x64位版本,请将DLL编译为64位版本环境下才能正常运行。 从xxx塔的2.34版后,接口支持逐K线模式调用,增加RUNMODE系统函数,用于告知调用的公式系统本接口的运行模式。 xxx塔的公式系统运行模式分序列模式和逐K线模式,序列模式模式整个公式系统解释时只会调用一次本接口,传递和 返回序列参数数据到接口,而逐K线模式会在解释时每个K线都调用本接口,传递和返回也都是单值数据。 传统的接口是设计在序列模式下运行的,虽然在逐K线模式下xxx塔也可以调用运行传统的接口,但是这是效率很低并且是不 稳定的,因此如果需要在逐K线模式下使用接口,请使用此种专用模式。 *//*//调用接口信息数据结构 //////////////////////////////////////////////////// typedef struct tagCALCINFO{ ... } CALCINFO; 注1: 1.函数调用参数由m_pfParam1--m_pfParam4带入,若为NULL则表示该参数无效. 2.当一个参数无效时,则其后的所有参数均无效. 如:m_pfParam2为NULL,则m_pfParam3,m_pfParam4也为NULL. 3.参数1可以是常数参数或序列数参数,其余参数只能为常数参数. 4.若m_nParam1Start<0, 则参数1为常数参数,参数等于*m_pfParam1; 5.若m_nParam1Start>=0,则参数1为序列数参数,m_pfParam1指向一个浮点型数组, 数组大小为m_nNumData,数据有效范围为 m_nParam1Start 至 m_nNumData-1. 在时间上m_pData[x] 与 m_pfParam1[x]是一致的 注2: 1.该扩展结构使调用参数在技术上可以是无限数目的,且每个参数都为数值序列。 2.CALCPARAM结构用于带入参数信息和实际数据,m_pCalcParam数组大小为m_nNumParam,数据有效范围为 0 至 m_nNumParam-1. 3.按参数的顺序,m_pCalcParam[0]为第一个参数的数据,m_pCalcParam[1]为第二个参数的数据...,为了保持兼容,原m_nParam1Start、m_pfParam1等5个属性依然有赋值。 4.取用m_pCalcParam[i].m_pfParam,数组大小为m_nNumData,数据有效范围为m_pCalcParam[i].m_nParamStart 至 m_nNumData-1. 若m_pCalcParam[i].m_nParamStart<0, 则此数组中无有效数据。 5.由于可以调用多个序列,许多序列的计算可以先在公式中进行,然后作为调用的参数即可。 *///////////////////////////////////////////////////// /* 函数输出 __declspec(dllexport) int xxxxxxxx(CALCINFO* pData); 1.函数名称需全部大写. 2.函数必须以上述形式声明,请用实际函数名称替代xxxxxxxx; 对于C++程序还需包括在 extern "C" { } 括号中. 3.函数计算结果用pData->m_pResultBuf带回. 4.函数返回-1表示错误或全部数据无效,对于序列模式返回第一个有效值位置,即: m_pResultBuf[返回值] -- m_pResultBuf[m_nNumData-1]间为有效值.逐K线模式返回值大于等于0均表示成功 */ //DLL公式的运行模式,系统系统调用该DLL时,告知公式系统该DLL公式运行在何种模式下 //返回值: 0本DLL运行序列模式 1本DLL运行逐周期模式 __declspec(dllexport) int WINAPI RUNMODE(); //示例函数,使用时用实际名称替换 __declspec(dllexport) int WINAPI MYMAVAR(CALCINFO* pData)
例子中的实现
//计算均价,2个参数,参数1为待求均线的数据,参数2表示计算周期 //调用方法: "STOCKFUNC@MYMAVAR"(CLOSE-OPEN,5) __declspec(dllexport) int WINAPI MYMAVAR(CALCINFO* pData)//对于逐K线模式,的处理方式的示范代码 { if(pData->m_pfParam1 && pData->m_pfParam2) { //对于逐K线模式,由于传递数据都是数值,因此需要一个数组用来保存传递过来的参数,用来计算. //本例只是简单演示这个用法,如果用户在公式多次调用了接口,则会出现重复使用该变量导致计算出错 //因此要根据情况做几个这种全局静态变量用于保存各种数据。 static std::vector<double> arMaData; //第一个周期初始化数据 if(pData->m_dwBarpos == 0) { arMaData.clear(); } double dbData = *pData->m_pfParam1; //防止使用仅刷最后K线的反复刷新问题 if(arMaData.size() >= pData->m_nNumData) arMaData[arMaData.size()-1] = dbData; //仅仅更新最后一个数据 else arMaData.push_back(dbData); DWORD dwCyc = (DWORD) *pData->m_pfParam2; if(pData->m_dwBarpos < dwCyc-1) { /*对于未到计算周期,返回无效数据*/ return -1; } //先累加 float fAdd = 0; for(DWORD i = pData->m_dwBarpos-(dwCyc-1); i <= pData->m_dwBarpos; i++) { fAdd += arMaData[i]; } *pData->m_pResultBuf = fAdd / dwCyc; } return 1;*/ }
mwArray dclose = mwArray(pData->m_nNumData,1, mxDOUBLE_CLASS, mxREAL); dclose.SetData(&arMaData1[0], arMaData1.size()); mwArray dif1, dif2; mwArray nR = mwArray((int)dwRank); /* m函数自动生成,声明为: extern LIB_MatDif_CPP_API void MW_CALL_CONV MatDif(int nargout, mwArray& dif1 , mwArray& dif2 , const mwArray& close , const mwArray& n); */ MatDif(2, dif1, dif2, dclose, nR); *pData->m_pResultBuf = dif1(1,1);//mxDouble(dif1);
某塔在加载完封装的dll后,居然不会在当前目录查找m函数的dll,所以这个过程中还涉及了dll路径查找,简单的放到system32供其调用。在这条路径不通的情况,考虑使用com组件,这样第三层(某塔第一层,封装dll第二层) 就等于是向整个系统登记了位置,就没有很强的依赖了吧?
if(disp.CreateObject("MatDif1.LibMatDif") == false) { MessageBox(NULL,"加载com失败!","",MB_OK); return 0; } VARIANT vclose, v3, vdif1, vdif2; VariantInit(&vclose); VariantInit(&vdif1); VariantInit(&vdif2); v3.vt = VT_I2; v3.intVal = 3; vclose.vt = VT_R8|VT_ARRAY; vclose.parray = SafeArrayCreateVector(VT_R8,0,arMaData1.size()-1); double * buf = NULL; SafeArrayAccessData(vclose.parray,(void**)&buf); memcpy(buf,&arMaData1[0],sizeof(double)*(arMaData1.size()-1)); SafeArrayUnaccessData(vclose.parray); disp.InvokeMethod("MatDif",2, &vdif1,&vdif2,vclose,v3); pData->m_pResultBuf = new float; *pData->m_pResultBuf = vdif1.dblVal;这里面又有新的内容,COM的基础类型是 VARIANT, VARIANT与matlab的矩阵(向量)数据的交互又涉及到了safearray.
//SAFEARRAY的Win32定义: typedef struct tagSAFEARRAY { //这个结构的成员(cDims,cLocks等)是通过API函数来设置和管理的。 unsigned short cDims; //数组的维数 unsigned short fFeatures; //用来描述数组如何分配和如何被释放的标志 unsigned long cbElements; //数组元素的大小 unsigned long cLocks; //一个计数器,用来跟踪该数组被锁定的次数 void * pvData; //指向数据缓冲的指针 /真正的数据存放在pvData成员中 SAFEARRAYBOUND rgsabound[ 1 ]; //描述数组每维的数组结构,该数组的大小是可变的 //SAFEARRAYBOUND结构定义该数组结构的细节。 } SAFEARRAY; /* rgsabound是一个有趣的成员,它的结构不太直观。它是数据范围的数组。//该数组的大小依safe array维数的不同而有所区别。 rgsabound成员是一个SAFEARRAYBOUND结构的数组--每个元素代表SAFEARRAY的一个维。 */ typedef struct tagSAFEARRAYBOUND { unsigned long cElements; unsigned long lLbound; } SAFEARRAYBOUND; /*维数被定义在cDims成员中。例如,一个\'C\'类数组的维数可以是[3][4][5]-一个三维的数组。 如果我们使用一个SAFEARRAY来表示这个结构,我们定义一个有三个元素的rgsabound数组--一个代表一维。 cDims = 3; SAFEARRAYBOUND rgsabound[3]; rgsabound[0]元素定义第一维。在这个例子中ILBOUND元素为0,是数组的下界。cElements成员的值等于三。 数组的第二维 ([4])可以被rgsabound结构的第二个元素定义。下界也可以是0,元素的个数是4,第三维也是这样。 要注意,由于这是一个"C"数组,因此由0 开始, */ /*对于其它语言,例如Visual Basic,或者使用一个不同的开始。该数组的详细情况如下所示: 元素 cElements ILbound rgsabound[0] 3 0 rgsabound[1] 4 0 rgsabound[2] 5 0 */
<pre name="code" class="cpp">if(pData->m_dwBarpos < dwRank || pData ->m_dwBarpos < pData->m_nNumData -1) { //对于未到计算周期,返回无效数据 return -1; } double *dif1 = new double; double *dif2 = new double; emxArray_real_T * close = emxCreateWrapper_real_T((double*)&arMaData[0],1,arMaData.size()); MatDif(close,3, dif1, dif2); pData->m_pResultBuf = new float; *pData->m_pResultBuf = *dif1; emxDestroyArray_real_T(close);
标签:
原文地址:http://blog.csdn.net/fonjames/article/details/51686131