第三章 大单识别算法:从数据中捕捉主力的“手印”

做量化交易这些年,我越来越觉得——大单就是主力的“指纹”。

每一笔异常的大额成交,背后都藏着某个交易员的意图。可能是建仓,可能是出货,也可能是对倒洗盘。而我们要做的,就是把这些“手印”从海量数据里提取出来。

这一章,我带你拆解大单识别的四个核心环节:阈值怎么设、统计怎么做、方向怎么判、频率怎么分析。嗯,都是实战中踩过坑才总结出来的东西。

核心观点:大单识别不是“一刀切”的活儿。不同股票、不同时段、不同市场环境,阈值和算法都得动态调整。死板地用固定阈值,大概率会漏掉真信号,或者被噪音淹没。

3.1 大单阈值设定:别用“拍脑袋”的数值

很多人一上来就问:“大单阈值设多少手合适?”

我的回答是:没有标准答案。你得根据股票的流通盘、日均成交量、价格区间来算。

我个人习惯用两种方法结合:

  1. 绝对阈值法:比如单笔成交≥500手就算大单。适合流动性好的大盘股。
  2. 相对阈值法:比如单笔成交量超过当日均量的3倍。适合中小盘股。

为什么要有相对法?举个例子。一只每天成交只有2000手的冷门股,突然出现一笔500手的单子,这绝对不正常。但同样的500手放在茅台身上,连个水花都溅不起来。

我的经验:我一般用“N倍标准差”法。先算过去20天每笔成交量的均值和标准差,然后设定阈值为:均值 + 2.5倍标准差。这样能自适应不同股票的波动特征。

代码实现也很简单:

import pandas as pd
import numpy as np

def calc_large_trade_threshold(tick_data, window=20, multiplier=2.5):
    """
    动态计算大单阈值
    tick_data: 逐笔成交数据,包含'volume'列
    """
    # 计算滚动均值和标准差
    tick_data['avg_vol'] = tick_data['volume'].rolling(window=window).mean()
    tick_data['std_vol'] = tick_data['volume'].rolling(window=window).std()
    
    # 阈值 = 均值 + 倍数 * 标准差
    tick_data['threshold'] = tick_data['avg_vol'] + multiplier * tick_data['std_vol']
    
    # 标记大单
    tick_data['is_large'] = tick_data['volume'] > tick_data['threshold']
    
    return tick_data

这里有个坑——如果股票突然停牌后复牌,或者遇到分红送股,成交量会剧烈变化。我建议在计算前先做“异常值剔除”,把那些明显是数据错误的记录过滤掉。

3.2 大单统计方法:别只看总数,要看结构

统计大单,很多人只算“今天有多少笔大单”。这太粗糙了。

我一般从三个维度去拆解:

  • 时间维度:大单集中在开盘、盘中还是尾盘?不同时段意义完全不同。
  • 价格维度:大单是在买一价成交,还是在卖一价成交?这能看出主动性。
  • 金额维度:同样1000手,在10块钱和100块钱的股票里,资金量差10倍。

举个例子。我曾经分析过一只票,发现它每天尾盘最后5分钟都有连续的大单买入。一开始以为是主力吸筹,后来仔细一看——全是挂单在买一价,但就是不往上吃。说白了,这是在做收盘价,方便第二天出货。

注意:统计大单时,一定要区分“主动成交”和“被动成交”。主动成交的单子才是真金白银在推动价格,被动成交可能是挂单被扫,意义不同。

我常用的统计代码:

def classify_large_trades(tick_data):
    """
    分类统计大单:按方向、时段、价格区间
    """
    # 标记买卖方向(假设有'price'和'last_price'字段)
    tick_data['direction'] = np.where(
        tick_data['price'] > tick_data['last_price'], 
        'buy',  # 主动买入
        np.where(tick_data['price'] < tick_data['last_price'], 
                 'sell',  # 主动卖出
                 'neutral')  # 中性
    )
    
    # 按小时分组统计
    hourly_stats = tick_data[tick_data['is_large']].groupby(
        tick_data['time'].dt.hour
    ).agg({
        'volume': 'sum',
        'amount': 'sum',
        'direction': lambda x: (x == 'buy').sum() / len(x)  # 买入占比
    })
    
    return hourly_stats

