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

IB API无法将ES合约RTH/ETH时段历史行情存入Excel的求助

问题排查与修复方案

核心问题定位

你的代码中historicalData回调未触发,大概率是合约定义错误、API请求参数不合理、缺少错误回调无法定位问题,或是使用了过期合约导致的。

具体修复步骤

1. 必须添加错误回调函数

IB API会通过error回调返回所有异常信息(如合约无效、权限不足、请求参数错误等),你之前没有实现这个函数,根本看不到问题所在。在HistoricalDataApp类中添加:

def error(self, reqId, errorCode, errorString):
    print(f"Error {reqId}: {errorCode} - {errorString}")

2. 修正ES期货合约参数

  • ES期货的电子盘交易所是GLOBEX,而非CME(CME是实体交易所,API里需要指定电子盘代码)
  • 你使用的202309合约已过期,必须替换为当前活跃合约月份(比如2024年可使用202409,或通过reqContractDetails自动查询活跃合约)
    修改后的合约定义:
contract = Contract()
contract.symbol = "ES"
contract.secType = "FUT"
contract.exchange = "GLOBEX"  # 修正为电子盘交易所
contract.currency = "USD"
contract.lastTradeDateOrContractMonth = "202409"  # 使用当前活跃合约月份

3. 调整历史数据请求参数

  • useRTH参数设为0:你之前设为1,只会请求常规交易时段(RTH)的数据;且如果用1 day粒度,日线bar无法区分RTH/ETH时段——要区分时段,需改用更小的时间粒度(比如1 hour或1 min)
  • 先缩短时间范围(比如30 D)测试,避免请求超时;whatToShow可先改用MIDPOINT测试权限问题
    修改后的请求代码:
# 改用1小时粒度,才能区分RTH(9:30-16:00美东时间)和ETH时段
app.reqHistoricalData(
    reqId=1,
    contract=contract,
    endDateTime="",
    durationStr="30 D",
    barSizeSetting="1 hour",
    whatToShow="MIDPOINT",
    useRTH=0,  # 0=请求全天数据(含盘后)
    keepUpToDate=False,
    chartOptions=[],
    formatDate=1
)

4. 修正时段判断逻辑

美东时间RTH时段是9:30-16:00,你之前只判断bar.time == "16:00:00"完全错误,需根据bar的时间范围区分:

def historicalData(self, reqId, bar):
    if reqId != 1:
        return
    bar_datetime = bar.date
    # 美东时间RTH:9:30-16:00
    is_rth = False
    if bar_datetime.hour > 9 and bar_datetime.hour < 16:
        is_rth = True
    elif bar_datetime.hour == 9 and bar_datetime.minute >= 30:
        is_rth = True
    elif bar_datetime.hour == 16 and bar_datetime.minute == 0:
        # 16:00属于RTH收盘时段
        is_rth = True

    data_row = [bar_datetime.strftime("%Y-%m-%d %H:%M:%S"), bar.open, bar.high, bar.low, bar.close]
    if is_rth:
        self.rth_data.append(data_row)
    else:
        self.eth_data.append(data_row)

5. 其他注意事项

  • 更换clientId:避免和其他连接冲突,比如把clientId=0改成clientId=10
  • 检查TWS API设置:确保“允许API访问”“允许来自本地主机的连接”已勾选,且端口号和代码中的7497一致(TWS实盘端口是7496,模拟盘是7497)

完整修改后的代码

from ibapi.client import EClient
from ibapi.wrapper import EWrapper
from ibapi.contract import Contract
import pandas as pd

class HistoricalDataApp(EWrapper, EClient):
    def __init__(self):
        EWrapper.__init__(self)
        EClient.__init__(self, wrapper=self)
        self.rth_data = []
        self.eth_data = []

    def error(self, reqId, errorCode, errorString):
        # 新增错误回调,必须实现才能排查问题
        print(f"Error {reqId}: {errorCode} - {errorString}")

    def historicalData(self, reqId, bar):
        if reqId != 1:
            return
        bar_datetime = bar.date
        # 美东时间RTH:9:30-16:00
        is_rth = False
        if bar_datetime.hour > 9 and bar_datetime.hour < 16:
            is_rth = True
        elif bar_datetime.hour == 9 and bar_datetime.minute >= 30:
            is_rth = True
        elif bar_datetime.hour == 16 and bar_datetime.minute == 0:
            # 16:00属于RTH收盘时段
            is_rth = True

        data_row = [bar_datetime.strftime("%Y-%m-%d %H:%M:%S"), bar.open, bar.high, bar.low, bar.close]
        if is_rth:
            self.rth_data.append(data_row)
        else:
            self.eth_data.append(data_row)

    def historicalDataEnd(self, reqId, start, end):
        if reqId == 1:
            print("Historical data download completed")
            self.disconnect()

def get_futures_historical_data():
    app = HistoricalDataApp()
    print("Connecting to API...")
    # 更换clientId,避免冲突;确认端口和TWS设置一致
    app.connect("127.0.0.1", 7497, clientId=10)
    print("Connected to API")

    contract = Contract()
    contract.symbol = "ES"
    contract.secType = "FUT"
    contract.exchange = "GLOBEX"  # 修正为电子盘交易所
    contract.currency = "USD"
    contract.lastTradeDateOrContractMonth = "202409"  # 使用当前活跃合约

    # 请求1小时粒度的30天全天数据
    app.reqHistoricalData(
        reqId=1,
        contract=contract,
        endDateTime="",
        durationStr="30 D",
        barSizeSetting="1 hour",
        whatToShow="MIDPOINT",
        useRTH=0,
        keepUpToDate=False,
        chartOptions=[],
        formatDate=1
    )

    app.run()

    # 生成DataFrame并导出
    rth_df = pd.DataFrame(app.rth_data, columns=["Date", "Open", "High", "Low", "Close"])
    eth_df = pd.DataFrame(app.eth_data, columns=["Date", "Open", "High", "Low", "Close"])

    rth_df.to_excel("rth_data.xlsx", index=False)
    eth_df.to_excel("eth_data.xlsx", index=False)
    print("Data exported to Excel files")

if __name__ == "__main__":
    get_futures_historical_data()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 00:04:55