博主的血泪史,就是搜遍国内外全网,不止博主一个人遇到8193后程序崩溃,但只有提问8193错误的,没有一个回答8193错误的解决方法。所以博主就决定了,一旦等到博主解决8193错误那一日,就一定要把解决方法公诸于世!
先说一说博主的8193错误导致崩溃的原因。
众所周知,8193错误就是CTP当中的,一旦引发,ctp就会调用回调函数“onFrontDisconnected”,返回错误码(目前博主见得最多的就是4097和8193)。
这个时候根据上期所官方CTP_API接口原文,API会自动重新连接,客户端理论上可以不做任何处理。
CTP虽然会帮我们自动重连前置机(前提是,你之前注册的前置列表里的前置机可以连接得上,注册多个前置机方法详见博主的另外一篇文章:https://blog.csdn.net/mooncrystal123/article/details/83269296),但是CTP不会帮我们重新登录!
重要的事情说三遍。
业务API就是下单啊,查询账户余额啊,查询市场最新tick行情啊等等等…………
所以博主的崩溃来自于两个方面
1. 前期
只注册了一个前置机,前置机坏掉后,无法重连,导致下单查询的业务线程无法获得必须的返回结果属性,导致后续业务逻辑报attributeError失败,崩溃。
2. 后期
注册了一堆前置机,但是重连后没登录,导致业务逻辑线程进入死循环,线程无法自动停止。
注册了一堆前置机,但是登陆方法写在了CTP的回调函数当中,然后登陆失败,导致程序崩溃。
注: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线程。
下面就是我自己封装的CTP类的断连检查+重新登录的方法。
博主对不起大家啊~~4月的时候做测试,查出来重登的方法有点问题,然后我自己程序修改了,但是一直没有修改博文,今天发现看的人真的挺多的,心想不能再继续放着旧代码不管了。大家按照新的方法来,保证行。
2019-5-17 正确版本:————————————
def reloginCheck(self):
# 查看前置机是不是自己断连过
if self.api.onFrontDisconnectedCode != 0:
stat = 0
'''在这里登录用self.api.reqUserLogin没用的……要在业务线程里用业务线程里对应的用来下单的那个类去登录'''
# 前置机没有断连过
else:
stat = 1
print('relogstat: '+str(stat))
return stat
——————————————————————————
以下是错误版本!!注意!!
错误版本—————————————————————————割割巫————————————————————
# 断连状态检查:给所有的业务类方法前加上去
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
错误版本—————————————————————————割割巫————————————————————
2019-5-17 修改:正确版———————以买开为例———————
看到当中的“frontStat”的检查了吗?? 和frontStat 不等于1 时进行重登的方法了吗?用的是之前被前置机踢下线的那个具体的类:sarProjectTest.Api
登录方法Login()就是之前自己封装过的login,反正就是你之前咋登陆的,这里你就咋登陆。
# single买开
def singleBuyOpen(self):
optSuccess = 0
optcode = 0
while optSuccess == 0:
frontStat = sarProjectTest.Api.reloginCheck()
# 检查CTP是否断连
if frontStat != 1:
logSuccessStat = sarProjectTest.Api.Login()
else:
logSuccessStat = 1
if logSuccessStat != 0:
sarProjectTest.Api.BuyOpen(self.id, self.num)
orderResult = self.ordertools.orderInsertJudge(sarProjectTest.Api.api, self.num, 1)
optSuccess = orderResult['optSuccess']
if optSuccess == 0:
print('下单失败')
self.apptools.logGenerate('买开下单失败')
longing = lastLonging
else:
# 重登失败
print('下单simnow重登失败')
self.apptools.logGenerate('下单simnow重登失败')
sarProjectTest.ctpLogStat = 0
break
if optSuccess == 1:
self.postCat = "买入开仓"
optcode = 1
result = {'optcode':optcode,'optSuccess':optSuccess}
return result
——以上是正确版——————————————————————————————————
错误版本——————————割割巫——————————————————
# 判断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重连。
还要提醒一句,大家过夜的时候要登出CTP,正确登出CTP的方法在使用logOut之后,要release你的Api。
具体代码看我这篇文章,关键词搜索:“self.api.release()”
https://blog.csdn.net/mooncrystal123/article/details/83269296