第九章:时间与销售——Tick 数据、逐笔成交、交易量聚类、大单识别

做量化交易的朋友,一定听过这句话:「价格是表象,成交量是真相」

我个人习惯把订单簿比作「静态的战场地图」,而 Tick 数据和逐笔成交,就是战场上的实时战报。你光看地图没用,得知道哪支部队在冲锋,哪支部队在撤退。

这一章,我们就来拆解这些「战报」——Tick 数据、逐笔成交、交易量聚类,以及大单识别。说白了,就是教你从海量交易数据里,嗅出主力的味道。

9.1 Tick 数据:最细粒度的市场心跳

先问个问题:你知道 1 分钟 K 线里,到底发生了多少次交易吗?

答案是:不知道。K 线只告诉你开盘、收盘、最高、最低、总成交量。中间的过程,全被抹掉了。

Tick 数据,就是记录每一次行情变动的快照。它通常包含:

  • 时间戳:精确到毫秒甚至微秒
  • 最新成交价
  • 最新成交量(这一笔成交了多少手)
  • 买卖盘口(买一、卖一的价格和挂单量)

核心认知: Tick 数据不是「每一笔成交」,而是「每一次行情变动」。如果 1 秒内成交了 100 笔但价格没变,很多交易所只推送 1 个 Tick。所以,Tick 数据是「有变化才记录」。

我在项目中遇到过一个问题:用 Tick 数据回测策略,结果实盘跑起来完全对不上。后来发现,我用的 Tick 数据是「合并后的快照」,而实盘用的是「逐笔成交」。这两者差别很大。

9.2 逐笔成交:还原每一笔交易的真相

逐笔成交(Trade by Trade),才是真正的「每一笔成交记录」。它告诉你:

  • 谁在买?谁在卖?
  • 这笔交易是主动买入(吃单)还是主动卖出(砸盘)?
  • 成交了多少量?

举个例子,你看到一笔 1000 手的成交,价格是 10.00 元。如果这笔成交是「主动买入」,说明买方直接吃掉了卖一价位的挂单。如果「主动卖出」,说明卖方直接砸给了买一价位的挂单。

我的习惯: 我会把逐笔成交数据按「主动买入」和「主动卖出」分别累加,计算一个「资金流向」指标。如果主动买入量远大于主动卖出量,说明主力在吸筹。

但这里有个坑——逐笔成交数据量极大。A 股一天可能有几百万笔成交,期货市场更是天文数字。你想想看,如果每笔都存下来,一天就是几个 GB 的数据。所以,很多量化团队会选择「降采样」,只保留关键信息。

9.3 交易量聚类:把散兵游勇编成军团

单笔成交数据太碎了。一笔 1 手的交易和一笔 1000 手的交易,在逐笔成交里都是「一条记录」。但它们的意义完全不同。

交易量聚类,就是把连续的小单合并成「大单块」。常用的方法有:

  • 时间窗口聚类:比如每 100 毫秒内的所有成交合并成一个「簇」
  • 价格阈值聚类:价格变动超过 0.1% 时,把之前的成交合并
  • 成交量阈值聚类:累计成交量达到某个阈值(比如 500 手)时,生成一个簇

我曾经用「成交量阈值聚类」做过一个策略:当连续 3 个簇都是主动买入,且每个簇的成交量都超过 1000 手时,我就认为主力在拉升,然后跟单。效果还不错,但要注意——阈值设得太小,全是噪音;设得太大,会错过行情

避坑指南: 我曾经把阈值设成 2000 手,结果在流动性差的品种上,一天都触发不了几次信号。后来改成动态阈值——根据过去 20 个 Tick 的平均成交量来调整。这才解决了问题。

9.4 大单识别:从数据中揪出主力

大单识别,说白了就是「找鲸鱼」。主力资金通常不会一笔砸出几万手,他们会拆单。但拆得再碎,也会留下痕迹。

常用的识别方法:

  • 绝对阈值法:单笔成交超过某个手数(比如 500 手)就算大单
  • 相对阈值法:单笔成交量超过过去 N 笔平均成交量的 3 倍标准差
  • 时间序列法:用算法检测「异常密集的成交序列」

我个人比较喜欢「相对阈值法」。为什么呢?因为不同品种的流动性差异太大了。茅台一手 20 万,螺纹钢一手才 3000 块。用绝对阈值,在茅台上一笔 100 手就是天量,在螺纹钢上 100 手就是毛毛雨。

下面是我常用的一个简单大单识别代码:

def detect_large_trade(trades, window=20, z_threshold=3):
    """
    trades: DataFrame,包含 ['time', 'price', 'volume', 'side']
    window: 滚动窗口大小
    z_threshold: Z-score 阈值
    """
    trades['volume_ma'] = trades['volume'].rolling(window).mean()
    trades['volume_std'] = trades['volume'].rolling(window).std()
    trades['z_score'] = (trades['volume'] - trades['volume_ma']) / trades['volume_std']
    
    large_trades = trades[trades['z_score'] > z_threshold].copy()
    return large_trades

嗯,这里要注意:Z-score 方法假设成交量服从正态分布,但实际数据往往有厚尾。所以阈值设成 3 还是 4,需要根据回测来调。

9.5 知识体系总览

为了让你更直观地理解这些概念之间的关系,我画了一张图:

时间与销售:数据层级与处理流程 Tick 数据 行情快照(有变化才记录) 逐笔成交 每一笔真实成交记录 订单簿快照 买卖盘口深度 数据清洗 & 对齐 去重、补全、时间戳对齐 交易量聚类 时间/价格/成交量阈值 大单识别 绝对阈值 / Z-score 输出指标 资金流向 | 大单频率 | 主动买卖比 | 成交量分布 | 主力痕迹 策略应用:跟单 / 反转 / 突破

这张图展示了从原始数据到策略应用的完整链路。你想想看,如果没有逐笔成交和 Tick 数据,你只能看到 K 线,根本不知道里面发生了什么。有了这些数据,你就能看到市场的微观结构。

9.6 实战中的几个坑

最后,分享几个我踩过的坑:

  • 数据延迟:Tick 数据的时间戳,不同交易所的精度不一样。有的精确到毫秒,有的精确到微秒。做跨交易所策略时,一定要对齐时间。
  • 合并规则:有些数据商把 Tick 数据「合并」了——同一价格的多笔成交合并成一条。如果你用这种数据做逐笔分析,结果会失真。
  • 大单拆单:主力会用算法把大单拆成小单,分散在不同时间点。单纯看单笔成交量,可能识别不出来。这时候需要结合「时间序列聚类」来检测。

一句话总结: Tick 数据是原料,逐笔成交是细节,交易量聚类是工具,大单识别是目的。把这四样东西用好,你就能在订单簿的微观世界里,找到主力的蛛丝马迹。


无相订单流研究社 微信Lucian808555