跳转到内容

接收历史 K 线

历史 K 线通过回调返回,不是 reqHistoricalData() 的函数返回值。每收到一根 bar,TWS API 会调用一次 historicalData()

def historicalData(self, reqId, bar):
"""接收单根历史 K 线。"""
print(
reqId,
bar.date,
bar.open,
bar.high,
bar.low,
bar.close,
bar.volume,
)
def historicalDataEnd(self, reqId, start, end):
"""历史 K 线请求结束。"""
print(f"历史 K 线结束:reqId={reqId}, start={start}, end={end}")

historicalDataEnd() 很重要。没有它,程序很难知道“这次请求是不是已经返回完了”。

字段中文解释
dateK 线时间。格式受 formatDate 影响。
open开盘价。
high最高价。
low最低价。
close收盘价。
volume成交量。
wap加权平均价。Python ibapi.common.BarData 字段名是 wap
barCount该 bar 内包含的成交笔数或数据点数量。
date=20260612 09:30:00 US/Eastern
open=295.9
high=297.14
low=294.89
close=295.35
volume=1472090
wap=295.893
barCount=10645

这是一根 5 分钟 K 线,表示美股东部时间 09:30:00 开始的这 5 分钟内,AAPL 的开高低收和成交量。

日线和更大周期的 bar 不一定像分钟线那样带完整时分秒。期货日线还可能使用交易所结算价作为收盘价,结算价有时会在交易时段结束后几个小时才更新。跨自然日的交易时段,日线日期通常以该交易时段结束的日期为准。

调试时可以直接打印。正式程序里建议整理成字典或数据库行:

bars = []
def historicalData(self, reqId, bar):
"""先收集原始 K 线。"""
bars.append(
{
"reqId": reqId,
"date": bar.date,
"open": float(bar.open),
"high": float(bar.high),
"low": float(bar.low),
"close": float(bar.close),
"volume": int(bar.volume),
"wap": float(bar.wap),
"barCount": int(bar.barCount),
}
)

保存时建议额外记录这些请求参数:

字段为什么要保存
symbol / conId知道是哪一个合约。
durationStr方便复现请求窗口。
barSizeSetting知道每根 K 线周期。
whatToShow区分成交价、买卖中间价、买价、卖价等口径。
useRTH区分是否只包含常规交易时段。
timeZoneId避免跨时区回测错位。

如果 historicalDataEnd() 一直没到,要同时检查连接状态、错误回调和 pacing 限制。