飞狐 DLL调用
(以“=DLL接口说明= #扩展函数可用于实现系统公式函数不能实现的特殊算法. #扩展函数用windows 32位动态链接库实现,建议使用Microsoft...”为内容创建页面) |
2013年4月11日 (四) 20:54的版本
目录 |
DLL接口说明
- 扩展函数可用于实现系统公式函数不能实现的特殊算法.
- 扩展函数用windows 32位动态链接库实现,建议使用Microsoft Visual C++编程.
- 调用时在公式编辑器中书写"动态库名称@函数名称"(参数表)即可,例如下面函数"FOXFUNC@MYMACLOSE"(5)
- 动态链接库名称和函数名称可以自己定义.
- 使用时必须将动态库文件放置在飞狐交易师安装目录下的FmlDLL子目录下使用.
DLL函数格式
DLL名称和函数名称可以自行定义,由于原飞狐公式不区分大小写,DLL的函数名最好使用全大写, 避免某些环境下无法加载,新版本的DLL则无此限制。 下面的例子定义了一个 MYMACLOSE 的函数,函数的实现下面具体分析。
extern "C" __declspec(dllexport) int WINAPI MYMACLOSE(CALCINFO* pData)
DLL函数返回值
首先注意上述函数的返回值是int,这个返回值表示在pData的m_pResultBuf里面有效位置的起始位, m_pResultBuf是DLL返回的数值序列的存放位置,0表示从第1位起有效,2表示从第3位起有效, 返回-1表示全部无效,公式将没有输出。m_pResultBuf和CALCINFO的类型下面讲述
DLL的参数类型
DLL的参数是一个结构体CALCINFO的指针,下面是定义
//////////////////////////////////////////////////// //调用接口信息数据结构 //////////////////////////////////////////////////// typedef struct tagCALCINFO { //结构大小 DWORD m_dwSize; //调用软件版本(V3.00 : 0x300) DWORD m_dwVersion; //调用软件序列号 DWORD m_dwSerial; //软件用户名 //char* m_strUserName; //股票代码 char* m_strStkLabel; //大盘 BOOL m_bIndex; //数据数量(pData,pDataEx,pResultBuf数据数量) int m_nNumData; //常规数据,注意:当m_nNumData==0时可能为 NULL STKDATA* m_pData; //扩展数据,分笔成交买卖盘,注意:可能为 NULL STKDATAEx* m_pDataEx; //参数1有效位置 int m_nParam1Start; //调用参数1 float* m_pfParam1; //调用参数2 float* m_pfParam2; //调用参数3 float* m_pfParam3; //调用参数4 float* m_pfParam4; //结果缓冲区 float* m_pResultBuf; //数据类型 int m_dataType; //财务数据 float* m_pfFinData; //以上与分析家兼容,所以沿用其结构和名称 //以下为 FoxTrader 扩展 // function type DWORD m_nFncType; // 调用参数数量 int m_nNumParam; // 调用参数数组 CALCPARAM* m_pCalcParam; //扩展结果缓冲区 float* m_pResultBufExt[8]; //扩展结果有效位置 int m_nResultStart[8]; // 用户数据(102400字节) void* m_pUserData; //内部函数计算用 //参数2有效位置 int m_nParam2Start; //参数3有效位置 int m_nParam3Start; //参数4有效位置 int m_nParam4Start; //股票名称 char* m_strStkName; //除权数据 SPLITDATA* m_pSplitData; //除权次数 int m_nNumSplitData; //计算当前下标数据 int m_iCurIndex; void* m_pReserved1; void* m_pReserved2; void* m_pReserved3; void* m_pReserved4; } CALCINFO;
注意里面的float* m_pResultBuf;就是函数返回数值序列的存放位置,序列的类型是float, 长度是int m_nNumData;
DLL参数传递
传入DLL的参数是CALCINFO结构体里面的m_pfParam1,m_pfParam2,m_pfParam3,m_pfParam4; 最多可传4个序列。当m_pfParam1为NULL时,表示无参数;当m_pfParam1不为空而m_pfParam2为空表示有1个参数; 当m_pfParam1和m_pfParam2不为空但m_pfParam3为空则表示有两个参数,以此类推。 序列的有效起始位是m_nParam1Start,m_nParam2Start,m_nParam3Start,m_nParam4Start, 起始位小于0表示是单值(用 *m_pfParam1 来获取)。起始位大于等于0时,有效数据为: m_pfParam1[m_nParam1Start],m_pfParam1[m_nParam1Start+1],m_pfParam1[m_nParam1Start+2]...m_pfParam1[m_nNumData-1] 第2,3,4条序列也是同样的结构。
基本数据结构
公式调用DLL时会把当前图形上的信息传入DLL,这些信息包括开高低收量额等, 定义在STKDATA* m_pData这个指针里,长度是m_nNumData, STKDATA结构体的定义如下:
//////////////////////////////////////////////////// //基本数据 //////////////////////////////////////////////////// typedef struct tagSTKDATA { TimeType m_time; //时间,UCT float m_fOpen; //开盘 float m_fHigh; //最高 float m_fLow; //最低 float m_fClose; //收盘 float m_fVolume; //成交量(手) float m_fAmount; //成交额(元)/持仓(未平仓合约,仅期货有效) WORD m_wAdvance; //上涨家数(仅大盘有效) WORD m_wDecline; //下跌家数(仅大盘有效) } STKDATA;
兼容时间格式
注意上述结构的m_time是TimeType类型,老版本的格式是time_t,由于新版本的time_t是64位的,老飞狐是32位, 所有原来time_t的字段,现在都用TimeType来表示。 使用vc6编译dll的,如果需要用到时间的,时间字段是vc6的time_t类型即可 使用vc2008以上版本的,time_t就是__int64,为了兼容老版本的DLL, 需要使用额外定义下面的TimeType类型(实际上就是int,32位的)
#define TimeType int
扩展数据格式
//////////////////////////////////////////////////// //扩展数据,用于描述分笔成交数据的买卖盘 //////////////////////////////////////////////////// typedef union tagSTKDATAEx { struct { float m_fBuyPrice[3]; //买1--买3价 float m_fBuyVol[3]; //买1--买3量 float m_fSellPrice[3]; //卖1--卖3价 float m_fSellVol[3]; //卖1--卖3量 DWORD m_dwToken; //成交方向 }; float m_fDataEx[13]; } STKDATAEx;
除权数据
//////////////////////////////////////////////////// //除权数据 //////////////////////////////////////////////////// typedef struct tagSPLITDATA { TimeType m_time; //时间,UCT float m_fHg; //红股 float m_fPg; //配股 float m_fPgj; //配股价 float m_fHl; //红利 } SPLITDATA;
扩展调用参数
//////////////////////////////////////////////////// //调用参数项结构 //////////////////////////////////////////////////// typedef struct tagCALCPARAM { union { const float m_fParam; //数值参数 const float* m_pfParam; //序列参数,指向一个浮点型数组 const char* m_szParam; //字符串参数 }; //序列参数有效起始位置 const int m_nParamStart; }CALCPARAM;
公式调用例子
公式里使用双引号来调用DLL, 例如下面的例子是调用MyDll.dll里面的MYMACLOSE函数,参数是5, 返回值输出成指标线k1。 下一节有建立DLL工程及调用公式的详细例子。
k1:"MyDll@MYMACLOSE"(5);
开发DLL的详细例子
这里例子是使用VS2012制作的,VS2010,VS2008,VC6也类似。
1. 首先创建Win32的工程项目,项目名称是MyDll
2. 项目设置成DLL
3. 把TimeType, STKDATA, STKDATAEx,等等上述数据结构拷贝到MyDll.cpp
4. 添加用户函数MYMACLOSE, 计算 N 日均线
//计算收盘价的均价,一个常数参数,表示计算周期 //调用方法: // "FOXFUNC@MYMACLOSE"(5) extern "C" __declspec(dllexport) int WINAPI MYMACLOSE(CALCINFO* pData) { if ( pData->m_pfParam1 && //参数1有效 pData->m_nParam1Start<0 && //参数1为常数 pData->m_pfParam2==NULL ) //仅有一个参数 { float fParam = *pData->m_pfParam1; int nPeriod = (int)fParam; //参数1 if(nPeriod>0) { float fTotal; int i, j; for ( i = nPeriod-1; i < pData->m_nNumData; i++ )//计算nPeriod周期的均线,数据从nPeriod-1开始有效 { fTotal = 0.0f; for ( j = 0; j < nPeriod; j++ ) //累加 fTotal += pData->m_pData[i-j].m_fClose; pData->m_pResultBuf[i] = fTotal/nPeriod; //平均 } return nPeriod-1; } } return -1; }
5. 设置项目的输出路径为软件安装目录下的 FmlDll 下,输出名称为 MyDll.dll。 这一步可以省略,编译后手动拷贝dll到软件的FmlDll目录也可以
6. 编译后,直接运行软件,或者在Debugging调试Command处添加软件的启动路径
7. 创建公式 测试DLL,并编译
8. 拖放到图上运行