在高频策略中,使用事件驱动的策略机制可以更快的获取行情数据以及订单信息,并且配合回调机制可以免去耗时任务函数调用的阻塞,可以实现高并发的策略机制,尤其适合于多品种的高频策略。
行情相应事件包括两类,分别是EventTick
和OrderTick
:
EventTick:{Event:"tick", Index:交易所索引, Nano:事件纳秒级时间, Symbol:合约名称, Ticker:行情数据}。
OrderTick:{Event:"order", Index:交易所索引, Nano:事件纳秒级时间, Order:订单信息}。
对于行情数据EventTick
数据结构大家可能都很熟悉,但是对于OrderTick
订单信息数据结构,大家可能比较陌生,从挂单,等待,交易成功或者撤单,这一系列流程EventTick
返回的数据存在一系列的流程,并且针对于仿真交易所(上期模拟)和真实的交易所,两者数据的返回结构存在一定的差别,本文就此展开一下解释。
def on_tick(symbol, ticker):
Log("symbol:", symbol, "update")
Log("ticker:", ticker)
def on_order(order):
Log("order update", order)
def main():
# wait connect trade server
while not exchange.IO("status"):
Sleep(10)
# switch push mode
exchange.IO("mode", 0)
# subscribe instrument
_C(exchange.SetContractType, "c2405")
while True:
e = exchange.IO("wait")
if e:
if e.Event == "tick":
on_tick(e['Symbol'], e['Ticker'])
elif e.Event == "order":
on_order(e['Order'])
这段代码是一个简单的交易策略的主程序,它实现了两个事件处理函数 on_tick
和 on_order
,以及一个主函数 main
。
on_tick
函数用于处理行情数据更新事件。当收到行情数据更新时,会打印出相关的 symbol 和 ticker 信息。
on_order
函数用于处理订单更新事件。当收到订单更新时,会打印出订单信息。
main
函数是主程序入口,其中的主要逻辑如下:
首先,程序会等待连接到交易服务器,这是通过 exchange.IO("status")
来判断连接状态的,直到连接成功才会继续执行后续逻辑。
连接成功后,程序将交易接口切换至推送模式(push mode),即交易所会主动推送行情和订单更新,而不需要主动去轮询查询。
接着,程序订阅了一个合约类型为 "c2405"
的合约,这表示程序将关注该合约的行情和订单更新。
最后,程序进入一个无限循环中,通过 exchange.IO("wait")
来等待交易所的事件。当收到事件时,程序会根据事件的类型(tick 或者 order)调用相应的处理函数进行处理。
总的来说,这段代码实现了一个基本的事件驱动型交易策略,它通过订阅行情和订单更新事件,并定义相应的处理函数来响应这些事件,从而实现了简单的交易逻辑。然后我们可以在交易终端里,手动的进行限价单挂单开仓/平仓,市价单挂单开仓/平仓,以及撤单的操作,我们来观察一下返回的OrderTick
信息流。
这里我们以玉米品种c2405
为例,首先以2400的价格挂了一个多单,可以看到StatusMsg
首先返回“报单已提交”,Offset
为0,代码开仓;Type
为0,代表买入,Status
为0,代表未成交,第一条信息代表“多头开仓挂单”;
随后第二条返回“未成交”信息;
等待一段时间后(1分钟左右),挂单成交,StatusMsg
返回“全部成交”,Status
返回1,代表“成功交易”,DealAmount
返回1,代表成功交易的数量为1;
最后返回一条信息,具体的属性为空,但是Type
和Offset
代表多头平仓,暂时不太理解这条信息返回是什么意思,如果有了解的大拿,可以说明一下。
以上,就是一个多头开仓返回的完整的四条信息,当然还有一些其他属性,大家有了解的可以说明下。
Time | ContractType | DealAmount | StatusMsg | Offset | Price | Status | Type |
---|---|---|---|---|---|---|---|
2024-04-11 13:34:14 | c2405 | 0 | 报单已提交 | 0 | 2400 | 0 | 0 |
2024-04-11 13:34:15 | c2405 | 0 | 未成交 | 0 | 2400 | 0 | 0 |
2024-04-11 13:35:11 | c2405 | 1 | 全部成交 | 0 | 2400 | 1 | 0 |
2024-04-11 13:35:11 | – | 0 | – | 1 | 0 | 0 | 1 |
对于平仓,也是以多头为例,基本上也是返回同样的流程,但是Offset
和Type
返回1,代表多头平仓。
Time | ContractType | DealAmount | StatusMsg | Offset | Price | Status | Type |
---|---|---|---|---|---|---|---|
2024-04-11 13:36:20 | c2405 | 0 | 报单已提交 | 1 | 2401 | 0 | 1 |
2024-04-11 13:36:20 | c2405 | 0 | 未成交 | 1 | 2401 | 0 | 1 |
2024-04-11 13:38:42 | c2405 | 1 | 全部成交 | 1 | 2401 | 1 | 1 |
2024-04-11 13:38:42 | – | 0 | – | 1 | 0 | 0 | 1 |
下面我们来看下撤单的信息返回,对于前两条信息返回的属性基本一致,但是当决定撤单时,首先会打印“未成交”的信息,然后再进行撤单,StatusMsg
返回“已撤单”,Status
返回2代表撤单。
Time | ContractType | DealAmount | StatusMsg | Offset | Price | Status | Type |
---|---|---|---|---|---|---|---|
2024-04-11 14:01:55 | rb2410 | 0 | 报单已提交 | 0 | 3600 | 0 | 0 |
2024-04-11 14:01:55 | rb2410 | 0 | 未成交 | 0 | 3600 | 0 | 0 |
2024-04-11 14:02:39 | rb2410 | 0 | 未成交 | 0 | 3600 | 0 | 0 |
2024-04-11 14:02:39 | rb2410 | 0 | 已撤单 | 0 | 3600 | 2 | 0 |
对于“限价单”和“市价单”,两个的信息返回基本一致,但是“市价单”里的price
会自动使用“涨/跌停”的价格进行挂单,所以下单速度很快,但是基本的信息返回仍是4条。
相对于真实的实盘交易,仿真交易所订单信息流的返回信息会有所区别,例如上期模拟为例,它的信息返回如下所示:
StatusMsg |
---|
报单已提交 |
报单已提交 |
全部成交报单已提交 |
全部成交报单已提交 |
因此我们要做相应的交易信息确认的时候,需要在程序中加以辨别和区分,这样才可以做到多品种事件驱动的有序进行,避免错误交易操作的执行。