3. 盘中走势的分时数据基础

要统计首次封板之后的盘中走势,第一步不是写统计逻辑,而是把“分时成交数据”这件事本身弄清楚。很多初学者拿到一份逐笔成交或分钟线数据后,直接对“收盘价”做统计,结果发现涨停板打开、回封、尾盘跳水这些关键形态全被抹平了。原因往往不在统计方法,而在于对分时数据的结构、字段含义和重采样方式理解不到位。本节围绕三个问题展开:分时成交数据长什么样、价格与成交量如何从原始记录中提取、均价线如何计算并在重采样中保持一致。

一、分时成交数据的两种常见形态

盘中数据在实际使用中主要有两种粒度。第一种是逐笔成交(Tick)数据,每一条记录对应一次撮合成交,典型字段包括:成交时间(精确到秒或毫秒)、成交价格、成交数量(股或手)、成交金额、买卖方向(主动买/主动卖,部分数据源提供)。第二种是分钟线数据,把一段时间内的成交聚合为一条记录,字段通常为:时间戳(标识该分钟的结束或开始)、开盘价、最高价、最低价、收盘价、成交量、成交额。

两者不是替代关系,而是上下游关系:分钟线本质上是逐笔数据按时间窗口聚合的结果。理解这一点非常关键——如果你只有分钟线,那么“这一分钟内价格如何波动”的信息已经丢失,只剩下 OHLC 四个价位;如果你有逐笔数据,就可以自行定义聚合窗口,甚至构造 30 秒、10 秒级别的更细粒度序列。做首次封板时间统计时,封板时刻往往落在某一分钟内,只有逐笔数据才能把封板时间精确到秒;而做盘中走势形态统计时,分钟线通常已经够用。

选择数据粒度的一条实用原则:需要判断“几点几分封板、封板后多久打开”这类时间点问题时,用逐笔数据;需要刻画“封板后价格重心的移动方向、成交量能是否衰减”这类趋势问题时,用分钟线即可,且计算量小得多。

二、价格序列的提取:收盘价、典型价与均价

从分钟线中提取“价格”并不是只有一种选择,不同提取方式服务于不同统计目的。最常用的是收盘价序列,即每分钟最后一个成交价,它适合刻画走势的方向和形态,因为收盘价代表了该时刻市场达成的最新共识价格。其次是典型价,定义为(最高价+最低价+收盘价)/3,它对单根K线内的价格分布做了平滑,适合在计算量价关系时降低噪声。第三种是成交均价,即该分钟成交额除以成交量,反映这一分钟内所有成交的真实加权平均成本。

这里有一个容易被忽略的细节:分钟线的“收盘价”与“该分钟最后一笔成交价”在多数数据源中是一致的,但在集合竞价时段或存在盘后固定价格交易的品种上可能不同。因此在提取价格序列前,应先确认数据源的时间戳约定——时间戳标记的是窗口起点还是终点。若标记起点,则第 t 条记录的收盘价实际对应 [t, t+1) 区间;若标记终点,则对应 (t-1, t]。这个约定一旦搞错,封板时间会整体偏移一分钟,后续所有统计都会系统性偏差。

三、成交量与成交额的提取及口径统一

成交量字段最常见的坑是单位不统一:有的数据源用“股”,有的用“手”(1手=100股),有的用“万股”。在把多只股票放在一起做横向统计时,必须先统一到同一口径,否则小盘股与大盘股的成交量差异会被单位放大或缩小。建议在数据底座中统一转换为“股”,并在字段命名上明确标注,例如 volume_shares。

成交额同样需要检查:部分数据源的成交额单位为“元”,部分为“万元”或“千元”。成交额与成交量的比值应当约等于该窗口的成交均价,这可以作为一个快速校验手段——若某条记录的成交额/成交量算出来是 0.05 或 5000 这类明显不合理的数值,基本可以判定单位口径有问题。此外,成交量在重采样时应当累加,而价格类字段不能简单累加,这是重采样中最基本的区分。

四、均价线的计算与重采样的一致性

