跳转到内容

取消时间戳请求

reqHeadTimeStamp() 属于需要显式清理的请求。收到 headTimestamp() 后,应调用 cancelHeadTimeStamp(reqId) 取消对应请求,让客户端和 TWS 都回到明确状态。

官方参考:Head Timestamp

def headTimestamp(self, reqId: int, headTimestamp: str):
"""收到最早时间后立即取消对应请求。"""
print(f"最早可用时间:{headTimestamp}")
self.cancelHeadTimeStamp(reqId)

也可以在主流程里保存请求编号,等多个请求都返回后统一取消:

pending_timestamp_requests = {3001}
def headTimestamp(self, reqId: int, headTimestamp: str):
"""接收结果并从待处理集合中移除。"""
print(reqId, headTimestamp)
pending_timestamp_requests.discard(reqId)
self.cancelHeadTimeStamp(reqId)
时机建议
已收到 headTimestamp()立即取消对应 reqId
发生错误如果 reqId 对应请求仍可能存在,也尝试取消。
程序准备退出遍历未完成请求,逐个取消。
批量请求超时取消超时请求,再按限频规则稍后重试。

cancelHeadTimeStamp() 只能取消同一个 reqId 的最早时间请求,不能取消历史 K 线、实时行情或逐笔行情请求。不同请求类型有自己的取消方法:

请求类型取消方法
最早历史时间cancelHeadTimeStamp(reqId)
历史 K 线cancelHistoricalData(reqId)
价格直方图cancelHistogramData(reqId)
实时行情cancelMktData(tickerId)
逐笔行情cancelTickByTickData(reqId)

对新手来说,最稳的是写一个统一清理函数,把每类请求编号分开放:

active_head_timestamp_ids = set()
def request_earliest(app, req_id, contract):
"""发送最早时间请求,并记录待清理编号。"""
active_head_timestamp_ids.add(req_id)
app.reqHeadTimeStamp(req_id, contract, "TRADES", 1, 1)
def cleanup_head_timestamp_requests(app):
"""程序退出或请求结束时清理所有最早时间请求。"""
for req_id in list(active_head_timestamp_ids):
app.cancelHeadTimeStamp(req_id)
active_head_timestamp_ids.discard(req_id)

这样扩展到多合约、多 whatToShow 时,不容易把请求编号和取消方法混在一起。

如果请求已经结束,再次取消同一个 reqId,TWS 可能没有额外回调,也可能返回找不到请求的错误。程序不应把这种情况当成历史数据服务不可用;重点是保证活跃请求集合已经清理干净。

实际批量查询中,可以在 headTimestamp() 回调里立即调用 cancelHeadTimeStamp(reqId)。AAPL 三个最早时间请求都返回了 headTimestamp(),并且没有业务错误,说明这种清理方式适合用于多合约查询。