2. 分钟聚合核心指标定义

逐笔行情是交易所按每一笔成交推送的原始数据流,一条记录通常包含成交时间、成交价、成交量、成交额、买卖方向等字段。分钟聚合的任务,是把这一分钟内所有逐笔成交压缩成一根K线,并附带若干统计量。指标口径一旦定义不清,后续的信号计算、回测和风控都会建立在错误的基础上。本节围绕一根分钟K线需要产出的核心字段,逐一说明计算口径与业务含义。

一、OHLC:价格区间的四个端点

OHLC分别指开盘价(Open)、最高价(High)、最低价(Low)和收盘价(Close)。在逐笔聚合场景下,它们的口径需要明确:

  • 开盘价:该分钟窗口内第一笔成交的成交价,而不是窗口起始时刻的快照价。若窗口内无成交,则沿用上一分钟收盘价,并标记为“无成交填充”。
  • 最高价 / 最低价:窗口内所有逐笔成交价的最大值与最小值,只统计实际成交,不包含盘口挂单价。
  • 收盘价:窗口内最后一笔成交的成交价,是下一分钟开盘价填充的参照。

业务含义上,OHLC刻画了价格在该分钟内的波动区间与起止位置。开盘价与收盘价之差反映净方向,最高价与最低价之差反映波动幅度。需要注意,若某分钟只有一笔成交,则O=H=L=C,这是正常现象而非数据异常,聚合逻辑不应将其丢弃。

二、成交量、成交额与笔数

成交量是该分钟窗口内所有逐笔成交的成交量之和,单位需与数据源保持一致(股、手或张),聚合过程中不得混用。成交额是逐笔成交额之和,也可用“成交价×成交量”逐笔累加得到,但更推荐直接累加原始成交额字段,以避免价格精度带来的舍入误差。

笔数是窗口内成交记录条数,反映交易活跃度。笔数与成交量结合可以观察平均单笔规模:平均单笔量偏大往往意味着大资金参与,笔数多而单笔量小则更接近散户主导的活跃行情。这三个字段都是可加量,跨分钟汇总时直接求和即可,这为后续的小时、日线聚合提供了便利。

三、均价:两种口径要分清

均价常见两种口径,业务含义不同,不能混用:

  • 成交量加权均价(VWAP):成交额 ÷ 成交量,反映该分钟内资金实际成交的平均成本,是衡量成交质量的核心指标。
  • 算术均价:(最高价 + 最低价) ÷ 2 或四价均值,仅作为价格中枢的粗略参考,不反映资金成本。

实战中应以VWAP为主。当收盘价明显高于VWAP时,说明该分钟内的成交更多集中在价格低位、尾段拉升,买方力量偏强;反之则偏弱。若成交量为零,VWAP无定义,应置空而不是填零,避免污染后续计算。

四、买卖方向统计

逐笔数据通常带有买卖方向标记(主动买或主动卖)。按方向分别累加成交量,可得到主动买量和主动卖量,二者之差即净主动买入量,是判断资金流向的直接依据。若数据源未提供方向字段,可用逐笔成交价与上一笔成交价比较来推断:价格上行视为主动买,下行视为主动卖,价格不变则沿用上一笔方向或归为中性。

方向推断属于近似口径,与交易所原始标记可能存在差异。同一策略中应固定使用一种口径,并在文档中注明,避免回测与实盘口径不一致。

五、聚合流程与字段关系

下面用一张图展示逐笔记录进入分钟窗口后,各指标字段是如何被计算出来的,以及它们之间的依赖关系。

逐笔成交 → 分钟指标聚合关系 逐笔成交流 时间 / 价格 / 量 / 额 买卖方向标记 按分钟窗口切分 窗口内逐笔遍历 窗口内聚合器 首笔价 → Open max/min → High/Low 末笔价 → Close 累加量/额/笔数 按方向分流累加 价格类指标 O / H / L / C,刻画波动区间与起止 量能类指标 成交量 / 成交额 / 笔数,可加量 方向类指标 主动买量 / 主动卖量 / 净主动买入 派生指标 VWAP = 成交额 ÷ 成交量(量为0时置空) 净主动买入 = 主动买量 − 主动卖量 口径校验要点 ① 成交量单位全程统一,不混用股与手 ② 成交额优先累加原始字段,减少舍入 ③ 无成交分钟:价格沿用前收,量额为0 ④ 方向推断口径固定,回测实盘一致 ⑤ 单笔成交分钟 O=H=L=C 属正常

六、一个可对照的示例

假设某分钟窗口内共有5笔成交,数据如下(示例数据,仅用于说明计算过程):

序号成交价成交量成交额方向
110.002002000买
210.053003015买
39.98100998卖
410.024004008买
510.011501501.5卖

按前述口径计算:Open=10.00,High=10.05,Low=9.98,Close=10.01;成交量=200+300+100+400+150=1150;成交额=2000+3015+998+4008+1501.5=11522.5;笔数=5;VWAP=11522.5÷1150≈10.0196;主动买量=200+300+400=900,主动卖量=100+150=250,净主动买入=650。收盘价10.01略低于VWAP,说明该分钟尾段成交价格略低于资金平均成本,买方优势有所收敛。

七、实现时的关键细节

在代码实现上,建议为每个分钟窗口维护一个聚合状态对象,逐笔更新而非先缓存全部记录再计算,这样内存占用与窗口内笔数无关。更新逻辑可概括为:首笔写入Open,每笔更新High/Low,每笔覆盖Close,量额笔数累加,按方向分流累加。窗口切换时输出结果并重置状态。

state = {open:None, high:-inf, low:inf, close:None,
         vol:0, amt:0, cnt:0, buyVol:0, sellVol:0}
for tick in window:
    if state.open is None: state.open = tick.price
    state.high = max(state.high, tick.price)
    state.low  = min(state.low,  tick.price)
    state.close = tick.price
    state.vol += tick.vol; state.amt += tick.amt; state.cnt += 1
    if tick.side == 'B': state.buyVol += tick.vol
    else:                 state.sellVol += tick.vol
vwap = state.amt / state.vol if state.vol else None

最后强调两点业务判断:其一,指标之间要能相互印证,例如成交额与“价×量”的偏差过大,往往提示数据源字段异常;其二,无成交分钟的填充规则必须在整条数据链上保持一致,否则跨周期聚合时会出现价格跳变。把口径写进文档、写进代码注释,并在回测与实盘使用同一套聚合函数,是保证分钟指标可信的最低要求。