自由DLL接口规范
目录 |
简介
相比传统DLL接口(飞狐接口),自由DLL接口的特点是放弃了对参数的要求。
传统DLL必须引入一个CalcInfo的结构化参数,通过它来传入行情数据。
这种设计的好处是用户操心得少一些,因为数据总是有的,不利之处是限制了发挥,难以返回多个序列结果,难以接入没有按接口要求编写的DLL。
自由DLL接口,不再传入CalcInfo参数,取而代之的是,用户必须自己负责传入所有的数据。
获得的回报是,
1.支持任意多的参数。
2.支持引用参数,也就是说,可以改变参数的值并返回给公式系统。
3.更灵活的参数传递。例如,可以根据需要传入地址,也可以传入值。
4.支持逐根的计算。每次只计算一根的值并返回单值。
与传统接口DLL一样,自由接口DLL也必须放置在FmlDLL目录下。
自由DLL声明
为了让公式系统知道DLL的参数格式,调用前需要使用extern语句进行声明
extern 返回值类型 函数名(参数类型 参数,...);
参数的个数和名称都没有限制
参数类型
传入DLL的参数有类型限制,目前支持的C类型包括 float, double, int,BOOL, LONG, DWORD, float*, LPCWSTR等 暂不支持double *
公式中,有些类型的名字与C不同。 其中,float*,有可能是NumericRef,也可能是NumericSeries,还可以是NumericArray 。 但打算传入单值,并改变值返回,那么用NumericRef,如果打算传入序列那么用NumericSeries,如果传入数组,那么用NumericArray 。
// C 代码里的声明
extern "C" __declspec(dllexport) void WINAPI my_ma2(float* pResultBuffer, float* pDataBuffer, int n, int barpos)
公式里面的声明 // 公式里面的声明
extern 'MyDll2.dll' void my_ma2(NumericSeries ResultBuffer, NumericSeries DataBuffer, int n, int barpos);
根据声明的不同,运行模式的不同,同一公式传入DLL的数值可能不同。
以一句myFunc( close )为例:
如果myfunc的声明是 extern 'myDll' void myFunc( float x );
则传入的实际是close[0]。
如果myfunc的声明是 extern 'myDll' void myFunc( NumericSeries x );
则传入的实际是close的整个序列的起始地址
自由DLL接口的调用
声明过的函数,可以通过函数名直接调用,无需通过"DLLName@FuncName"格式或RefDLL使用。
使用时必须将DLL放在软件安装目录下的FmlDll子目录下
DLL名称和函数名都是大小写敏感的,代码声明和公式调用时需要匹配。
DLL的返回值
新格式DLL可返回单值,序列和数组。单值类型大致分为两种:数值类型和字符串类型,可以通过函数返回值直接返回。
- 返回单值类型的c语言例子
//返回整数 extern "C" __declspec(dllexport) int WINAPI my_test1() { return 1; } //返回浮点 extern "C" __declspec(dllexport) float WINAPI my_test2() { return 2.0f; } //返回字符串 extern "C" __declspec(dllexport) LPCWSTR WINAPI my_test3() { return L"TEST STRING"; }
相应的公式调用例子
#MAINCHART #Run_By_Bar extern 'MyDll2.dll' int my_test1(); extern 'MyDll2.dll' float my_test2(); extern 'MyDll2.dll' LPCWSTR my_test3(); k1: my_test1; k2: my_test2; comment(my_test3);
若要返回序列或数组,则把需要返回的序列赋值目标当作参数传递给DLL,在DLL内部直接修改已达到赋值。 注意逐根运行模式下,每一根K线都会调用dll,所以通常每次调用只需要赋值比上一根K线新增加的类型, 例如计算收盘价均值时,每次在BarPos位置填入当根K线的均值即可。由此可见,这种应用下通常需要把 BarPos(当前是第几根K线)作为参数传入Dll中。
- 返回序列和数组的例子
extern "C" __declspec(dllexport) void WINAPI my_test4(float*pReturn, int nIndex) { pReturn[nIndex-1] = 123; } extern "C" __declspec(dllexport) void WINAPI my_test5(float*pReturn, int nLen) { for(int i=0;i<nLen;i++) pReturn[i] = 0; }
相应的公式调用例子
#MAINCHART #Run_By_Bar variable: NumericSeries mySequence(0); array: myArray[100](1); extern 'MyDll2.dll' void my_test4(NumericSeries mySequence, int nIndex); extern 'MyDll2.dll' void my_test5(NumericArray myArray, int nLen); my_test4(mySequence, BarPos); my_test5(myArray, 100);
DLL的参数类型
- | 单值 | 序列 | 数组 | 引用 |
---|---|---|---|---|
数值 | NumericSimple | NumericSeries | NumericArray | NumericRef |
字符串 | String | - | StringArray | StringRef |
无效数据表示
公式系统使用std的无效浮点数表示无效值,浮点无效值的一个重要特征是 f != f 为真,可作为判断依据, 其它运算皆输出无效值,其它比较皆输出假。当序列作为指标输出时,开始和结束两段的无效值自动截除,不作为指标输出。 例如要输出5日均线,序列的前4个值可填充无效值(填充0时会使指标线变形)
#include <limits> #define INVALID_NUMERIC std::numeric_limits<float>::quiet_NaN()
无效值在公式里可以用 Invalid 关键字指定,例如
k1:Invalid;
则k1指标线不会输出
编写调用公式
开发DLL的详细例子
实例下载
调用Windows系统DLL
调用win32提供的系统DLL,与调用自己编写的DLL是一样的。
只要知道windows系统函数所属的DLL和函数名,参数等信息就可以直接使用,例如
extern 'kernel32.dll' int GetTickCount(); tickcount:GetTickCount();
调用.Net DLL
跟一般DLL不同的是,.net DLL在声明时,除了函数名信息,还要提供命名空间、类名的信息,例如:
extern 'RzRq.dll' void RzRq.Grabber.GetFinance( LPCWSTR stockCode);
这里的RzRq就是命名空间,而Grabber则是类的名称,GetFinance是函数名