13.6 MATLAB对接期货接口介绍(XAPI项目.NET版)

13.6 MATLAB对接期货接口介绍(XAPI项目.NET版)

项目地址:https://github.comlQuantBox/XAPI2下有C版、C#版、MATLAB版等多个版本, 一般来说C版、C#版更新及时,MATLAB版更新不那么及时。要想保持最新版,可以编译最新版的C版与C#版,井复制到与M文件同目录。

C库:thostmduserapi.dll、thosttraderapi.dll来自上期技术,CTP_Quote-x86.dll、CTP_Trade x86.dll、Queue_x86.dll(Queue_x86d.dll)是编译产生的。

.NET库:XAPI_CSharp.dll(XAPI_CSharp.exe)、NLog.dll。

注意:XAPI_CSharp.dll或XAPl_CSharp.exe只是输出类型的区别,内部的代码完全一样,在当前项目中可以混用。

test_CTP.m/test_Kingstar.m是程序入口,其做了以下工作:

(1) 导入C#库。

(2) 创建行情对象、交易对象的实例。

(3) 注册事件。

(4) 登录。

(5) 下单(请手工执行)。

(6) 撤单(请手工执行)。

(7) 退出(己经注释,没有执行,需手工输入退出)。

13.6.1 导入C#库

首先切换当前目录,然后导入.NET库(注意同目录下的其他C++库和C库都没有导入),最后导入库中的命名空间。

13.6.2 启动行情连接

这句话的意思是XAPI_CSharp中报了一个错误,试着加载不正确的格式。这是因为XAPI_CSharp.dll会加载CTP_Quote_ x86.dll,而CTP_Quote_x86.dll是一个32位的库,而MATLAB是64位的。如何解决这个问题?请参考前面的相关章节,安装32位的MATLAB或编译64位XAPI2项目。

还可能会出现如下的报错:

这又是另一个错误,表示找不到CTP_Quote_x86.dll,但明明就在当前目录,怎么会找不到呢?如果是自己编译的CTP_Quote _ x86.dll,一般不会出现这个问题,但VisualStudio 2015一类的开发工具没有安装的话,出现问题的可能性就比较大。主要是因为XAPI版项目编译的版本可能会有一些依赖库,但计算机中没有安装Visual Studio 2015,所以这些依赖库都没有。

如何解决呢?可以下载depends软件,链接为http://www.dependencywalker.com/,用它打开CTP_Quote_x86 .dll,看缺少哪些依赖库,然后到网上搜索下载缺少的.dIl即可。如果缺少的文件少,则很容易解决:如果缺少的文件很多,建议直接下载Visual Studio的最新版,重新编译一下CTP_Quote项目。

global全局变量在接下来的各函数中都要用到。XApiWrapper是.NET中的类,首先创建,然后通过addlistener向其中注册各事件的处理函数。有哪些事件可以注册呢?这必须得查看C#项目。打开XAPI_CSharp项目,找到Event命名空间下的XApiWrapper.cs,代码开头的部分即可用的事件:

每个事件会传递哪些信息呢?以OnRtnDepthMarketData事件为例,EventHandler就是MATLAB所支持的标准事件签名。将光标移动到OnRtnDepthMarketDataNEventArgs上,按F12键,会跳到EventArgs.cs文件。以下是对应的代码:

其中最重要的是看OnRtnDepthMarketDataNEventArgs有哪些变量可以使用,从代码中可以看到marketData。再将光标放在Dept抽larketDataNClass上,按F12键,跳转到Struct.cs文件,这便是深度行情结构体的定义。注意,由于以上结构体太长,这里只挑选一部分显示。

行情事件的C#相关代码己经展示完,如何在MATLAB中使用呢?打开OnRtnDepthMarketData.m文件:

通过前面的代码可以知道,在这段代码中,arg表示的是OnRtnDepthMarketDataNEventArgs,其中可以使用的一个变量是marketData,而此变量又是一个结构体,其结构体为DeptMarketDataNClass。那么,如何打印行情到来时的最新价呢?可以通过arg.marketData.LastPrice。

13.6.3 显示连接状态

上节解释了行情如何打印,但只运行上一段代码并不会立即打印。首先得登录成功,然后订阅指定的合约。如何知道登录成功呢这就得靠OnConnectionStatus了。

细心的读者会发现以上函数多了md,为何?因为交易的连接状态事件也是OnConnectionStatus,在这里是为了分别调用不同的函数加以区分。

代码很简单,就是把当前的连接状态打印出来。都有哪些状态呢?打开XAPI_CSharp项目,Enum.cs文件中即是。

连接状态可以分为两大类:进行时和完成时。将不同API的各种状态都进行了统一,Done表示登录成功,Disconnected表示登录失败。

CTP行情服务器目前不检查账号是否有效,所以填写错误的用户名和密码也可以达到Done状态。如果打印的最后状态是长时间Connecting,则表示服务器无法连接,有可能是本地网络断开,也有可能是行情服务器在非交易时间关闭。

