分钟 K 线是日内策略和高频因子研究的基础数据,但它的「坑」比日线多得多:时间标签有开始时刻和结束时刻两种约定,开盘集合竞价要不要单独成一根,自行合成的大周期和数据源提供的是否一致,跨除权日如何保证价格连续。本文以一个交易日的真实数据为样本,给出分钟级行情数据的入库规范与校验方案。示例使用 Python、pandas 与 QuantDash 的 Python SDK,标的 600519.SH,交易日 2026-10-30,于 2026-11-01 实跑。
维度 | 要求 |
|---|---|
周期 | 1m 为基础,5m/15m/30m/60m 可直接取或合成 |
标签 | 全库统一「结束时刻」约定 |
一致性 | 合成周期与源数据逐根一致 |
完整性 | 分钟成交量加总等于日线成交量 |
复权 | 存档不复权,研究按需复权 |
┌──────────┐ ┌────────────┐ ┌──────────────┐ ┌────────────┐
│ 分钟取数 │──▶│ 标签规范化 │──▶│ 集合竞价归并 │──▶│ 周期合成 │
│ 1m/5m │ │ 结束时刻 │ │ 09:30 并入 │ │ resample │
└──────────┘ └────────────┘ └──────────────┘ └─────┬──────┘
│
┌────────────┐ ┌──────▼─────┐
│ 入库 │◀──│ 一致性校验 │
│ 不复权存档 │ │ 量/价/根数 │
└────────────┘ └────────────┘取同一交易日的 1m、5m、30m 三个周期:
from datetime import datetime
import pandas as pd
from quantdash import QuantDash
qd = QuantDash() # 凭证从环境变量 QUANTDASH_API_KEY 读取
def ms(s):
return int(datetime.strptime(s, "%Y-%m-%d %H:%M").timestamp() * 1000)
def get_min(symbol, period, day, adjust="none"):
return qd.klines.get(symbol, period=period, adjust=adjust,
start_time=ms(f"{day} 09:00"), end_time=ms(f"{day} 15:10"),
count=10000, to_dataframe=True)
for p in ["1m", "5m", "30m"]:
d = get_min("600519.SH", p, "2026-10-30")
print(p, len(d), d["trade_time"].iloc[0], d["trade_time"].iloc[-1])实跑结果整理如下:
周期 | 全天根数 | 第一根 | 上午末根 | 下午首根 | 末根 |
|---|---|---|---|---|---|
1m | 241 | 09:30 | 11:30 | 13:01 | 15:00 |
5m | 48 | 09:35 | 11:30 | 13:05 | 15:00 |
30m | 8 | 10:00 | 11:30 | 13:30 | 15:00 |
结论:标签表示该 K 线的结束时刻。1m 的 241 根由 1 根 09:30 集合竞价、上午 120 根、下午 120 根组成。09:30 这一根开高低收均为 1363.00、成交量 1534。
入库规范第一条:全库只允许一种标签约定。若接入的其他数据源使用开始时刻,在规范化层统一加上一个周期长度后再入库。
直接对 1m 按 5 分钟右闭重采样,得到 49 根,比源数据多 1 根,原因是 09:30 被单独分桶。源数据中第一根 5m 的成交量为 4148,恰好等于 09:30 的 1534 加 09:31–09:35 的 2614,说明集合竞价被并入第一根。
合成规则:
def resample_min(m1, rule="5min"):
d = m1.copy()
d["ts"] = pd.to_datetime(d["trade_time"])
d.loc[d["ts"].dt.strftime("%H:%M") == "09:30", "ts"] += pd.Timedelta(minutes=1)
agg = {"open": "first", "high": "max", "low": "min",
"close": "last", "volume": "sum", "amount": "sum"}
return (d.set_index("ts")
.resample(rule, label="right", closed="right")
.agg(agg).dropna(subset=["close"]))
m1 = get_min("600519.SH", "1m", "2026-10-30")
m5 = get_min("600519.SH", "5m", "2026-10-30")
mine = resample_min(m1)
print(len(mine), len(m5), int(mine["volume"].iloc[0]), int(m5["volume"].iloc[0]))输出 48 48 4148 4148。午休时段没有数据,重采样后的空桶被 dropna 去除,无需额外处理。
合成方式 | 根数 | 第一根成交量 | 是否与源一致 |
|---|---|---|---|
直接右闭重采样 | 49 | 1534(单独一根) | 否 |
09:30 归并后重采样 | 48 | 4148 | 是 |
入库前执行三项校验:
day = qd.klines.get("600519.SH", period="1d", adjust="none", count=3, to_dataframe=True)
day_vol = int(day.loc[day["trade_date"] == "2026-10-30", "volume"].iloc[0])
checks = {
"bars_1m": len(m1) == 241,
"bars_5m": len(m5) == 48,
"vol_sum": int(m1["volume"].sum()) == int(m5["volume"].sum()) == day_vol,
}
print(checks, day_vol)实跑三项均为 True,全天成交量 59927。
校验项 | 规则 | 失败处理 |
|---|---|---|
根数 | 1m=241、5m=48(全天交易日) | 半日市或停牌单独标记 |
总量 | 分钟成交量加总 = 日线成交量 | 重拉当日 |
价格 | 分钟最高价的最大值 = 日线最高价 | 进入人工复核 |
标签 | 首根标签符合约定 | 拒绝入库 |
分钟数据同样受除权影响。以 2026-06-26 除权为例,取除权前 2026-06-24 的 5m 数据:
raw = get_min("600519.SH", "5m", "2026-06-24", adjust="none")
fwd = get_min("600519.SH", "5m", "2026-06-24", adjust="forward")
f = qd.klines.ex_factors("600519.SH", to_dataframe=True)
print(raw["close"].iloc[-1], round(fwd["close"].iloc[-1], 2),
round(raw["close"].iloc[-1] / fwd["close"].iloc[-1], 6), f["ex_factor"].iloc[-1])不复权收盘 1207.68,前复权 1179.76,比值 1.023663,与除权因子完全一致。据此确定复权策略:
数据集 | 口径 | 原因 |
|---|---|---|
分钟存档 | 不复权 | 不随新除权事件变化,可只追加 |
除权因子表 | 每日同步 | 用于按需计算复权价 |
研究视图 | 由存档×因子计算 | 避免拼接不同时点拉取的前复权数据 |
前复权以最新价为锚,每次除权都会整体改写历史价格。若把不同时间拉取的前复权分钟数据直接拼接,在除权日前后会出现价格断层。存不复权、算复权,是分钟库长期维护成本最低的方案。
分钟数据量大,建议按「周期/交易日/标的」分区,文件名中写明口径,例如 min5/20261030/600519.SH_raw.parquet。查询时按日期分区裁剪,单日全市场的分钟数据可以独立重建,不影响其他日期。
规范只覆盖正常交易日是不够的,入库任务还要能识别几类异常,否则校验会频繁误报:
场景 | 表现 | 处理规则 |
|---|---|---|
全天停牌 | 当日无分钟数据,日线也无记录 | 记为停牌,不触发重拉 |
盘中临时停牌 | 分钟根数少于 241,但成交量加总仍等于日线 | 根数校验降级为告警,总量校验仍为强校验 |
新股上市首日 | 价格波动大,涨跌幅阈值失效 | 跳过跳变校验,保留价格关系校验 |
除权当日 | 前复权价格整体改写 | 存档不受影响,仅重建研究视图 |
数据延迟到达 | 收盘后立即拉取,末根尚未生成 | 设置延迟窗口,收盘后间隔一段时间再执行 |
实践中最有用的是把「强校验」和「告警」分开:总量一致性、标签约定属于强校验,失败即拒绝入库;根数、跳变属于告警,记录后由人工确认。这样既能保证数据正确,也不会因为个别停牌股阻塞整批任务。
另外建议为每次入库生成一条元数据记录,包括标的、交易日、周期、复权口径、根数、成交量合计、拉取时间和校验结果。出现问题时,可以直接按元数据定位到具体批次,而不是重新比对原始文件。
分钟级数据入库的核心是把隐含约定显式化:标签用结束时刻、集合竞价归并进第一根、存档不复权并配套除权因子,再用根数、总量和价格三类校验兜底。按这套规范入库后,合成周期与源数据逐根一致,跨数据源比对时的差异也能快速定位到具体原因。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。