同一批成交为什么会聚合出两根不同的分钟 K 线?

K 线聚合:从 Tick 到 OHLCV

约 10 分钟5 道自测更新于 2026-10-27

一句话记住K 线不是天然事实,而是按证券、交易阶段、时间边界和缺失处理规则聚合出来的结果;先写口径,再写代码。

01学完你能做到

定义一份可复现的 OHLCV 口径;正确处理窗口边界、交易阶段、空窗和缺失;用量额守恒、边界样本和重复消息检查聚合结果。

02这课解决什么问题

同一批成交为什么会聚合出两根不同的分钟 K 线?差异通常不在 max 或 sum 本身,而在时间边界、排序、交易阶段、累计量和缺失状态。

03先定义输入和输出

对已经确定证券、交易范围和时间窗口的成交集合:

  • O:按事件顺序的第一笔成交价。
  • H/L:最高、最低成交价。
  • C:按事件顺序的最后一笔成交价。
  • V:窗口内成交数量之和。
  • A:窗口内成交金额之和。
  • VWAP = A ÷ V;V 为 0 时没有成交均价,应保留为空。

这是自定义成交窗口的定义。交易所正式开盘价、收盘价和日行情可能使用专门规则,不能把窗口最后一笔当作所有市场的官方收盘价。若消息里的数量是累计值,必须先转成增量再求和。

04时间窗口的两个开关

左闭右开窗口 [09:30, 09:31) 包含 09:30:00,不包含 09:31:00。closed 决定边界归属,label 只决定显示标签;标签写成 09:31,不会自动改变归属。

窗口还需要锚点。例如一小时窗口从午夜对齐,和从 09:30 对齐,切片会不同。开盘、午休、收盘和跨市场会话不能只靠通用重采样参数处理。

验收时在 09:30:59.999 和 09:31:00.000 各放一笔成交,先手写归属,再运行程序。相同时间戳的多笔成交要按数据源给出的序号处理,不能默认 ID 排序就代表市场先后。

05交易阶段必须单独建模

以上海市场普通股票竞价交易为例,交易规则列出的时段包括:09:15—09:25 开盘集合竞价,09:30—11:30 和 13:00—14:57 连续竞价,14:57—15:00 收盘集合竞价;盘后固定价格交易另有适用范围。具体品种、市场和规则会有差异,应以所属交易所最新规则为准。

一分钟线是否包括集合竞价、11:30 和 15:00 的边界成交、盘后交易和停牌状态,都要写进产品定义。“一天约有 240 根”只能是特定口径下的估算,不能作为所有数据的固定答案。

06空窗要区分状态

状态需要的证据价格与量额
已确认无成交市场开市且源数据覆盖完整可保留空价格、零量额,或给展示层单独标记
停牌证券状态或公告等证据保留停牌状态,不假装发生交易
休市或非交易阶段交易日历与阶段定义不补出普通交易 K 线
数据缺失或覆盖未知断流、缺包或校验失败保留缺失与原因,不能悄悄补成零成交

表格里没有记录,只能说明输入中没有记录,不能自动证明没有交易。沿用前收盘价也只是合成展示值,必须保留原始值和合成标记,不能当作实际成交价。

07代码:统一窗口参数

import pandas as pd

raw = pd.DataFrame({
    "id": ["T1", "T2", "T3", "T4", "T5", "T6"],
    "ts": ["2026-10-26 09:30:00.120", "2026-10-26 09:30:20.480",
           "2026-10-26 09:30:45.050", "2026-10-26 09:31:02.900",
           "2026-10-26 09:31:30.010", "2026-10-26 09:33:10.500"],
    "price": [10.00, 10.03, 9.98, 10.02, 10.05, 10.01],
    "qty": [500, 300, 200, 1000, 400, 600],
})
raw["ts"] = pd.to_datetime(raw["ts"]).dt.tz_localize("Asia/Shanghai")
raw["amount"] = raw["price"] * raw["qty"]
raw = raw.sort_values(["ts", "id"]).set_index("ts")
kw = dict(rule="1min", closed="left", label="left", origin="start_day")
bars = raw["price"].resample(**kw).ohlc()
bars = bars.join(raw[["qty", "amount"]].resample(**kw).sum())
bars["vwap"] = bars["amount"].div(bars["qty"].where(bars["qty"].gt(0)))
print(bars)

所有价格、数量和金额都要复用同一组窗口参数。跨到更长周期时,O 取第一根有效 O,H 取最大 H,L 取最小 L,C 取最后有效 C,V 和 A 分别求和;不能直接平均子 K 线的 VWAP,应使用总 A ÷ 总 V。

08验收一项 K 线能力

  1. 同一过滤范围下,输入量额与输出量额守恒,差异要有排除原因。
  2. 有成交的 K 线满足 L 不高于 O/C,H 不低于 O/C,V 与 A 单位一致。
  3. 同样输入重跑得到同样结果,重复消息不会无意增加成交。
  4. 乱序输入按源顺序恢复后结果一致,丢包时输出降级状态。
  5. 迟到成交怎样修订,是否区分暂定、确认和修订版本。
  6. 证券状态、交易阶段和复权口径明确,原始行情可追溯。

09延伸阅读

10一分钟讲给别人

试着用自己的话讲一遍K 线不是把数据按一分钟切一下就结束。要先定边界、锚点、交易阶段和缺失状态,再算开高低收、成交量和成交额。验收时用同一批输入核对量额和边界,并保留迟到与修订机制。

想一想

5 道自测

先在心里答一遍,再展开对照。能说清理由,比答对数字更重要。

  1. 01左闭右开窗口 `[09:30, 09:31)` 是否包含 09:31:00.000?

  2. 0209:30 分钟成交量 1000 股、成交额 10005 元,VWAP 是多少?

  3. 03表格中没有某一分钟记录,能否直接判定为无成交?

  4. 04为什么所有字段要使用同一组窗口参数?

  5. 05两根子 K 线的 VWAP 为什么不能直接求算术平均?

已看 0/5 题

练动手练习

任务:在样本中加入一笔 09:31:00.000、价格 10.04、数量 100 的成交,按当前左闭右开口径判断它属于哪根 K 线,并重新计算该根的 V、A 和 VWAP。再设计三个边界样本测试窗口实现。

完成这一课

完成这一课

读完讲义、看完自测答案,这一课就算学完了。

  • 读完讲义
  • 看完全部自测

本课为投资者教育内容,案例数字均为示意,不构成任何投资建议,也不承诺收益。规则和费率会变,实际操作前请以交易所、监管机构和产品的最新公告为准。