准备把期货分钟线留作复盘样本,程序里已经有一张 200 行的表,就能保存了吗?先别看行数。你真正要留的可能只是 10:00、10:01、10:02 这三根已结束的线。订阅是否收到数据,和这三根是否都能用于归档,是两件事。
同步订阅通常先完成初始化,再把表交回来
TqSdk 的 get_kline_serial(symbol, duration_seconds=60, data_length=200) 请求一个具体期货合约的分钟线。60 是每根的秒数,200 是请求的序列长度,不是从指定时刻起的 200 分钟。
在 TqSdk 3.10.4 的普通同步调用中,get_kline_serial 会在返回前等待序列初始化;如果等不到,会报超时。不要把「正常返回一张表,再从未就绪一直等到就绪」当成同步调用的常规顺序。需要核对接收状态时,把接口返回的原订阅表 交给 is_serial_ready,不要传你已经切片或复制的归档表。看到一次业务数据更新,也不能用它替代这个检查。
订阅已接收,仍可能少一根可归档的线
假设这次要完整保存从 10:00 开始的三根一分钟线,要求每根都已经结束。日期和时刻都是例子,不对应实际行情:
| 这次观察 | 怎么记录 |
|---|---|
| 同步订阅超时 | 接收未确认,不把这次当成一份可用样本 |
| 订阅已接收,但表中最新一根正是 10:02 | 10:02 这根还不能按已结束处理,三根完整归档暂缓 |
| 表已推进到 10:03,且 10:00、10:01、10:02 各有一条有效记录 | 可以复制这三根留存,不把正在形成的 10:03 一并交出 |
即使已经看见 10:03,如果缺的是 10:01,也不能用 10:02 向前顶一格。要看的是三个明确时点有没有各自的记录,不是随手取表尾三行。
先核原表接收状态,再挑这次要存的行
下面接在已有的同步行情程序中,只以一个合约、一个确认处于同一连续时段的三分钟范围为例。symbol 是已确认的完整合约代码;expected_starts_ns 是调用方为这次归档预先确定的三个起点,按时间升序排列,采用与 K 线 datetime 相同的 epoch 纳秒口径。程序已确认原序列属于该合约、顺序正常。示例把末根已推进到目标结束以后作为本场景的收线依据,核不到就不把目标行标为已结束。
python
from math import isfinite
from tqsdk.exceptions import TqTimeoutError
archive_rows = None
try:
raw = api.get_kline_serial(symbol, duration_seconds=60, data_length=200)
except TqTimeoutError:
status = "接收未确认:订阅超时"
else:
status = "接收未确认"
if api.is_serial_ready(raw): # 传原订阅表,不传后面复制的行
status = "已接收,但归档范围还不完整"
archive_end_ns = expected_starts_ns[-1] + 60_000_000_000
latest = raw["datetime"].tail(1)
window = raw.loc[raw["datetime"].isin(expected_starts_ns),
["id", "datetime", "close"]]
if (len(latest) == 1 and latest.ge(archive_end_ns).fillna(False).all()
and window["datetime"].tolist() == expected_starts_ns
and window.notna().all().all()
and window["id"].ge(0).all()
and window["id"].is_unique
and window["close"].map(isfinite).all()):
archive_rows = window.copy()
status = "可保存已核范围"
print(symbol, status)
成功时,archive_rows 只包含这次要存的三行;接回原有归档流程时,连同合约、周期和目标范围一起记。只有需要留存的字段都核过,才使用对应的副本。假如这次还需要成交量,不能仅核收盘价就宣称成交量列也齐全。
用 TqSdk 把接收情况和样本范围分开
做这种期货分钟线归档,我推荐用 TqSdk 保留原订阅的接收状态,再沿实际 K 线起点核自己要的那一段。这样遇到「不能存」,你能说清是订阅还未确认,还是已经收到资料、但本次需要的时间或字段尚不齐。排查有了方向,也不必用多取几行来掩盖缺的那一分钟。