大单识别逻辑:如何定义大单?
做盘口分析,第一个绕不开的问题就是:到底多大的单子才算大单?
这个问题听起来简单,但我在实际项目中踩过不少坑。刚开始做量化的时候,我天真地以为“单笔超过100手就算大单”。结果呢?茅台和工商银行的100手,那能一样吗?
所以今天咱们就来聊聊,怎么科学地定义大单。
一、大单的本质是什么?
说白了,大单就是显著偏离当前市场正常交易规模的订单。
你想想看,一只股票平时每笔成交就几手、十几手,突然蹦出来一笔500手的单子——这肯定不正常。但如果是一只日均成交几千万股的大盘股,500手可能只是毛毛雨。
所以,定义大单不能搞“一刀切”。
我个人习惯从两个维度来考量:
- 成交量维度:单笔成交的手数
- 成交金额维度:单笔成交的金额
两个维度各有优劣,咱们一个一个说。
二、基于成交量的阈值设定
成交量阈值,就是设定一个手数门槛。比如“单笔超过200手就算大单”。
这个方法的好处是直观、计算快。但问题也很明显——不同股票的价格差异太大了。
举个例子:
| 股票 | 股价 | 200手金额 | 是否合理? |
|---|---|---|---|
| 贵州茅台 | 1800元 | 360万元 | ✅ 绝对算大单 |
| 工商银行 | 5元 | 10万元 | ❌ 可能只是普通单 |
| 某ST股 | 1.5元 | 3万元 | ❌ 散户都能做到 |
看到问题了吧?同样的200手,在不同股票上的资金含义天差地别。
那怎么办?
我建议用相对阈值,而不是绝对阈值。
具体做法:
- 统计该股票过去N天的平均每笔成交量
- 设定一个倍数,比如3倍或5倍
- 超过这个倍数的,就算大单
代码实现起来也很简单:
import pandas as pd
import numpy as np
def detect_large_trade_by_volume(trades, multiplier=5, window=20):
"""
基于成交量的相对大单识别
Parameters:
- trades: DataFrame, 包含'volume'列
- multiplier: 倍数阈值
- window: 统计窗口天数
Returns:
- 标记为大单的布尔序列
"""
# 计算滚动平均每笔成交量
avg_volume = trades['volume'].rolling(window).mean()
# 标记大单
is_large = trades['volume'] > avg_volume * multiplier
return is_large
嗯,这里要注意:窗口大小的选择很关键。窗口太小,均值不稳定;窗口太大,反应太迟钝。我个人习惯用20个交易日,也就是一个月左右。
三、基于成交金额的阈值设定
成交金额维度,其实更能反映资金的真实意图。
为什么?因为资金看的是钱,不是手数。一个机构要建仓,他关心的是“我要花多少钱”,而不是“我要买多少手”。
我见过不少交易员,只看手数不看金额,结果把几百万的小单当大单,把几十万的机构单当普通单——这坑我踩过。
基于金额的阈值设定,同样建议用相对法:
- 计算该股票过去N天的平均每笔成交金额
- 设定倍数阈值(比如3倍)
- 超过的标记为大单
代码示例:
def detect_large_trade_by_amount(trades, multiplier=3, window=20):
"""
基于成交金额的相对大单识别
Parameters:
- trades: DataFrame, 包含'amount'列(单位:元)
- multiplier: 倍数阈值
- window: 统计窗口天数
Returns:
- 标记为大单的布尔序列
"""
# 计算滚动平均每笔成交金额
avg_amount = trades['amount'].rolling(window).mean()
# 标记大单
is_large = trades['amount'] > avg_amount * multiplier
return is_large
四、综合阈值:双维度联合判定
单一维度总会有盲区。比如:
- 一只低价股,突然出现大量手数但金额不大——可能是散户跟风
- 一只高价股,手数不多但金额巨大——可能是机构在吸筹
所以,我建议用双维度联合判定。
具体逻辑:
- 先分别计算成交量和成交金额的相对阈值
- 设定一个“大单分数”
- 两个维度都超过阈值的,标记为“强信号大单”
- 只有一个维度超过的,标记为“弱信号大单”
代码实现:
def detect_large_trade_combined(trades, vol_mult=5, amt_mult=3, window=20):
"""
双维度联合大单识别
Returns:
- DataFrame, 包含'is_large_vol', 'is_large_amt', 'large_signal'列
"""
df = trades.copy()
# 计算滚动均值
avg_vol = df['volume'].rolling(window).mean()
avg_amt = df['amount'].rolling(window).mean()
# 单维度标记
df['is_large_vol'] = df['volume'] > avg_vol * vol_mult
df['is_large_amt'] = df['amount'] > avg_amt * amt_mult
# 联合判定
conditions = [
(df['is_large_vol'] & df['is_large_amt']), # 双维度都满足
(df['is_large_vol'] | df['is_large_amt']) # 至少一个满足
]
choices = ['strong', 'weak']
df['large_signal'] = np.select(conditions, choices, default='none')
return df
- 成交量阈值:适合识别“量异常”,但受股价影响大
- 金额阈值:适合识别“资金异常”,更稳定
- 联合判定:取两者交集,信号更可靠
五、避坑指南
我曾经犯过一个错误:把“大单”和“主力资金”直接划等号。
后来发现,有些大单是对倒单(左手倒右手),有些是拆单后的汇总(比如算法交易),还有些是乌龙指(手滑了)。
所以,识别出大单只是第一步。你还需要结合:
- 盘口挂单变化:大单成交前后,买卖盘口有没有异常
- 时间分布:是开盘、盘中还是尾盘出现的
- 价格影响:大单成交后,价格是突破还是反转
这些内容,后面的章节会详细展开。
六、本章知识体系
下面这张图,帮你梳理大单识别的完整逻辑:
这张图把整个逻辑串起来了。从最底层的单维度识别,到双维度联合判定,再到最终的信号输出——每一步都有讲究。
好了,大单识别的基础逻辑就讲到这里。记住:没有完美的阈值,只有不断优化的方法。多复盘、多测试,找到适合你交易品种的参数,这才是正道。
公众号:蓝海资料掘金营,微信deep3321