Python 期货策略怎么判断一根新 K 线已经生成
前言
在国内期货做 Python 策略,很多人第一步是拿到 K 线、算均线或突破。K 线是把连续成交按固定时间窗口聚合成一根“柱子”(也有按成交量、按 tick 等,本文只说最常见的时间周期 K 线,例如 5 分钟、1 小时)。策略里有一句“等新 K 线出来再交易”,落地时必须变成可执行的判断:程序怎么知道“上一根已经收盘、新的一根开始了”?
若判断错了,典型后果是:同一根未收盘的 K 线内信号闪动多次、重复报单;或者回测用历史数据时以为“最后一行就是收盘”,实盘却用正在跳动的最后一行,回测与实盘完全两套逻辑。下文用天勤 TqSdk 说明 K 线表从哪来、datetime 是什么、如何用 wait_update 与 is_changing 判断新 K 线,以及为何常在 iloc[-2] 上算信号。面向正在从“研究脚本”迁到“实时行情驱动”的期货量化初学者,不默认你已写过 CTP 程序。
一、期货 K 线表从天勤哪里来、每列含义
连接模拟或实盘账户后:
from tqsdk import TqApi, TqAuth, TqSim
api = TqApi(TqSim(), auth=TqAuth("快期账户", "密码"))
kl = api.get_kline_serial("SHFE.rb2510", 300, data_length=200)
SHFE.rb2510:交易所代码 + 合约代码,表示上期所螺纹钢某一具体月份合约(实盘需换成可交易月份)。300:K 线周期 300 秒,即 5 分钟线。data_length:向服务端申请的 K 线根数缓冲,用于计算长周期指标。
返回的 kl 是 pandas DataFrame,每一行一根 K 线。与判断“新 K 线”最相关的是 datetime 列:由行情/K 线业务服务根据交易所规则写入,标识该根 K 线的时间;不是你在策略里 import datetime 自己打印的本地时钟,也不是 sleep(300) 计时出来的。
主循环必须先 api.wait_update():天勤在此步骤接收并合并数据包,表中的 close、datetime 等才会更新。不调用 wait_update,表里数据不会随市场走。
二、两行索引:正在形成的 bar 与刚收盘的 bar
| 写法 | 在实盘语义下指什么 |
|---|---|
kl.iloc[-1] |
当前这一根,还在交易时段内,OHLC 可能随 tick 变化 |
kl.iloc[-2] |
上一根,在下一根未出现前,其收盘价等一般视为已定格 |
因此,“收盘突破”“均线金叉”若定义在收盘价上,应在 [-2] 上判断;触发计算的时机是 [-1] 的 datetime 相对上一帧发生变化(表示新一根 bar 开始)。
三、标准判断代码及逐句解释
while True:
api.wait_update()
if not api.is_changing(kl.iloc[-1], "datetime"):
continue
done_close = kl.close.iloc[-2]
wait_update():等待并应用本次业务数据更新。kl.iloc[-1]:取“当前根”那一行对象。is_changing(..., "datetime"):问天勤——这一次更新里,当前根的时间标签变了吗? 若变,通常说明新 K 线生成,上一根刚收盘。continue:若没变,说明仍处在同一根 K 线内,跳过信号逻辑,避免 tick 级重复计算。iloc[-2]:用刚收盘那根的价格做决策。
天勤文档写明:生成新 K 线时,对最后一根执行 is_changing(klines.iloc[-1]) 会为 True;实务中指定 "datetime" 更精确。
四、不建议的替代写法
- 用
len(kl)是否 +1 判断:重连、补数据时长度可能跳变,不如直接看datetime。 - 用
iloc[-1].close做突破:未收盘前 close 会变,一分钟内可能触发十几次。 - 回测用 [-1]、实盘用 [-2]:等于两个策略,绩效不可比。
五、指标 NaN 与 data_length
若 ma20.iloc[-2] 为 nan,说明历史 K 线根数不够或合约上市不久,该次触发应跳过,不要比较 nan。
六、和 tick、盘口策略的边界
若策略本质是“每一个成交 tick 都要反应”,就不应以 K 线 datetime 为主触发,而应另写 quote 的 last_price 等规则,并团队内明确:本策略是 K 线驱动还是 tick 驱动,勿混用。
总结
判断“一根新的期货 K 线已经生成”,在国内期货 Python 量化里应建立在:天勤 get_kline_serial 返回的表 → 表中 datetime 字段由行情服务更新 → 每次 wait_update 后用 is_changing(最后一行, "datetime") 检测是否开新 bar → 在 iloc[-2] 上计算收盘类信号。
不要依赖本地 sleep,也不要把 DataFrame 最后一行无条件当成“已收盘”。把这条规则写进团队规范,回测、快期模拟、实盘共用同一套代码,能避免大量“回测好、实盘乱”的纠纷。
FAQ
1)tick 策略还需要 datetime 吗?
纯 tick 策略不必;混合策略必须规定以谁为准。
2)主连合约 KQ.m 是否一样?
仍是 serial 表与 datetime;换月逻辑另做。
3)夜盘休市时 datetime 会乱跳吗?
休市无新 bar 则 datetime 不推进,一般无误触发。
4)能否用 pandas 重采样自己造 datetime?
实时交易应以天勤推送的 serial 为准,自造易与交易所规则不一致。
风险提示
本文讨论技术实现,不构成投资建议。
更多推荐


所有评论(0)