3.3 大单方向判断:别被“红绿”骗了

很多人以为:红色就是买入,绿色就是卖出。大错特错。

交易所的逐笔成交数据里,颜色只代表“成交价格相对于前一笔是涨还是跌”,不代表买卖方向。真正的方向判断,得用“主动性”逻辑。

我判断大单方向的方法很简单:

  1. 价格比较法:如果成交价 > 卖一价,说明买方主动扫货,这是真买入。
  2. 挂单变化法:如果大单成交后,买一挂单明显减少,说明是卖方主动砸盘。
  3. 时间优先法:同一价格下,先挂单的是被动方,后成交的是主动方。

嗯,这里要注意。有些主力会用“对倒”手法——自己买自己卖,制造虚假的成交量。怎么识别?看买卖双方的席位号是否相同,或者成交时间是否极其密集。

避坑指南:我曾经在分析一只妖股时,发现连续三天都有大量“主动买入”的大单。结果一查席位,全是同一个营业部在左手倒右手。从那以后,我每次做大单方向判断,都会加一道“席位去重”的过滤。

3.4 大单频率分析:密集程度比单笔大小更重要

单笔大单可能是偶然,但连续密集的大单一定是主力行为。

我一般用“单位时间内的大单笔数”来衡量频率。比如:

  • 低频大单:每分钟不到1笔。可能是机构调仓,也可能是散户跟风。
  • 中频大单:每分钟1-3笔。大概率是主力在分批建仓或出货。
  • 高频大单:每分钟超过5笔。基本可以确定是主力在集中操作。

为什么会这样?你想想看,散户哪有能力在1分钟内连续下5笔百万级的大单?只有程序化交易或者主力操盘手才能做到。

我常用的频率分析代码:

def analyze_trade_frequency(tick_data, freq='1min'):
    """
    分析大单出现的频率密度
    """
    # 筛选大单
    large_trades = tick_data[tick_data['is_large']]
    
    # 按时间窗口统计笔数
    freq_stats = large_trades.resample(freq, on='time').size()
    
    # 定义频率等级
    def classify_freq(count):
        if count <= 1:
            return 'low'
        elif count <= 3:
            return 'medium'
        else:
            return 'high'
    
    freq_stats = freq_stats.apply(classify_freq)
    
    return freq_stats

我的习惯:我会把频率分析和价格走势叠加来看。如果大单频率突然升高,但价格没怎么动,说明有人在偷偷吸筹。如果频率高且价格急涨,那可能是拉升前的试盘。

知识体系总览

下面这张图,我把大单识别算法的四个核心环节串起来了。你可以把它当作一个检查清单——每次分析前,先过一遍这四个步骤。

大单识别算法核心流程 阈值设定 绝对阈值 / 相对阈值 统计方法 时间/价格/金额维度 方向判断 价格比较 / 挂单变化 频率分析 低/中/高频分类 N倍标准差法 主动/被动成交 席位去重过滤 时间窗口统计 输出:主力意图信号 建仓 / 出货 / 对倒 / 试盘 四个环节缺一不可,顺序执行才能得到可靠的主力意图信号

这四个环节,每一个单独拿出来都能写一整章。但实战中,它们必须串联起来用。阈值设错了,后面统计的都是垃圾数据;方向判反了,频率分析再准也没用。

我建议你从最简单的“绝对阈值+价格比较法”开始,跑通一个最小可用版本。然后慢慢加入动态阈值、席位过滤、频率分析这些高级功能。别想一口吃成胖子。

最后说一句:大单识别只是第一步。识别出大单后,怎么跟盘口挂单、资金流向、技术形态结合起来判断,才是真正的功力。这些内容,我们后面的章节会逐一展开。


公众号:蓝海资料掘金营,微信deep3321