13.7 MATLAB对接期货接口介绍(XAPI项目COM版)
前面提到过MATLAB对接.NET版有各种局限,特别是崩溃的问题影响比较严重,所以很多人用它来进行下单交易,用其他接口来接收行情,用它来实时监控行情的人比较少。是否有方法可以解决呢?那就得靠进程外COM版了。利用进程外COM不但可以绕过64位与32位的问题,崩溃的问题也随之不见了。
由于笔者没有时间完全用C++重新编写COM版,所以取巧地使用C#来实现COM。还是前面的.NET项目,只是在其中添加了兼容COM的接口。具体的代码在XAPI_CSharp/COM目录下。
COM版实现了进程内调用和进程外调用。进程内COM调用的局限性与.NET是一样的,所以只介绍一下二者之间的区别。
13.7.1 COM 组件注册
COM完全依赖于注册表,按Win+R组合键后输入regedit,将打开注册表编辑器。
以下是两条注册表信息。在64位操作系统中,当32位程序读取第一条注册表信息时, 其实会重定向到第二条的键值;而64位程序读注册表时就不会重定向。它们之间的区别是多了一个Wow6432Node。
HKEY_CLASSES_ROOT\CLSID\{825E3182-8444-4580-8ABC-9654B5FBF451}
HKEY_CLASSES_ROOT\Wow6432Node\CLSID\{825E3182-8444-4580- BA8C-965485FBF451}
目前此项目的ProgID(ProgID是程序员给某个CLSID指定的一个易记的名字)是"XAPI.COM",对应的CLSID是" {825E3182-8444-4580-8A8C-965485FBF451}"。即COM机制会先通过ProgID找到对应的CLSID,然后按CLSID下的设置项来启动对应的服务。将XAPI_CSharp.exe编译好后,使用命令RegAsm.exe来进行注册。
根据前面的注册表重定向的规则,RegAsm.exe也就会有64位版和32位版两种,在注册时也就分别能写入FKEY_CLASSES _ROOT\CLSID或FKEY_CLASSES_ROOT\Wow6432Node\CLSID目录下。同样,MATLAB的64位版或32位版分别读取的也是这两个注册表键值。
为了方便用户, 在XAPI2\tests\COM目录下提供了两个版本的RegAsm。同时提供了一个RegCOM.bat用来注册,内容如下:


注册成功后,在MATLAB中可以使用actxcontrolIist或actxcontrolselect查到所注册的COM组件。
使用regedit命令可以查看一下前面提到的注册表键值,有三个键值特别重要。
• LocalServer32:进程外COM信息。
• InprocServer32:进程内COM信息。
• Control:在Control和lnprocServer32同时存在的情况下才可以使用actxcontrollist/actcontrolselect查询。
注意:在XAP12\tests\COM目录下还提供了clear_InprocServer32.reg,内容如下:

它很重要, 是以进程外运行COM的关键,作用是删除InprocServer32。
13.7.2 COM组件运行
XAP12\languages\MATLAB\COM目录下是调用COM版的示例:


可以与前面的.NET版作一下对比,发现代码是基本类似的,只是.NET中对成员变量直接赋值改成了一堆的SetXxx方法。
为何使用这种方法呢?主要是在COM中复杂的类并不方便表示,枚举类型也无法按自己的想法表达。例如,开仓Open/Close使用1/2来代替,使用起来肯定极不方便。actxserver函数用来启动COM组件。再通过各种SetXxx将一些参数设置到COM对象中。各种可用的宇段可以参考COM/Struct. cs中的代码:

怎么一开始就报错?其实是因为MATLAB与COM组件XAPI_CSharp.exe分别属于不同的位数,例如MATLAB是64位,而XAPI_CSharp.exe是32位或正好相反。奇怪了,进程外COM不就是由XAPI_CSharp.exe来调用CTP的库吗?如果CTP库是32位,那XAPI_CSharp.exe也得是32位才对,为何还会报错呢?
其实问题出在了InprocServer32。因为MATLAB在lnprocServer32和LocalServer32都存在的情况下,优先使用lnprocServer32即进程内COM,所以才会报此错。可以双击clear_InprocServer32.reg利用导入注册表的方式删除,也可以手工删除。
导入注册表文件一般都是用来添加键值的,怎么还可以删除?这是一种特殊的用法。注意HKEY_CLASSES_ROOT前有一个"-",用它来实现删除操作。
删除后再使用actxcontrollist或actxcontrolselect,变成查不到此组件了。
删除后再来运行一下md=actxserver('XAPl.COM'),这次弹出了一个黑色控制台窗口,表示以进程外COM启动成功。不要关闭它。这时打开进程管理器,可以看到XAPI_CSharp.exe进程正在运行。再运行后面的代码,发现报错:
>>md.Connect();
Error using COM. XAPI COM/Connect
前面启动COM后,后面都是设置地址与账号信息,不大可能立即报错,就算报锚也应当是报连接账号信息错误,一定是出现了很严重的底层错误。再认真看一下,发现是因为md.SetLibPath设置的地址错误,上面设置的路径不存在指定的dll. 将地址修改正确即可。
13.7.3 COM事件注册
仅运行COM还不够,还需要接收COM通知过来的事件才可以。

以上是三个关键的函数,使用events函数查看当前组件支持哪些事件,通过registerevent函数注册好后,可以通过eventlisteners 函数查看注册的结果。导出的事件对应代码XAPI_CSharp/COM/lXApiEvents.cs。
再来看看事件处理函数的代码:

可以发现与.NET版本的代码基本类似。我们通过varargin得到传入的所有参数,其中倒数第二个cell就是事件struct信息,只取它进行处理即可。为何是取倒数第二个cell呢?进入Doc中查找COM Event Handlers即可,这里不再详叙。
观察上面的代码,为何status_String这个字段看起来这么别扭?其实还有一个Status字段。这里的Status就是在.NET中提到的连接状态,是一个枚举类型,但在COM中只能转换成数字,但数字的辨识度太差,所以同时给出一个字符串。其他的枚举类型也都是同样的处理方式。
订阅成功后,行情处理函数如下:

再来看看事件处理函数的代码,其中InstrumentID与ExchangeID是由所调用的API直接返回的,CTP的期货接口ExchangeID字段是空值,而Symbol是将InstrumentID与ExchangeID合并成一个字符串。合并成一个宇段的好处是上层用户可以将Symbol当成唯一符号直接存到字典这类数据结构中,方便使用。
13.7.4 下单
下单的方法也是需要先创建一个Order对象,然后再对它进行各种参数的设置。有哪些字段可以设置呢?每个字段又有哪些参数呢?参考XAPI_CSharp\COM目录下的Struct.cs中的OrderClass类。但对于其中的枚举可以用哪些参数呢?这下只能用VS打开XAPI_ CSharp\Struct.cs.找到结构体OrderField,在对应的枚举类型上按Fl2键跳转到对应的地方看可用的参数。
枚举类型在填写参数时都使用字符串,底层会将字符串解析成对应的值,所以枚举的字符串不要写错,大小写必须与按F12键看到的完全一样。


不同于.NET版.COM版中委托回报代码中不需要处理中文问题,在底层己经转换完成。如下面的order.Text,如果使用.NET版,则只能写成Extensions_GBK.Text(order) 。
