记录学习CTP出现4097、8193报错,原文参考https://zhuanlan.zhihu.com/p/89263750
追根溯源
在客户端程序与期货公司行情、交易前置建立连接之后,服务器会定时发送心跳包确认连接是否正常。当网络连接出现异常,客户端可以在回调函数OnFrontDisconnected中收到通知:
///当客户端与交易后台通信连接断开时,该方法被调用。当发生这个情况后,API会自动重新连接,客户端可不做处理。
///@param nReason 错误原因
/// 0x1001 网络读失败 4097
/// 0x1002 网络写失败 4098
/// 0x2001 接收心跳超时 8193
/// 0x2002 发送心跳失败 8194
/// 0x2003 收到错误报文 8195
void OnFrontDisconnected(int nReason) {};
交易者最常遇到的就是4097(十六进制:0x1001)和8193(十六进制:0x2001)报错。
如果网络异常,很容易发现问题。
但是初次使用CTP的交易者会发现,在网络正常情况下,也会报这个错误。究竟是哪里出了问题呢?
其实,这是不熟悉CTP异步执行特性导致的。
CTP所有的方法都是异步执行的,也就是说,调用一个方法返回时,该方法并没有执行完成,而是刚开始执行。如果主线程没有等待子线程执行完成就结束了,会触发OnFrontDisconnected错误。
网络正常情况下使用AlgoPlus重现该问题
from AlgoPlus.CTP.MdApi import MdApi
class TickEngine(MdApi):
#5-8行
# def __init__(self, md_server, broker_id, investor_id, password, app_id, auth_code
# , instrument_id_list, md_queue_list=None
# , page_dir='', using_udp=False, multicast=False):
# self.Join()
# ///深度行情通知
def OnRtnDepthMarketData(self, pDepthMarketData):
print(pDepthMarketData)
if __name__ == '__main__':
import sys
sys.path.append("..")
from account_info import my_future_account_info_dict
future_account = my_future_account_info_dict['SimNow']
tick_engine = TickEngine(future_account.server_dict['MDServer']
, future_account.broker_id
, future_account.investor_id
, future_account.password
, future_account.app_id
, future_account.auth_code
, future_account.instrument_id_list
, None
, future_account.md_page_dir)
# 30行
# tick_engine.Join()
网络正常情况下的解决方案
解决办法很简单,就是在主线程结束之前调用Join方法,等待子线程执行。
将以上5-8行代码的注释取消,或者在30行之后调用tick_engine的Join方法,就正常了。
网络异常情况下的解决方案
无需做其他处理,等待CTP自动重连,重连成功后自动登录账户,然后就可以正常使用了。
MdApi同样会自动重连,且重连成功后自动登录账户,但是需要重新订阅行情,否则不会收到断开前订阅的行情数据。
AlgoPlus已封装了MdApi重连成功时订阅合约的功能。