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

使用ib_insync获取盈透证券逐笔数据时陷入无限循环求助

解决ib_insync获取逐笔数据时的无限循环问题

问题场景

使用ib_insync编写Python脚本从盈透证券(Interactive Brokers/TWS)获取单日逐笔数据,预期逻辑为:每次请求1000条逐笔数据,将最新tick的时间作为下一次请求的起始时间,循环直至达到结束时间。但实际脚本陷入无限循环,每次请求返回的最新tick时间始终固定,导致起始时间无法推进,重复请求相同数据。

原函数代码

def ticker_data(ticker, start, end='',numberOfTicks=1000, Exchange='SMART', Currency='USD', ip='127.0.0.1', port=7496, clientId=1):
    ib = IB()
    ib.connect(ip, port, clientId=clientId)

    contract = Stock(ticker, Exchange, Currency)

    real_end = start
    df = pd.DataFrame()

    while end != real_end:
        ticks = ib.reqHistoricalTicks(contract,
                                      startDateTime=real_end,
                                      endDateTime=end,
                                      numberOfTicks=numberOfTicks,
                                      whatToShow='TRADES',
                                      useRth=True)

        df = pd.concat([df, util.df(ticks)], ignore_index=True)
        print("Latest time in DataFrame:", df.iloc[-1]['time'])
        print("Updated real_end_1:", real_end)
        print("End time:", end)
        print("length of recived_data:", len(ticks))
        print()


        real_end = datetime.strptime(str(df.iloc[-1]['time']), "%Y-%m-%d %H:%M:%S%z").strftime("%Y%m%d %H:%M:%S")#+' US/Eastern'

    ib.disconnect()
    return df

原调用代码

from functions.simple_ib_data import ticker_data
from datetime import datetime, timedelta

import pandas as pd

start = (datetime.now() - timedelta(days=1)).replace(hour=9, minute=30, second=0, microsecond=0).strftime("%Y%m%d %H:%M:%S")
end = (datetime.now() - timedelta(days=1)).replace(hour=23, minute=59, second=59, microsecond=0).strftime("%Y%m%d %H:%M:%S")

data = ticker_data(ticker="NCLH", start=start, end=end)
print(data)

问题原因

  1. 时区信息丢失:处理real_end时,将带时区的时间格式化为不带时区的字符串,IB的API无法正确解析时间范围,导致每次请求都从错误的起始点获取数据。
  2. 循环终止条件失效:直接比较字符串格式的时间,忽略了时区、毫秒级精度的差异,即使时间已经到达结束点,条件依然成立。
  3. 未处理空数据情况:当没有更多数据返回时,未终止循环,会继续重复请求同一范围的数据。

修复后的代码

from datetime import datetime, timezone, timedelta
import pandas as pd
from ib_insync import IB, Stock, util

def ticker_data(ticker, start, end='', numberOfTicks=1000, Exchange='SMART', Currency='USD', ip='127.0.0.1', port=7496, clientId=1):
    ib = IB()
    ib.connect(ip, port, clientId=clientId)

    contract = Stock(ticker, Exchange, Currency)

    # 将起始/结束时间字符串转为UTC时区的datetime对象
    start_dt = datetime.strptime(start, "%Y%m%d %H:%M:%S").replace(tzinfo=timezone.utc)
    end_dt = datetime.strptime(end, "%Y%m%d %H:%M:%S").replace(tzinfo=timezone.utc)
    current_start = start_dt
    df = pd.DataFrame()

    while current_start < end_dt:
        # 使用带时区的时间字符串作为请求参数
        ticks = ib.reqHistoricalTicks(
            contract,
            startDateTime=current_start.strftime("%Y%m%d %H:%M:%S %Z"),
            endDateTime=end_dt.strftime("%Y%m%d %H:%M:%S %Z"),
            numberOfTicks=numberOfTicks,
            whatToShow='TRADES',
            useRth=True
        )

        if not ticks:
            # 无新数据时终止循环
            print("No more ticks to fetch.")
            break

        tick_df = util.df(ticks)
        df = pd.concat([df, tick_df], ignore_index=True)
        print(f"Latest time in DataFrame: {tick_df.iloc[-1]['time']}")
        print(f"Current start time: {current_start}")
        print(f"End time: {end_dt}")
        print(f"Number of ticks received: {len(ticks)}")
        print()

        # 更新起始时间为最后一条tick的时间+1微秒,避免重复获取同一条数据
        current_start = tick_df.iloc[-1]['time'] + timedelta(microseconds=1)

    ib.disconnect()
    return df

关键修改点

  • 时区统一:将起始、结束时间转为UTC时区的datetime对象,请求时使用带时区的字符串格式,确保IB API正确解析时间范围。
  • 循环条件优化:用带时区的datetime对象比较current_start < end_dt,避免字符串比较的精度问题。
  • 空数据处理:判断ticks为空时直接终止循环,避免无效请求。
  • 避免重复数据:更新current_start时给最后一条tick的时间加1微秒,确保下一次请求从下一个tick开始。

修改后的调用代码

无需调整原调用代码,确保生成的start和end字符串格式正确即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 19:43:23