You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TWS API请求参数错误时脚本冻结问题求助

TWS API历史数据请求参数错误时脚本挂起的解决方法

问题描述

使用Python的IB API调用reqHistoricalData()获取历史数据时,参数正确情况下脚本可正常执行结束;但传入错误参数(例如contract.currency = 'US')时,控制台会输出错误:

ERROR 123 321 Request validation failed. -'bS' : cause - US currency is not allowed

但脚本会无限挂起,必须手动停止才能终止。

问题原因

代码中通过while not app.data_end:循环等待数据获取完成,而data_end仅在historicalDataEnd回调中被设置为True。当参数验证失败时,TWS不会触发historicalDataEnd回调,导致data_end始终为False,循环无限执行。

解决方案

1. 实现error回调捕获请求错误

重写EWrapper的error方法,捕获TWS返回的错误信息,并触发终止循环的条件。

2. 添加超时机制

为等待循环设置超时时间,避免因异常情况(如网络问题导致错误回调未触发)导致脚本永久挂起。

修改后的代码示例

from ibapi.client import EClient
from ibapi.wrapper import EWrapper
from ibapi.contract import Contract
from ibapi.order import Order
import pandas as pd
import threading
import time


class IBapi(EWrapper, EClient):
    def __init__(self):
        EClient.__init__(self, self)
        self.open_orders = list()
        self.historical_data = list()
        self.df = None
        self.data_end = False
        self.error_occurred = False  # 标记是否发生错误
        self.error_msg = ""  # 存储错误信息

    def nextValidId(self, orderId: int):
        super().nextValidId(orderId)
        self.nextorderId = orderId
        print('The next valid order id is: ', self.nextorderId)

    def openOrder(self, orderId, contract, order, orderState):
        self.open_orders.append(('OpenOrder ID:', orderId, contract.symbol, contract.secType, '@',
                                 contract.exchange, ':', order.action, order.orderType, order.totalQuantity,
                                 orderState.status))

    def historicalData(self, reqId, bar):
        self.historical_data.append(vars(bar))

    def historicalDataUpdate(self, reqId, bar):
        line = vars(bar)
        self.df.loc[pd.to_datetime(line.pop('date'))] = line

    def historicalDataEnd(self, reqId: int, start: str, end: str):
        self.df = pd.DataFrame(self.historical_data)
        self.data_end = True

    def error(self, reqId, errorCode, errorString):
        print(f"ERROR {reqId} {errorCode} {errorString}")
        # 针对历史数据请求的错误(reqId=123),触发终止条件
        if reqId == 123:
            self.error_occurred = True
            self.data_end = True
            self.error_msg = errorString


class Connect:
    app = None

    def __init__(self):
        self.app = IBapi()
        self.app.connect('127.0.0.1', 7497, 123)

        api_thread = threading.Thread(target=self.run_loop, daemon=True)
        api_thread.start()

        time.sleep(1)
        print('Соединились')

    def run_loop(self):
        self.app.run()


def get_historical_data(symbol, sectype, exchange, currency, duration=None, barsize=None,
                        whattoshow=None, enddatetime=None, userth=None, format_date=None) -> list:
    print('\nGET HISTORY\n-------------------------------')

    app = Connect().app

    contract = Contract()
    contract.symbol = symbol
    contract.secType = sectype
    contract.exchange = exchange
    contract.currency = currency

    format_date = format_date or 1
    enddatetime = enddatetime or ''
    barsize = barsize or '1 hour'
    duration = duration or '1 D'
    whattoshow = whattoshow or 'BID'
    userth = userth or 1

    app.reqHistoricalData(reqId=123, contract=contract, endDateTime=enddatetime, durationStr=duration,
                          barSizeSetting=barsize, whatToShow=whattoshow, useRTH=userth, formatDate=format_date,
                          keepUpToDate=False, chartOptions=[])

    # 带超时的等待循环
    start_time = time.time()
    timeout = 10  # 自定义超时时间(秒)
    while not app.data_end:
        time.sleep(1)
        if time.time() - start_time > timeout:
            print("请求超时,终止循环")
            app.data_end = True
            app.error_occurred = True
            app.error_msg = "请求超时"

    # 根据状态返回结果或错误提示
    if app.error_occurred:
        print(f"请求失败: {app.error_msg}")
        result = []
    else:
        result = app.df.to_dict('records')
        print(result)

    app.disconnect()
    return result


if __name__ == '__main__':
    # get_historical_data(symbol='EUR', sectype='CASH', exchange='IDEALPRO', currency='USD')
    get_historical_data(symbol='EUR', sectype='CASH', exchange='IDEALPRO', currency='US')  # 错误参数测试

关键修改说明

  • 新增错误处理回调:通过error方法捕获请求错误,当对应reqId的历史数据请求出错时,设置data_end=True终止等待循环,并记录错误信息。
  • 超时机制:设置固定超时时间,避免因异常情况导致脚本永久挂起。
  • 错误状态判断:在返回结果前判断是否发生错误,返回对应空列表或错误提示,保证脚本流程正常结束。

内容的提问来源于stack exchange,提问作者Eldellano

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 07:45:51