跳转到内容

接收错误消息

Python 版 ibapi 通过 EWrapper.error() 接收错误和系统信息。不同 API 版本下,error() 的参数形态可能略有差异,当前 TWS API 常见新版签名会带 errorTime

def error(self, reqId, errorTime, errorCode, errorString, advancedOrderRejectJson=""):
print(reqId, errorTime, errorCode, errorString)

如果你看到脚本报 TypeError: error() takes ... positional arguments,通常是回调签名和安装的 API 版本不匹配。

def error(self, reqId, *args):
if len(args) == 2:
errorCode, errorString = args
errorTime = None
advancedOrderRejectJson = ""
elif len(args) >= 3:
errorTime, errorCode, errorString = args[:3]
advancedOrderRejectJson = args[3] if len(args) >= 4 else ""
else:
return
print({
"reqId": reqId,
"errorTime": errorTime,
"errorCode": errorCode,
"errorString": str(errorString),
"advancedOrderRejectJson": advancedOrderRejectJson,
})

这个写法适合教学脚本和调试脚本。正式项目里可以固定使用安装版本对应的签名,并在升级 API 后重新跑最小检查脚本。

字段中文含义用途
reqId请求编号定位是哪一个行情、合约、历史数据或订单请求出错。
errorTime错误时间新版回调可能提供,便于对照日志。
errorCode错误代码程序判断主要依据。
errorString错误文本给人阅读,可能随语言设置变化。
advancedOrderRejectJson高级拒单信息订单被拒时可能包含更细原因。
INFO_CODES = {2103, 2104, 2105, 2106, 2107, 2108, 2158}
def error(self, reqId, errorTime, errorCode, errorString, advancedOrderRejectJson=""):
row = {
"reqId": reqId,
"code": errorCode,
"message": str(errorString),
}
if errorCode in INFO_CODES:
self.info_messages.append(row)
else:
self.error_messages.append(row)

调试时建议把两类消息分开保存。否则大量 21042106 会把真正的请求错误淹没。

不同 API 版本、不同语言绑定、不同消息来源下,error() 回调参数可能不完全一样。教学脚本可以使用上面的兼容写法;正式项目应固定使用安装版本对应的签名,并在升级 TWS API 后重新跑最小连接和错误样本测试。

无效合约和 AAPL 行情权限请求会进入同一个 error() 回调,输出结构如下:

ERROR=reqId=99101;code=200;msg=未找到该请求的证券定义
ERROR=reqId=99102;code=10168;msg=请求的市场数据没有订阅。延迟市场数据未启用。
ERROR=reqId=99102;code=300;msg=无法使用tickerId找到EId::99102

这里最重要的是保留 reqId。同一个脚本里可能同时有合约详情、行情、历史数据、订单和取消请求,只有 reqId 能把错误准确对应回原请求。