|
|
(未显示1个用户的3个中间版本) |
第1行: |
第1行: |
− | =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
| |
− |
| |
− | [[Image:Fml_dll_create_project.png]]
| |
− |
| |
− | 2. 项目设置成DLL
| |
− |
| |
− | [[Image:Fml_dll_project_settings.png]]
| |
− |
| |
− | 3. 把TimeType, STKDATA, STKDATAEx,等等上述数据结构拷贝到MyDll.cpp
| |
− |
| |
− | [[Image:Fml_dll_edit_src.png]]
| |
− |
| |
− | 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目录也可以
| |
− |
| |
− | [[Image:Fml_dll_linker_output.png]]
| |
− |
| |
− | 6. 编译后,直接运行软件,或者在Debugging调试Command处添加软件的启动路径
| |
− |
| |
− | 7. 创建公式 测试DLL,并编译
| |
− |
| |
− | [[Image:Fml_dll_create_fml.png]]
| |
− |
| |
− | 8. 拖放到图上运行
| |
− |
| |
− | [[Image:Fml_dll_run_dll.png]]
| |
− |
| |
− | =示例DLL工程文件下载=
| |