3. 拥挤度的度量方法:持仓重叠度、交易量异常度、波动率结构、相关性突变

好,咱们直接进入正题。拥挤度这东西,看不见摸不着,但杀伤力极大。怎么量化它?我这些年摸索下来,核心就四个维度:持仓重叠度、交易量异常度、波动率结构、相关性突变。说白了,就是从“谁在里面”、“交易有多疯”、“波动是否异常”、“大家是否一起跑”这四个角度去拆解。

3.1 持仓重叠度:看看谁在“挤”

这个指标最直观。你想想看,如果全市场都在买同一只股票,那肯定挤。我个人习惯用公募基金持仓重叠度来度量。

计算方法:

  • 取前N大公募基金的重仓股列表
  • 计算任意两只基金的重仓股交集数量
  • 除以并集数量,得到Jaccard相似度
  • 对所有基金对取平均,就是当前市场的持仓重叠度

实战经验:我在2020年底做过一次全市场扫描,发现白酒板块的持仓重叠度达到了历史极值——超过0.65。我当时就警觉了,因为历史上超过0.6之后,半年内必然有一次剧烈回调。嗯,后来的事情大家都知道了。

代码示例(Python):

import pandas as pd
import numpy as np

def calculate_overlap(holdings_dict):
    """
    holdings_dict: {fund_name: set(stock_codes)}
    """
    fund_names = list(holdings_dict.keys())
    n = len(fund_names)
    overlap_matrix = np.zeros((n, n))
    
    for i in range(n):
        for j in range(i+1, n):
            set_i = holdings_dict[fund_names[i]]
            set_j = holdings_dict[fund_names[j]]
            intersection = len(set_i & set_j)
            union = len(set_i | set_j)
            overlap_matrix[i][j] = intersection / union if union > 0 else 0
    
    # 返回平均重叠度
    return np.mean(overlap_matrix[overlap_matrix > 0])

避坑指南:我曾经犯过一个错误——只看前十大重仓股。结果发现重叠度很低,但实际持仓高度集中在某几个行业。后来我改成看全部持仓,数据才靠谱。记住:只看头部会漏掉尾部风险

3.2 交易量异常度:市场在“发烧”

拥挤的另一个信号是交易量异常放大。我一般用相对成交量这个指标。

计算公式:

  • 计算过去20天的日均成交量
  • 计算过去5天的日均成交量
  • 两者比值就是交易量异常度
  • 比值超过2.0,说明交易异常活跃
比值范围 拥挤程度 建议操作
< 1.5 正常 可继续持有
1.5 - 2.0 轻度拥挤 开始减仓
2.0 - 3.0 中度拥挤 大幅减仓
> 3.0 极度拥挤 清仓观望

注意:交易量异常度要结合市场环境看。牛市里比值3.0可能只是正常波动,熊市里1.5就要警惕。我一般会做一个滚动分位数,看当前值处于历史什么位置。

3.3 波动率结构:看看“水面”是否平静

拥挤的因子,波动率结构会变得很奇怪。我主要看两个东西:波动率微笑波动率期限结构

波动率微笑:

  • 正常市场:平值期权IV最低,两边高
  • 拥挤市场:虚值看涨期权IV异常高
  • 说明大家都在赌上涨,市场已经“过热”

波动率期限结构:

  • 正常:远期波动率高于近期
  • 拥挤:近期波动率高于远期
  • 说明短期不确定性极大,大家都在抢跑

我的经验:2021年春节前,我观察到沪深300的波动率期限结构出现了罕见的“倒挂”——近月IV比远月高了5个点。我当时就觉得不对劲,果然节后就是一波大跌。这个指标比持仓数据更灵敏,因为它反映的是市场预期

3.4 相关性突变:大家开始“抱团”了

这个指标最微妙。拥挤的因子,内部股票的相关性会突然升高。我一般用滚动相关系数来监测。

具体做法:

  1. 选取因子成分股(比如所有高ROE股票)
  2. 计算两两之间的60日滚动相关系数
  3. 取所有相关系数的平均值
  4. 如果平均值突然跳升超过0.2,就是警报

避坑指南:我曾经踩过一个坑——用全样本计算相关性。结果发现相关性一直很高,因为市场本身就有系统性风险。后来我改成剔除市场因子后的残差相关性,才真正捕捉到拥挤信号。说白了,你要看的是“抱团”效应,而不是“同涨同跌”。

代码示例:

def calculate_residual_correlation(returns, market_returns):
    """
    returns: 个股收益率矩阵 (T x N)
    market_returns: 市场收益率 (T,)
    """
    # 回归剔除市场影响
    from sklearn.linear_model import LinearRegression
    
    residuals = np.zeros_like(returns)
    for i in range(returns.shape[1]):
        model = LinearRegression()
        model.fit(market_returns.reshape(-1, 1), returns[:, i])
        residuals[:, i] = returns[:, i] - model.predict(market_returns.reshape(-1, 1))
    
    # 计算残差相关性
    corr_matrix = np.corrcoef(residuals.T)
    # 去掉对角线
    mask = np.ones(corr_matrix.shape, dtype=bool)
    np.fill_diagonal(mask, 0)
    avg_corr = np.mean(corr_matrix[mask])
    
    return avg_corr

3.5 综合评分:把四个指标揉在一起

单独看一个指标容易误判。我一般会做一个拥挤度综合评分

  • 持仓重叠度:权重30%
  • 交易量异常度:权重25%
  • 波动率结构:权重25%
  • 相关性突变:权重20%

每个指标先做标准化(Z-score),然后加权求和。得分超过2.0,我就开始减仓;超过3.0,直接清仓。

最后提醒:这些指标都不是万能的。我见过一个因子,四个指标全部亮红灯,但硬是又涨了三个月才崩盘。拥挤度识别是概率游戏,不是精确科学。你只能做到“大概率正确”,然后严格执行纪律。

因子拥挤度度量框架 拥挤度综合评分 持仓重叠度 权重30% 交易量异常度 权重25% 波动率结构 权重25% 相关性突变 权重20% 评分规则 Z-score标准化后加权求和 得分 < 1.0:正常 得分 1.0-2.0:轻度拥挤 得分 2.0-3.0:中度拥挤 得分 > 3.0:极度拥挤 建议:得分>2.0开始减仓 得分>3.0清仓观望

这四个维度,说白了就是一套体检指标。持仓重叠度看“体脂率”,交易量异常度看“心率”,波动率结构看“血压”,相关性突变看“血常规”。单独一项异常可能没事,但四项都亮红灯,那肯定得住院了。

我自己的经验是:宁可错杀,不可放过。拥挤度指标发出信号后,即使错了,最多踏空一小段;但对了,能躲过一场灾难。这个盈亏比,值得你认真对待。


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