提到国内的量化交易柜台系统一定无法绕过上期技术的CTP,这是巨人肩膀一样的存在。有人在模仿,也有人在超越。
虽然CTP已经极大的降低了普通交易者进入量化交易领域的门槛,但是这个门槛任然不低,要熟悉个中细节仍需花费不少时间和精力。
另外,由于交易规则差异(例如,交易所特色指令)、业务差异(例如,期货交易业务、股票交易业务、两融交易业务)、经纪商柜台差异(例如,期货经纪商用的CTP系统、证券经纪商自主开发的系统)等的存在,开发跨市场交易策略面临的问题会更多。
好在大部分交易柜台都是以CTP这个行业标准为蓝本开发,实现一套统一的全市场量化交易API并不是一件不可能的事情。
AlgoPlus项目在这方面做了一些尝试。
统一交易规则
- 价格类型和有效期
不同交易所允许的价格类型不同:上期所只允许限价单,郑商所、大商所允许市价单,中金所和证券交易所还允许最优价单、五档最优价单等。有效期就是我们所熟知的FAK(fill and kill)和FOK(fill or kill)。
正确使用价格类型和有效期并不是一件困难的事情,却有些繁琐。虽然,统一使用限价单不失为一种解决方案。但是,合理使用价格类型和有效期,通常能会达到事半功倍的效果。
AlgoPlus的设计使用OrderType重新定义了订单类型,交易者可以很方便的使用不同交易所的特色指令,例如:
/// 最优五档,等待成交(上海证券交易所)#define ENUM_OrderType_SSE_FiveAndWait 'b'/// 最优对方,等待成交(深圳证券交易所)#define ENUM_OrderType_SZSE_BestAndWait 'l'/// 市价,等待成交(郑州商品交易所)#define ENUM_OrderType_CZCE_AnyAndWait 'C'/// 市价,等待成交(大连商品交易所)#define ENUM_OrderType_DCE_AnyAndWait 'J'/// 限价,等待成交(上海期货交易所)#define ENUM_OrderType_SHFE_LimitAndWait 'O'/// 最优五档,剩余撤销(中国金融期货交易所)#define ENUM_OrderType_CFFEX_FiveAndKill 'W'
另外,AlgoPlus还定义了通用型“市价”单。这些市价单的本质是使用行情价格的限价单。
/// 限价,等待成交(通用)#define ENUM_OrderType_LimitAndWait '0'/// 最优对方限价,等待成交(通用)#define ENUM_OrderType_BestLimitAndWait '1'/// 最优本方限价,等待成交(通用)#define ENUM_OrderType_HomeBestLimitAndWait '2'/// 极限价格限价,等待成交(通用)#define ENUM_OrderType_FrontierLimitAndWait '3'/// 最新成交限价,等待成交(通用)#define ENUM_OrderType_LastLimitAndWait '4'
- 订单数量
期货订单最小量是1手,以1为单位变化。股票订单最小量是100股,且以100为单位变化。科创版比较特殊,订单最小量是200股,以1为单位变化。订单最大数量根据交易所、品种、价格类型不同而不同。一般来说市价单的最大量比限价单最大量小。如果报单时没有遵循这些规则,将会导致废单。
AlgoPlus支持按照交易规则修正报单数量,并且将超过最大数量的订单拆成数个子单执行。
- 平仓、平今、平昨
上海期货交易所和上海能源交易中心的品种在平仓时必须指定今仓或者昨仓,否则会导致废单。
从交易者的角度,区分今/昨仓的意义有限(除非有相关限制或者优惠)。
AlgoPlus支持未指定今/昨的平仓指令,即使待平数量包括今仓和昨仓,也可以正确执行。
- 买、卖
有人可能会有疑问,除了买卖还有第三种交易吗?
是的。AlgoPlus的定位是全市场统一的交易API,其中就包括对股票两融业务的支持。两融业务会出现融资买入、卖券还款、融券卖出、买券还券等操作。负债和持仓有本质的区别。但是,从交易的角度,融券负债就是空头持仓,平仓与还券没有本质区别。
AlgoPlus的设计将融券负债作为空头持仓对待,使用卖开仓指令进行融券卖出,买平仓指令进行买券还款。与其他交易业务保持了一致。
实时订单、实时持仓和实时资金
API只向用户实时推送订单状态、成交数据,并不会主动推送持仓和资金。用户可以发送查询请求获取,但是通常不这样做,因为查询请求受流控限制。更好的解决方案就是在本地维护实时持仓和资金数据。
虽然API实时推送订单数据,但是用户仍需要在本地维护所有订单列表。因为订单状态不变时API并不推送数据,此时就需要从本地订单列表中获取信息。
AlgoPlus的设计在登录时通过查询获取初始持仓、可用资金,成交发生时自动增减持仓数量,当平仓报单时自动增加冻结数量,当报撤单、出入金时自动增减可用资金。
智能交易指令
- 买卖智能开平指令
只关注买卖,不关注平仓还是开仓,优先平仓,无持仓的情况下再开仓。
除了buyOpen、sellClose、sellOpen、buyClose、closeLong、closeShort这些指定了开平方向的指令,其他都是智能开平指令。
例如,初始有5手多头持仓,其中2手昨仓、3手今仓,智能开平指令“卖10手”所执行的操作就是卖平2手昨仓,再卖平3手今仓,最后卖开5手。
- 调仓指令
经过一些列的操作将持仓调整为目标方向和数量。
balanceToLongVolume、balanceToLongVolume、balanceToShortValue、balanceToShortVolume都属于该类。
例如,初始有5手多头,其中2手昨仓、3手今仓,目标仓位是1手多头,所执行的操作就是卖平2手昨仓,再卖平2手今仓。
- 资金报单指令
以期货保证金或者股票市值为数量报单指令。
buyAmount、buyRatio、sellAmount、sellRatio、balanceToLongValue、balanceToShortValue都属于该类。
- 平仓/清仓指令
实际平仓数量限定于可平数量。支持平特定标的持仓,平某交易所品种持仓,以及平账户全部持仓。
closeLong、closeShort都属于该类。
项目demo是使用智能指令完成一系列复杂报单过程的例子(前提是初始有30手fu2109多头昨仓和30手fu2109空头昨仓)。指令顺序:
①buyOpen买开仓8手
②sellClose卖平昨2手
③sellClose卖平今2手
④sellOpen卖开仓8手
⑤buyClose买平昨2手
⑥buyClose买平今2手
⑦buy买30手
⑧buyAmount买6000元
⑨sell卖24手
⑩sellAmount卖6000元
⑪balanceToShortVolume调仓至10手空仓
⑫balanceToLongValue调仓至6000元多仓
⑬balanceToLongVolume调仓至10手多仓
⑭closeLong平1手多头持仓
⑮closeLong平所有手多头持仓
报单及成交过程,如图:
持仓动态变化过程,如图:
流控管理
所谓的流控就是禁止并发业务请求和限制每秒业务请求总量。这里的业务主要是指查询业务,报撤单等交易业务不受流控限制。
触发流控会导致业务执行失败,必须等流控限制解除之后再发起业务请求。不同经纪商的每秒总量参数也不同,例如比较严格的每秒只允许1-2笔查询请求,有些比较宽松会允许更多查询请求。
如果一项业务请求是不允许失败的,那么流控管理就显得格外重要,例如初始化时登录账户、查询订单、查询成交等。
AlgoPlus设计了一个任务队列,主要负责在流控的限定内执行一些对效率不敏感的业务。
举个简单的例子,前面提到AlgoPlus维护了实时资金,但是该数据并不精确。因为根据实时行情计算持仓盈亏变化是一件得不偿失的事情。这就需要通过查询进行矫正。使用AlgoPlus添加一个间隔5秒循环执行的查询资金任务只需要一行代码:
addTask(ENUM_CTPTaskID_QryTradingAccount, NULL, 9999999, MICROSECONDS_IN_SECOND * 5, false);
兼顾效率与易用性
不管是追求效率,还是易用性,交易者都可以找到合适的AlgoPlus方法。例如,buyOpen、sellClose、sellOpen、buyClose的设计就从效率出发,使用交易者的参数直接报单,这就要求交易者熟悉交易规则,否则可能会导致废单。
AlgoPlus还内置了默认的事件回调函数,缺省情况下自动展示所有响应信息,帮助初学者了解业务。交易者对业务足够熟悉之后可以根据需要修改事件回调所执行的逻辑,这并不会带来性能上的损耗。
AlgoPlus提供了将结构体转为字符串的方法,方便记录日志、操作数据库等。
仿真交易
实战前一定会经历过无数次演习,仿真系统就是量化交易开发的演习战场。目前市场上有两套比较成熟的仿真系统,分别是上期技术的SimNow和N视界的NSight。
AlgoPlus支持这两套仿真系统的账户,结合快期v2客户端,基本可以实现007式的开发、调试。
项目地址
Github https://github.com/KeyAlgo/AlgoPlus
Gitee https://gitee.com/AlgoPlus/AlgoPlus