分时图上那条平滑的均价线,标准定义是当日累计成交额除以当日累计成交量,即从开盘到当前时刻的成交量加权平均价(VWAP)。它不是各分钟均价的简单算术平均,也不是收盘价的移动平均。这一点在重采样时尤其重要:如果你先把 1 分钟数据聚合成 5 分钟数据,再计算均价线,必须使用聚合后的累计成交额与累计成交量重新相除,而不能对 1 分钟均价线做算术平均,否则会得到一条偏离真实成本的曲线。

下面给出一个可直接参考的提取与重采样示例(Python 伪代码,示例参数为合理假设,非实测结果):

import pandas as pd

# 假设 df 为 1 分钟线,字段:dt, open, high, low, close, volume_shares, amount_yuan
df = df.sort_values("dt").reset_index(drop=True)

# 1) 提取价格序列:收盘价与典型价
df["typical"] = (df["high"] + df["low"] + df["close"]) / 3

# 2) 分钟成交均价(用于校验单位口径)
df["vwap_1m"] = df["amount_yuan"] / df["volume_shares"]

# 3) 当日累计均价线(VWAP)
df["cum_amount"] = df["amount_yuan"].cumsum()
df["cum_volume"] = df["volume_shares"].cumsum()
df["vwap_day"] = df["cum_amount"] / df["cum_volume"]

# 4) 重采样为 5 分钟:价格取窗口末值,量额累加,均价用累计量额重算
agg = df.set_index("dt").resample("5min").agg({
    "open": "first", "high": "max", "low": "min",
    "close": "last", "volume_shares": "sum", "amount_yuan": "sum"
}).dropna()

agg["vwap_5m"] = agg["amount_yuan"].cumsum() / agg["volume_shares"].cumsum()

这段代码体现了三条重采样规则:价格取边界值(开盘取首、收盘取末、高低取极值),量额做累加,均价用累计量额重新相除。只要守住这三条,无论聚合到 5 分钟、15 分钟还是 30 分钟,均价线都能保持与原始逐笔口径一致。

五、数据底座的结构与质量检查

把上述字段整理成一张规范的分时表,是后续所有走势统计的基础。建议的最小字段集为:交易日期、时间戳、开盘、最高、最低、收盘、成交量(股)、成交额(元)、当日累计成交量、当日累计成交额、当日均价线。在此基础上,还应做三项质量检查:一是时间连续性,正常交易时段内分钟线不应缺行,若缺失需判断是停牌、无成交还是数据源问题;二是价格合理性,最高价应不小于开盘、收盘、最低价,且各价格应落在当日涨跌停范围内;三是量额一致性,成交额/成交量应落在当日价格区间附近。

下图展示了从逐笔成交到分钟线、再到重采样序列与均价线的完整数据链路,以及各环节需要保持的口径约定:

分时成交数据底座:从逐笔到重采样序列 逐笔成交(Tick) 时间(秒/毫秒) 成交价 · 成交量 · 成交额 买卖方向(可选) 特点:可精确定位封板时刻 按分钟聚合 1 分钟线 开 · 高 · 低 · 收 成交量(股)· 成交额(元) 时间戳约定:起点 or 终点 特点:走势形态统计的主力粒度 重采样 5/15/30 分钟序列 开=首 · 收=末 · 高低=极值 成交量、成交额:累加 均价:累计量额重新相除 特点:降噪,看趋势与量能 字段提取规则 价格序列 收盘价 / 典型价 成交量口径 统一为“股” 成交额校验 额/量 ≈ 价格区间 均价线 VWAP 累计额 / 累计量 均价线示意(示例数据,非实测) 09:30 10:30 11:30/13:00 14:00 15:00 收盘价 均价线 VWAP 封板时刻

图中左侧是逐笔数据,中间是分钟线,右侧是重采样序列,下方则把价格、成交量、成交额、均价线四类字段的提取规则并列出来。可以看到,均价线在每一层都遵循“累计成交额除以累计成交量”的同一定义,这正是重采样时不能对均价做算术平均的根本原因。图中封板时刻的标记也提示了一点:若只有分钟线,封板时刻只能定位到分钟;若需要精确到秒,就必须回到逐笔层。

把这张数据底座搭好之后,后续的首次封板时间统计、封板后开板次数、封板期间均价线是否走平或下移、尾盘量能是否萎缩等指标,都可以在同一张规范表上直接计算,而不必每次重新处理原始数据。数据底座的稳定性,决定了走势统计结论的可比性。