跳转到内容

修改返回日期

formatDate 用来控制历史行情回调里日期字段的返回格式。它不会改变请求范围,也不会改变行情本身,只改变返回给程序的时间表示方式。

官方参考:Historical Bar Data

app.reqHistoricalData(
reqId,
contract,
endDateTime,
durationStr,
barSizeSetting,
whatToShow,
useRTH,
formatDate, # 控制返回日期格式
keepUpToDate,
chartOptions,
)

reqHeadTimeStamp() 也有 formatDate

app.reqHeadTimeStamp(
reqId,
contract,
whatToShow,
useRTH,
formatDate, # 控制最早时间戳返回格式
)
formatDate返回形式适合场景
1可读日期字符串,例如 20260612 09:30:00 US/Eastern文档示例、人工检查、日志排查
2Unix 秒级时间戳,例如 1781271000程序入库、统一转 UTC、跨市场处理

新手调试时建议先用 1,因为肉眼能看懂。等字段和时区都确认后,再考虑用 2 做系统存储层存储。

下面两个请求只有 formatDate 不同:

# 返回可读日期字符串
app.reqHistoricalData(
97101,
contract,
"20260612 15:59:00 US/Eastern",
"1 D",
"1 hour",
"TRADES",
1,
1,
False,
[],
)
# 返回 Unix 秒级时间戳
app.reqHistoricalData(
97102,
contract,
"20260612 15:59:00 US/Eastern",
"1 D",
"1 hour",
"TRADES",
1,
2,
False,
[],
)

AAPL、1 D1 hourTRADES 请求的返回结果:

CONNECTED=True
FORMAT_DATE_1_ROWS=20260612 09:30:00 US/Eastern|20260612 10:00:00 US/Eastern|20260612 11:00:00 US/Eastern
FORMAT_DATE_2_ROWS=1781271000|1781272800|1781276400
DONE_FLAGS=97101,97102
NON_INFO_ERROR_COUNT=0

可以看到,两个请求对应的是同一组 K 线,只是日期字段的表达方式不同。

from datetime import datetime, timezone
def historicalData(self, reqId, bar):
"""接收历史 K 线,并兼容两种日期格式。"""
raw_date = bar.date
if str(raw_date).isdigit():
# formatDate=2:TWS 返回 Unix 秒级时间戳
bar_time = datetime.fromtimestamp(int(raw_date), tz=timezone.utc)
else:
# formatDate=1:TWS 返回可读字符串,建议连同原始字符串一起保存
bar_time = raw_date
print(bar_time, bar.open, bar.high, bar.low, bar.close)
场景建议
给新手看日志formatDate=1
写文档或排查日志formatDate=1
存数据库主时间字段formatDate=2 或自行转换成 UTC
同时需要复盘原始 TWS 输出保存 raw_date 字段

无论选择哪种格式,都要在项目里保持一致。最怕的是一部分数据按字符串解析,一部分数据按时间戳解析,后面回测时才发现时间轴混乱。