使用ib_insync订阅IBKR流数据后pendingTickersEvents未触发求助
问题分析与解决
你的代码存在几个关键问题导致pendingTickersEvent无法触发:
线程与asyncio循环不兼容
ib_insync的IB实例是在主线程创建的,它绑定的是主线程的asyncio事件循环。你在子线程里新建循环并设置,会导致ib的消息处理机制混乱,无法正常接收推送的行情数据。阻塞式循环抢占线程资源
stream_data里的while True: sleep(1)是阻塞式操作,会完全占用子线程,ib没有机会运行内部的事件循环来处理行情推送。主线程提前退出
主线程sleep 150秒后直接结束,整个程序会终止,可能还没等到行情事件触发就退出了。
修正后的代码示例
import asyncio from datetime import datetime import pytz from ib_insync import IB, Stock def _on_connected_event(): print(f"Connected to IB!") def _on_pending_tickers_event(tickers): print(f"In tickers event") for t in tickers: print(t) def stream_data(ib: IB, contract): # 直接请求行情数据,不需要手动创建循环 ib.reqMktData(contract, '', True, True) # 用ib的内置方法运行事件循环,替代手动sleep循环 ib.run() if __name__ == '__main__': ib = IB() ib.connectedEvent += _on_connected_event ib.pendingTickersEvent += _on_pending_tickers_event # 连接IB,指定timeout参数确保连接成功 ib.connect('127.0.0.1', port=7497, clientId=1, timeout=30) stock = Stock(symbol="SPY", exchange="SMART", currency="USD") # 不需要子线程,直接调用stream_data try: stream_data(ib, stock) except Exception as e: print(f"Error: {e}") ib.cancelMktData(stock) ib.disconnect()
关键改动说明
- 移除子线程和手动循环:ib_insync自带
ib.run()方法,会启动内部的asyncio事件循环,持续处理消息和事件,不需要手动创建线程或阻塞式sleep。 - 简化流程:直接在主线程中调用
stream_data,让ib的事件循环正常运行,确保能接收行情推送。 - 增加异常处理与资源清理:捕获异常后取消行情订阅并断开连接,避免资源泄漏。
如果需要在后台运行行情监听同时执行其他任务,也可以用异步写法,更贴合ib_insync的设计逻辑:
async def main(): await ib.connect('127.0.0.1', port=7497, clientId=1, timeout=30) ib.reqMktData(stock, '', True, True) while True: await asyncio.sleep(1) print(f"{datetime.now(tz=pytz.timezone('US/Eastern'))}") if __name__ == '__main__': ib = IB() ib.connectedEvent += _on_connected_event ib.pendingTickersEvent += _on_pending_tickers_event stock = Stock(symbol="SPY", exchange="SMART", currency="USD") ib.run(main())
内容的提问来源于stack exchange,提问作者Mubbashir Ali
相关产品推荐
相关产品推荐

