无法通过TWS API获取历史数据,请求排查问题
问题原因及解决办法
核心错误原因分析
首次运行报错
- ERROR 10 320:
endDateTime参数格式不符合TWS API要求。你用datetime.datetime.today().strftime("%Y%m%d %H:%M:%S %Z")生成的带时区字符串,TWS无法解析,导致请求读取失败。 - historic_data_queue.timed_out:请求解析错误导致TWS未返回任何历史数据,队列超时后返回空数据。
- ValueError: Length mismatch:空数据创建DataFrame后,试图给0行数据设置6个列名,引发长度不匹配错误。
- ERROR -1 504:请求失败可能导致连接异常中断,或初始连接未成功就执行了后续操作。
第二次运行报错_queue.Empty
首次运行的异常导致连接或队列状态异常,未正确清理资源,二次请求时队列无数据可读取。
具体解决步骤
1. 修正endDateTime参数格式
TWS API要求endDateTime为空字符串(表示获取到最新数据),或使用不带时区的YYYYMMDD HH:mm:ss格式。修改reqHistoricalData中的对应参数:
# 替换原endDateTime行 "", # endDateTime,留空表示获取到当前最新数据
2. 增加空数据判断,避免列名赋值错误
在创建DataFrame前检查数据是否为空,提前处理:
historic_data = historic_data_queue.get(timeout = MAX_WAIT_SECONDS) if historic_data_queue.timed_out(): print("historic_data_queue.timed_out") # 返回空DataFrame或直接退出,避免后续报错 return pd.DataFrame(columns=['Datetime', 'Open', 'High', 'Low', 'Close', 'Volume']) self.cancelHistoricalData(tickerid) df = pd.DataFrame(historic_data) df.columns = ['Datetime', 'Open', 'High', 'Low', 'Close', 'Volume']
3. 修复连接等待逻辑,避免未连接就执行操作
不要用time.sleep(1234)等待连接,改用API的连接成功回调确认状态。修改main函数:
if __name__ == '__main__': app = App_Class('127.0.0.1',7497, 11) # 等待连接成功(需要App_Class实现连接成功的回调标记) # 示例:假设App_Class有is_connected属性,等待连接 import time while not app.is_connected: time.sleep(0.1) ibcontract = IBcontract() ibcontract.secType = 'FUT' ibcontract.lastTradeDateOrContractMonth = '20221129' ibcontract.symbol = 'HSI' ibcontract.exchange = 'HKFE' resolved_ibcontract = app.resolve_ib_contract(ibcontract) print(resolved_ibcontract) df = app.get_IB_historical_data(resolved_ibcontract, 10, durationStr='30 D', barSizeSetting='1 D') print(df)
注:需要在你的App_Class中实现连接成功的回调,比如重写connectionClosed、connectionSuccess方法,设置is_connected标记。
4. 检查TWS/IB Gateway的API设置
确保:
- TWS或IB Gateway已启动,端口设置为7497(对应paper交易,实盘端口通常为7496)
- 开启
Active X and Socket Clients选项(TWS:编辑->全局配置->API->设置) - 勾选
允许来自本地主机的连接,或添加你的IP到允许列表
5. 确保队列回调逻辑正确
检查init_historicprices方法,确保它正确绑定了tickerid对应的historicalData回调,将收到的K线数据添加到队列中。示例回调逻辑:
def init_historicprices(self, tickerid): data = [] def callback(tickerId, bar): if tickerId == tickerid: data.append([bar.date, bar.open, bar.high, bar.low, bar.close, bar.volume]) self.historicalData = callback return data
内容的提问来源于stack exchange,提问作者Ho Chuen Cheung
相关产品推荐
相关产品推荐

