4. 流动性分组方法论

在上一节中我们已经明确:流动性是刻画股票交易难易程度的核心维度,常用换手率、成交额、Amihud非流动性等指标度量。但要把全市场股票按流动性"分组",仅仅把指标从大到小排个序是远远不够的。分组方法本身会直接影响后续策略测试的结论——同一份流动性数据,用不同的分组逻辑,可能得到截然不同的多空收益曲线。本节聚焦三种最常用的分组设计:分位数分组、行业中性化分组与市值中性化分组,讲清它们各自解决什么问题、如何实现、以及结果如何判读。

一、分位数分组:最直接的全样本切分

分位数分组(Quantile Grouping)是最基础的做法:在每个调仓截面上,把股票按流动性指标排序,然后按分位点切成若干组。假设我们做五分组,则第1组为流动性最低的20%,第5组为流动性最高的20%。实现上通常有两种写法:一是用排序后的序号除以样本数得到分位秩,再按区间切分;二是直接调用分位数函数取切点。

import pandas as pd
import numpy as np

def quantile_group(df, factor_col, n_groups=5):
    # df: 单期截面,含 code 与流动性因子
    df = df.dropna(subset=[factor_col]).copy()
    # 用 rank(pct=True) 得到 0~1 的分位秩,避免重复值导致的切点偏移
    df['pct_rank'] = df[factor_col].rank(pct=True, method='first')
    # 切分为 n_groups 组,标签 1..n_groups,1 为流动性最低
    df['group'] = np.ceil(df['pct_rank'] * n_groups).astype(int)
    df['group'] = df['group'].clip(1, n_groups)
    return df

这里有两个容易被忽略的细节。第一,方向约定必须全文统一:本节约定"第1组=流动性最低",若你的因子是换手率(越大越流动),则第1组对应换手率最小的20%;若用Amihud非流动性(越大越不流动),则第1组对应Amihud最大的20%,方向恰好相反。第二,重复值与缺失值要处理干净:用method='first'打破并列,用dropna剔除缺失,否则ceil切分会出现空组或组内数量严重不均。

分位数分组的优点是简单、可复现、组内样本量均衡;缺点是它不控制任何其他暴露。流动性低的股票往往同时是小市值、冷门行业的股票,因此第1组与第5组之间的收益差异,可能混杂了市值效应和行业效应,无法干净地归因于流动性本身。

二、行业中性化分组:剥离行业结构干扰

行业中性化分组要解决的问题是:不同行业的天然流动性水平差异很大。例如银行、公用事业类股票换手率普遍偏低,而计算机、传媒类股票换手率偏高。如果直接全样本排序,低流动性组可能被银行股"占满",高流动性组被科技股"占满",那么分组收益差实际上是在比较两个行业,而不是在比较流动性。

行业中性化的设计逻辑是:在每个行业内部独立排序分组,再把各行业的同一组别合并。这样每个组都按行业权重均匀地包含了各行业股票,行业结构被"对齐"了。实现步骤如下:

  1. 为每只股票打上行业标签(如申万一级,共31个行业);
  2. 按行业分组,在每个行业内对流动性因子做rank(pct=True);
  3. 在每个行业内按分位秩切分为N组;
  4. 合并所有行业的同组股票,得到最终的行业中性分组。
def industry_neutral_group(df, factor_col, industry_col, n_groups=5):
    df = df.dropna(subset=[factor_col, industry_col]).copy()
    df['pct_rank'] = df.groupby(industry_col)[factor_col]\
                       .rank(pct=True, method='first')
    df['group'] = np.ceil(df['pct_rank'] * n_groups).astype(int)
    df['group'] = df['group'].clip(1, n_groups)
    return df

需要注意一个现实约束:行业内股票数量不足时无法均匀切分。若某行业只有8只股票却要分5组,每组不足2只,分组就失去统计意义。常见处理是:行业内股票数少于n_groups × 最小样本阈值(如每组至少3只,即少于15只)时,将该行业整体并入"其他"或按全样本分位秩处理,并在结果中标注。这一步不做,小行业会产生大量噪声组。

三、市值中性化分组:控制规模效应

市值中性化针对的是流动性研究中最大的混淆变量——市值。A股中流动性指标与市值高度相关:小市值股票成交额小、换手率波动大,大市值股票成交额大但换手率未必高。若不控制市值,流动性分组的收益差很可能只是"小市值溢价"的另一种表达。

