取消时间戳请求
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)什么时候取消
Section titled “什么时候取消”| 时机 | 建议 |
|---|---|
已收到 headTimestamp() | 立即取消对应 reqId。 |
| 发生错误 | 如果 reqId 对应请求仍可能存在,也尝试取消。 |
| 程序准备退出 | 遍历未完成请求,逐个取消。 |
| 批量请求超时 | 取消超时请求,再按限频规则稍后重试。 |
不要混用取消方法
Section titled “不要混用取消方法”cancelHeadTimeStamp() 只能取消同一个 reqId 的最早时间请求,不能取消历史 K 线、实时行情或逐笔行情请求。不同请求类型有自己的取消方法:
| 请求类型 | 取消方法 |
|---|---|
| 最早历史时间 | cancelHeadTimeStamp(reqId) |
| 历史 K 线 | cancelHistoricalData(reqId) |
| 价格直方图 | cancelHistogramData(reqId) |
| 实时行情 | cancelMktData(tickerId) |
| 逐笔行情 | cancelTickByTickData(reqId) |
请求编号管理
Section titled “请求编号管理”对新手来说,最稳的是写一个统一清理函数,把每类请求编号分开放:
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 时,不容易把请求编号和取消方法混在一起。
取消后的常见现象
Section titled “取消后的常见现象”如果请求已经结束,再次取消同一个 reqId,TWS 可能没有额外回调,也可能返回找不到请求的错误。程序不应把这种情况当成历史数据服务不可用;重点是保证活跃请求集合已经清理干净。
实际批量查询中,可以在 headTimestamp() 回调里立即调用 cancelHeadTimeStamp(reqId)。AAPL 三个最早时间请求都返回了 headTimestamp(),并且没有业务错误,说明这种清理方式适合用于多合约查询。