|
本文讨论一下数据监听线程和订单管理线程做些什么。
一,数据监听线程
数据监听线程,当行情处理线程接收到新的行情数据时,也就是每当一个tick到来时,就向数据监听线程发出信号,触发此线程启动,然后依次进行:
1.各种指标计算,
2.然后进行策略计算,
3.最后在满足策略时进行交易。
指标计算,就是指根据新到来的数据以及历史数据进行某些统计值的计算,比如常见的MA,MACD,RSI等,当然也可以自己构造出某个统计值。这里需要提到的是数据周期的问题(我在之前的博文中曾解释过)。如果指标计算是基于数据周期,那么对于行情数据就要进行数据的拼装,也就是说将每一tick数据(500毫秒)拼装成你所需要的数据周期(也就是拼装成K线),然后将每个周期(每根k线)中的open,high,low,close计算出来,以便进行统计值的计算。
策略计算就是将你的计算出来的指标,按照你自己的交易思想,交易策略进行逻辑的组合,然后在满足策略逻辑的时候进行交易。
这里我建议一下架构,就是不要将指标计算和策略计算以及交易写到一个函数里面,而是将每一个指标计算写成一个函数,然后分别用函数指针指向它;然后策略计算以及交易写成一个函数,然后用函数指针指向它,并将其压入一个堆栈,此后每添加一个指标,就将指标对应的函数指针压入堆栈;
当每次数据监听线程启动时就依次弹出每个指标并计算,最后完成策略函数。
二,订单管理线程
订单管理线程,主要是用于处理订单管理中的两个问题:
1.订单队列的管理,一般按照报单的时间先后顺序用数组等数据结构进行管理,原则是每一个业务请求要准确对应其回报,每一组请求和回报要准确的对应其归属的订单。其关键就在于业务请求编号和交易序列号。
业务请求号是指发送请求时设定的RequestID,TraderApi返回响应时返回相关请求的RequestID。因为TraderApi是异步实现的,终端程序可能连续发出多个请求和查询指令。RequestID可以把请求/查询指令和相关的回报关联起来。
而交易序列号是组合而成的。从报单到成交的交易过程中,会产生如下几组交易序列号:
FrontID + SessionID + OrderRef
用户使用这组交易序列号可以按照自己的方式来唯一标示发出的任何一笔委托。用户登入成功后,会收到前置机编号FrontID, 会话编号SessionID 和最大报单引用MaxOrderRef。用户在报单时设定报单引用OrderRef。 OrderRef可以从MaxOrderRef开始递增。如果用户没有设定OrderRef,在报单响应中,Thost会为用户设置一个的OrderRef。使得每个报单的这组序列号保持唯一。
通过这个交易序列号,就可以确定委托回报和成交回报的归属,也可以使用这组交易序列号进行撤单操作。
2.订单的各种状态的管理:在回报中,订单的状态有很多种,请参考ThostFtdcUserApiDataType.h,我建议根据其含义归纳为这五种状态:报单中,已成交,撤单中,已撤单,出错,因为这五种状态对于策略逻辑的完成是至关重要的。
下面说一下订单交易的机制与时序。先给出一个时序图:
其中,报单响应和回报的机制是当Thost收到报单指令,如果没有通过参数校验,拒绝接受报单指令。用户就会收到OnRspOrderInsert消息,其中包含了错误编码和错误消息。如果Thost接受了报单指令,用户不会收到OnRspOrderInser,而会收到OnRtnOrder,用来更新委托状态。交易所收到报单后,通过校验。用户会收到OnRtnOrder、OnRtnTrade。如果交易所认为报单错误,用户就会收到OnErrRtnOrder。
撤单响应和回报和报单响应和回报相似。当Thost收到撤单指令,如果没有通过参数校验,拒绝接受撤单指令。用户就会收到OnRspOrderAction消息,其中包含了错误编码和错误消息。如果Thost接受了撤单指令,用户不会收到OnRspOrderAction,而会收到OnRtnOrder,用来更新委托状态。交易所收到撤单后,通过校验,执行了撤单操作。用户会收到OnRtnOrder。如果交易所认为报单错误,用户就会收到OnErrRtnOrderAction。
|
|