市值中性化分组有两种主流实现路径,二者逻辑不同,需按研究目的选择:

路径A:先回归取残差,再分组。在每个截面上,将流动性因子对对数市值做横截面回归,取残差作为"剔除市值影响后的流动性",再对残差做分位数分组。残差为正表示该股票流动性高于同市值水平的预期,为负表示低于预期。

import statsmodels.api as sm

def size_neutral_factor(df, factor_col, mktcap_col):
    df = df.dropna(subset=[factor_col, mktcap_col]).copy()
    df['ln_cap'] = np.log(df[mktcap_col])
    X = sm.add_constant(df['ln_cap'])
    model = sm.OLS(df[factor_col], X).fit()
    df['resid'] = model.resid   # 市值中性化后的流动性
    return df

路径B:市值分层内分组。先按市值把股票分为大、中、小三档(如按市值分位点切三组),再在每个市值档内对流动性做分位数分组,最后合并同组。这种做法更直观,且不假设流动性与市值呈线性关系,适合市值效应非线性明显的市场。

两条路径的差异值得强调:路径A输出的是连续残差,保留了流动性因子的全部信息,但依赖线性假设;路径B输出的是分层后的组别,对非线性更稳健,但会损失档内精细度。实际研究中,若流动性指标与市值关系近似单调,路径A更常用;若怀疑存在"大市值高流动性、小市值低流动性但中间段反转"的非线性结构,路径B更稳妥。

三种流动性分组方法的设计逻辑对比 ① 分位数分组 全样本按流动性排序 rank(pct=True) → 0~1 分位秩 按分位点切 5 组 G1 G2 G3 G4 G5 G1=流动性最低 20%,G5=最高 20% 特点 · 组内样本量均衡 · 实现简单、可复现 · 不控制行业/市值暴露 风险提示 低流动性组可能被银行股 占满,收益差混杂行业效应 与市值效应,归因不干净 ② 行业中性化分组 按行业分组,行业内独立排序 银行 计算机 医药 每个行业内 rank(pct=True) 后切 5 组 各行业 G1 合并 → 低流动性组 各行业 G3 合并 → 中流动性组 各行业 G5 合并 → 高流动性组 特点 · 各组行业结构对齐 · 剥离行业天然流动性差异 · 小行业需合并处理 实现要点 行业内股票 < 15 只时并入"其他" ③ 市值中性化分组 路径 A:回归取残差 流动性 ~ ln(市值) 横截面回归 取残差 → 对残差分 5 组 路径 B:市值分层内分组 大市值 中市值 小市值 每档内对流动性切 5 组,再合并同组 特点 · 剥离市值规模效应 · A 依赖线性假设 · B 对非线性更稳健 选择依据 关系单调 → 路径 A 怀疑非线性 → 路径 B

四、三种方法如何选择与组合

三种方法并非互斥,实际研究中常做双重中性化:先对流动性因子做市值回归取残差,再在行业内对残差做分位数分组。这样既剥离了规模效应,又对齐了行业结构,得到的分组收益差最接近"纯流动性效应"。代价是每一步都会损失一部分样本与信息,且残差的经济含义变得更抽象,解释时要格外谨慎。

选择方法时可按研究目的判断:若只想快速看流动性单调性,用分位数分组即可;若怀疑行业结构主导了结果,加行业中性化;若担心小市值溢价污染结论,加市值中性化。判断是否"分组有效",可观察两点:一是各组股票数量是否均衡(避免空组或极端不均),二是分组后各组在行业分布、市值分布上是否已明显对齐——若对齐后收益单调性消失,说明原结论很可能来自行业或市值暴露而非流动性本身。

分组前务必统一因子方向约定,并在代码注释中写明"第1组=流动性最低"。方向搞反是流动性策略回测中最常见、也最难察觉的错误之一,它会让多空收益符号整体翻转而不报任何错。
行业中性化时,若某行业股票数少于分组数×每组最小样本阈值,不要强行切分。建议将该行业并入"其他"类别或改用全样本分位秩,并在结果表中标注处理方式,否则小行业会产生大量只有1~2只股票的噪声组,严重扭曲组均收益。

最后强调一个实现层面的纪律:三种分组都必须在每个调仓截面上独立执行,不能跨期混排。跨期混排会让同一只股票在不同期落入不同组时缺乏可比性,也会引入前视偏差。把分组函数写成"输入单期截面、输出带组别标签的截面",再按日期循环调用,是保证可复现性的基本工程习惯。