终于,终于,终于!!!!
博主千辛万苦把CTP 8193心跳超时导致程序崩溃的问题解决了!!!!!经历了一天一夜的测试后,第二天亲眼看到CTP返回了8193错误后,我的程序没有崩溃!第二天早上9:00一到,又自己正常运行了。敲开心~~~
博主的血泪史,就是搜遍国内外全网,不止博主一个人遇到8193后程序崩溃,但只有提问8193错误的,没有一个回答8193错误的解决方法。所以博主就决定了,一旦等到博主解决8193错误那一日,就一定要把解决方法公诸于世!
先说一说博主的8193错误导致崩溃的原因。
众所周知,8193错误就是CTP当中的,一旦引发,ctp就会调用回调函数“onFrontDisconnected”,返回错误码(目前博主见得最多的就是4097和8193)。
这个时候根据上期所官方CTP_API接口原文,API会自动重新连接,客户端理论上可以不做任何处理。
但是!!博主要说,这边所谓的不做处理,是指不用做任何重新连接前置机的处理。
CTP虽然会帮我们自动重连前置机(前提是,你之前注册的前置列表里的前置机可以连接得上,注册多个前置机方法详见博主的另外一篇文章:https://blog.csdn.net/mooncrystal123/article/details/83269296),但是CTP不会帮我们重新登录!
然而,CTP的业务API必须要登陆后才能使用!登录后才能使用!!登陆后才能使用!!!
重要的事情说三遍。
业务API就是下单啊,查询账户余额啊,查询市场最新tick行情啊等等等…………
所以博主的崩溃来自于两个方面
1. 前期
只注册了一个前置机,前置机坏掉后,无法重连,导致下单查询的业务线程无法获得必须的返回结果属性,导致后续业务逻辑报attributeError失败,崩溃。
2. 后期
注册了一堆前置机,但是重连后没登录,导致业务逻辑线程进入死循环,线程无法自动停止。
注册了一堆前置机,但是登陆方法写在了CTP的回调函数当中,然后登陆失败,导致程序崩溃。
所以,综上所述,博主经过多番实验找到了办法。
首先,最重要的就是在回调函数中不加任何重新登录的方法,只负责打印或者记录CTP断连后onFrontDisconnected返回的错误码,然后等待CTP自动重连,重连成功后CTP会调用onFrontConnected。
注:self.logoutCode是博主自设的用来鉴别是手动登出时导致的断连还是CTP自身原因导致的断连。
def onFrontDisconnected(self,n):
# n的type是int
print(n)
# 手动登出
if self.logoutCode == 1:
self.onFrontDisconnectedCode = 0
else:
self.onFrontDisconnectedCode = n
def onFrontConnected(self):
"""服务器连接"""
print("onFrontDisconnectedCode: " + str(self.onFrontDisconnectedCode))
CTP调用回调函数的时候,会自动开启一个新线程来处理,我们称之为A线程。
然后,我们要做的就是把重新登录的方法写在我们程序运行的线程里面,默认就是B线程。
下面就是我自己封装的CTP类的断连检查+重新登录的方法。
# 断连状态检查:给所有的业务类方法前加上去
def reloginCheck(self):
stat = 0
# 查看前置机是不是自己断连过
if self.api.onFrontDisconnectedCode != 0:
loginReq = {} # 创建一个空字典
loginReq['UserID'] = self.userid
loginReq['Password'] = self.password
# loginReq['BrokerID'] = '9999'
loginReq['BrokerID'] = self.brokerid
self.reqid = self.reqid + 1 # 请求数必须保持唯一性
self.api.reqUserLogin(loginReq, self.reqid)
sleep(1)
if hasattr(self.api,'loginErrorID'):
if self.api.loginErrorID == 0:
stat = 1
# 前置机没有断连过
else:
stat = 1
print('relogstat: '+str(stat))
return stat
这个方法在业务逻辑中插入的位置:
# 判断simnow是否开启
if simnowStat == 1:
frontStat = sarProjectTest.Api.reloginCheck()
# 检查CTP是否断连
if frontStat == 1:
while optSuccess == 0:
sarProjectTest.Api.BuyOpen(self.id, num)
orderResult = self.ordertools.orderInsertJudge(sarProjectTest.Api.api,num,1)
optSuccess = orderResult['optSuccess']
if optSuccess == 0:
print('下单失败')
self.apptools.logGenerate('买开下单失败')
# 未开启simnow
else:
optSuccess = 1
---------------------
作者:mooncrystal123
来源:CSDN
原文:https://blog.csdn.net/mooncrystal123/article/details/83269296
版权声明:本文为博主原创文章,转载请附上博文链接!
通过这样的处理,即使CTP报8193或者4097,我们的程序也不会崩溃,可以等待CTP重连。