交易比较复杂。在出现Logined后还会出现Confirming和Confirmed,但只有最后达到Done才表示成功。这主要与API的设计及监管有关。监管规定结算单必须要确认,所以API中在登录成功后还要进行一次结算单的确认才可以下单,否则将被拒绝。另外,由于开发人员的水平参差不齐,给各期货公司带来很多事故,在期货公司的强烈要求下,柜台商加了一个检查客户端授权的功能。如果期货公司设置了该功能,则必须先进行客户端授权检查再进行登录,即先Authorizing、Authorized才会到Logining, 最后到Done。

这样则会打印出登录失败的原因,需要根据结果对参数进行调整。

注意:Extensions_GBK.Text(arg.userLogin),其实ùserLogin.Text这个对象是有内容的,内容一般为中文,但因英文和繁体操作系统内码不同,导致中文不能正确解析。为了使中文能在不同语言的操作系统上显示,同时又为了兼顾处理速度,只在必要的时候处理,所以提供了一个扩展方法,将其中的Text字段解码出来。后面只要会出现中文的地方都有对应的Extensions_GBK,而不会出现中文的宇段则可以直接打印,如Symbol。Extensions_GBK实现代码在Extensions.cs中。

13.6.4 订阅行情

行情状态打印出Done即表示登录成功,接下来就是订阅行情了。

只要输入以上代码就会立即打印行情。该代码中的第一个参数表示合约列表,支持一次写多个,可用";"分隔。区分大小写,大小写错误时不会有行情返回。上期所和大商所是小写, 郑商所和中金所是大写。如果不知道合约代码,则可以查看快期中的合约列表。第二个参数表示交易所代号,在期货交易时可以留空,但在证券交易时必须指明交易所。

13.6.5 行情连接参数

前面提到了基本行情显示的方式,连接状态的查看都是为了在连接遇到问题时能自己检查问题所在。接下来看看连接的参数:

BrokerID:经纪公司代码,因CTP最开始设计时支持一个柜台上跑多家经纪公司,而每家公司的客户号有可能重复,所以使用经纪公司代码来区分。

Address服务器地址,注意前面有"tcp://",后面有端口号。

UserID:账号。

Password:密码,目前CTP行情服务器不检查密码是否正确。

13.6.6 启动交易连接

接下来则是最复杂的交易部分:

注意:行情服务器与交易服务器的地址是不一样的。从以上示例来看, 行情的端口是10010,交易的端口是10000。

13.6.7 交易的相关事件

XApiWrapper到底支持哪些事件呢?XAPI_CSharp/Event/ XApiWrapper.cs源码中有详细的事件列表。其实CTP还提供了很多功能,由于目前只是实现简单程序化工具,用不到那些功能,所以没有提供对应的事件支持。用户可以参与开源项目,一同完善。

在下单时,能在OnRtnOrder中收到委托变化的回报。如果成交了,则会在OnRtnTrade中收到成交回报。

以OnRtnOrder为例, 其语法如下:

可在委托回报中使用全局的orders记录回报信息。同时,还存在LocalID与ID,后面将介绍这两个ID的区别和使用方法。

13.6.8 下单

直接调用C#版的接口进行下单还是比较复杂的,下面是一个简单的封装样例。

以买入开仓为例, 其语法如下:


以上代码的意思为:先创建一个order对象,然后设置合约名、订单类型、买卖方向、数量、价格、开平仓、投机套利标志,最后下单。

如何表示开平仓呢?在Enmu.cs中查找OpenCloseType,其语法如下:

注意:上期所区分平今与平昨,必须指定正确才能平仓, 否则提示可平仓位不足。上期所平今用CloseToday,而平昨用Close。其他交易所使用CloseToday和Close都能正常平仓。

套保标记。通过查找HedgeFlagType的定义即可。

注意: 普通用户开通的账户只能下投机Speculation。

Type可以设置市价单/限价单。

TimelnForce可以设置IOC或FOK。

下单的代码如下:

13.6.9 撤单

必须要传入订单的编号,其实一个简单的编号柜台并无法识别,而是通过好几个字段来进行标识的。所以XAPI内部其实通过报单回报做了一些映射。这里开始涉及LocalID与ID了。有部分API在下单前可以指定ID,而还有部分API只有下单后等到回报后才知道ID是多少,大部分证券接口因是同步接口,所以存在此问题。为了异步处理订单,只能使用两个编号: 一个是本地生成LocalID;另一-个是柜台返回的ID。

SendOrder返回的是LocaUD,而OnRtnOrder中能返回ID。只要收到的OnRtnOrder中ID不为空,就用ID来撤单:反之则用LocallD来撤单。

CTP接口可以提前指定编号,所以LocalID与ID相等,可以直接用于撤单。

13.6.10 退出

13.6.11 改进

实际上,实盘中还有更多的工作要做,比如要处理以下细节:

(1) 当报单在期货公司前置机参数检测出错时返回,如资金不足等。

(2) 在交易所报单出锚时返回,如不支持的交易指令等。

(3) 当撤单在期货公司前置机参数校验出错时返回,如找不到报单。

(4) 在交易所撤单出错时返回,如报单已经成交等。

同时,对于MATLAB层调用来说也过于烦琐,建议用户再封装一次。可行的封装方式有以下几种。

(1) Buy/Sell:仅记录净持仓。

(2) OpenLong/CloseLong、OpenShortlCloseShort:区分了双向持仓。

(3) order_target:不管操作,只在乎最后持仓。