Alpha101 这类量价因子的公式是公开的。公开意味着任何人都能照着复现,也意味着市场上可能有一大批账户持有几乎一样的仓位。

这件事平时看不出来。行情正常的时候,大家都赚钱或者都不赚钱,各过各的。问题出在压力期:一旦有人开始减仓,同样的持仓会被同时抛售,多头和空头一起被打——多头砸下去,空头轧上来,两边同时亏。

2007 年 8 月发生过一次教科书级别的案例。多家量化基金在几天内出现远超模型预期的回撤,而市场整体几乎没动。Khandani 和 Lo 的《What Happened to the Quants in August 2007?》复盘了这个过程:起因是某些机构因为其他资产的问题被迫去杠杆,平掉的量化仓位触发了同类持仓的连锁反应。持有相同因子暴露的账户,谁都没做错什么,一起亏了。

想提前知道自己有没有站在这样的位置上,就得算拥挤度。

拥挤度为什么没法直接测

拥挤度想回答的问题是「有多少钱压在同一个信号上」。这个数没有任何地方可以直接查——没人公布自己的因子仓位。

所以所有拥挤度指标都是代理:找一个能被观测到、且和「资金拥挤」有稳定关联的量,用它去逼近。

代理有代理的代价。每个指标都会在某些情况下给出错误信号,而且它们之间经常打架。实操里通常是几个一起看,取一致的方向。

五种算法

一、估值价差(valuation spread)

思路。把因子的多头组合和空头组合分别算一个估值指标(P/B、P/E、EV/EBITDA 都行),取比值:

VSt=median(P/B)longmedian(P/B)short\text{VS}_t = \frac{\text{median}(P/B)_{\text{long}}}{\text{median}(P/B)_{\text{short}}}

因子被大量买入时,多头那一篮子会被推贵,空头那一篮子被压便宜,比值往上走。价差越宽,说明这个因子已经被交易得越充分,未来的收益空间被提前透支。

用法。看 VSt\text{VS}_t 相对自身历史的 z 分数,不看绝对值。不同因子的估值价差绝对水平天差地别,横向比没有意义。

zt=VStμ(VS)σ(VS)z_t = \frac{\text{VS}_t - \mu(\text{VS})}{\sigma(\text{VS})}

数据要求。基本面数据,而且必须是 point-in-time 的——用今天的财报数据去回填三年前的持仓,会得到一个完全失真的序列。

盲区。对价值类因子最有效,因为它本身就是估值驱动的。对纯量价因子(动量、反转、波动率)效果差很多,多空两边的估值分布可能根本没系统性差异。Alpha101 大多属于后者,用这个指标去测它们基本白费力气。

二、空头利用率(short interest / utilization)

思路。空头这一腿更容易观测。融券余额、券源利用率、days-to-cover 都是公开或半公开数据。

DTCi=ShortInterestiADVi\text{DTC}_i = \frac{\text{ShortInterest}_i}{\text{ADV}_i} Utilizationi=已借出券量i可借券总量i\text{Utilization}_i = \frac{\text{已借出券量}_i}{\text{可借券总量}_i}

对因子的空头组合取加权平均,得到一个组合层面的拥挤度。利用率逼近 100%、days-to-cover 高的时候,说明这批票的空头已经很挤——一旦要平仓,需要好几天的成交量才能出得来,轧空的条件已经具备。

数据要求。美股的 short interest 是双周披露,滞后大约两周。券商的实时利用率数据一般要付费。

盲区。只看得到空头。多头拥挤(大家一起买同一批票)在这个指标上完全不显示。而且披露滞后两周,对快速积累的拥挤反应不过来。

三、成对相关性(pairwise correlation)

思路。同一批钱在同时买卖同一批票的时候,这些票的日内和日间走势会变得更同步。算组合内所有标的的两两相关,取平均:

ρˉt=2N(N1)i<jρij,t\bar{\rho}_t = \frac{2}{N(N-1)}\sum_{i<j}\rho_{ij,t}

ρij,t\rho_{ij,t} 用滚动窗口(60 日常见)算。这个均值相对自身历史往上跳,是拥挤在积累的信号。

更干净的做法是先把市场因子回归掉,用残差算相关。否则大盘一波动,所有相关性都会同时上升,跟拥挤没关系。

ri,t=αi+βirm,t+εi,tr_{i,t} = \alpha_i + \beta_i r_{m,t} + \varepsilon_{i,t}

ε\varepsilon 序列去算 ρˉ\bar{\rho}

数据要求。只要价格。这是五个里门槛最低的,个人完全做得起来。

盲区。行业集中会污染结果。如果组合里一半是半导体股,它们的残差相关本来就高,这跟拥挤没关系。需要先做行业中性化,或者至少分行业看。

四、因子收益的波动与自相关

思路。拥挤会改变因子收益序列本身的形状。资金持续流入的阶段,因子收益的自相关会变正(趋势变强);同时波动率上升。这两个一起出现,通常意味着行情由资金流推着走,基本面在这个阶段说了不算。

AC1(t)=corr(ft,ft1)(滚动窗口)\text{AC}_1(t) = \text{corr}\big(f_{t}, f_{t-1}\big) \quad \text{(滚动窗口)}

ftf_t 是因子的多空组合日收益。

还有一个更直接的信号:回撤的形状。拥挤因子的回撤特征是又快又深,几天之内跌完一年的超额。慢慢磨出来的回撤通常另有原因。如果你的因子历史回撤里出现过前一种形态,它大概率被拥挤过。

数据要求。只要因子的历史收益序列,自己的回测就能产出。

盲区。这是滞后指标。它在拥挤已经形成、甚至已经开始出清的时候才亮灯,用来事后归因比事前预警好用。

五、持仓重叠度(overlap)

思路。如果能拿到别人的持仓,直接算重叠是最准的。机构的 13F 是季度披露的公开数据,可以用来算你的组合和主流量化基金持仓的交集:

Overlap=imin(wimine,witheirs)\text{Overlap} = \sum_i \min(w_i^{\text{mine}}, w_i^{\text{theirs}})

拿不到持仓时的替代做法。算自己的因子排名和几个公开因子排名的相关性。

ρrank=corr(rank(fmine),rank(fpublic))\rho_{\text{rank}} = \text{corr}\big(\text{rank}(f^{\text{mine}}), \text{rank}(f^{\text{public}})\big)

fpublicf^{\text{public}} 用 Fama-French 那几个因子,或者任何一个你能复现的广为人知的信号。相关性高,说明你的信号和公开信号在选同一批票,那么公开信号的拥挤度就是你的拥挤度。

跑公开公式的人尤其该量一下这个数。公式人人可见,持仓大概率高度重合,重合到什么程度是可以算出来的。

数据要求。13F 数据有免费源但清洗麻烦,季度频率也太粗。排名相关性版本只要价格数据。

盲区。13F 只覆盖美股多头,不含空头和衍生品,也不含对冲基金的全部仓位。季度滞后对高换手策略基本没用。

怎么合成一个能用的数

单个指标都有盲区,实操里一般合成。最简单的做法是各自转成 z 分数再取平均:

Ct=1Kk=1Kzk,tC_t = \frac{1}{K}\sum_{k=1}^{K} z_{k,t}

有几个细节值得注意:

用 z 分数,不用原始值。每个指标的量纲和分布完全不同,不标准化就没法加。

z 分数的窗口要够长。至少两三年,否则「相对自身历史」这个基准会跟着短期波动漂移。窗口太短的话,缓慢积累的拥挤会被当成新常态,指标一直显示正常。

不要给拥挤度设绝对阈值。「z > 2 就减仓」这种规则听着爽,但 z 分数本身依赖于你选的窗口和指标组合,换一组就是另一个数。更实际的用法是看方向和斜率:这个季度比上个季度挤了多少,加速了还是在缓解。

算出来之后能干什么

别拿它当交易信号。拥挤度和未来收益之间没有稳定的可交易关系。因子可以在高度拥挤的状态下继续赚一年钱,也可以在看起来不挤的时候崩掉。用它来择时进出,多半是给自己加噪音。

拿它调风险敞口。这是我认为最合理的用法。拥挤度高的时候,把杠杆降下来、把单因子的权重上限收紧、把止损带放宽一点(因为拥挤期的正常波动就是更大)。目标是在出清发生的时候少亏。至于出清哪天到,别指望能预测出来。

拿它做事后归因。策略回撤的时候,先看拥挤度指标那几天有没有异动。有异动,这次回撤大概率是流动性事件,扛住或者降杠杆就行;没异动,才该怀疑因子本身失效,那是要改模型的。这两件事经常被混为一谈,处理方式完全相反。

拿它决定要不要继续用一个因子。这是最根本的一层。如果一个因子的拥挤度长期处在高位,说明它的超额已经被交易得差不多了。与其在上面调参数,不如去找相关性更低的信号。

从哪个指标开始

五个指标的落地成本差得很远。按门槛从低到高:

  1. 残差成对相关性——只要价格数据,回测框架里直接就能加
  2. 排名相关性——把自己的组合排名和几个公开因子对一下,量化重合度
  3. 因子收益的自相关和回撤形态——历史收益序列已经有了,纯粹是算不算的问题
  4. 空头利用率——要买数据,但对做空的策略值这个钱
  5. 估值价差——要 point-in-time 基本面数据,且只对价值类因子有用

前三个不需要新增任何数据源,一个下午就能加上。绝大多数人卡在拥挤度上,卡的是没排优先级,不是数据不够。

先把最便宜的那个装上,让它跑起来产出一条时间序列。拥挤度这种东西,只有攒够历史才有参照系——今天的读数单看毫无意义,它必须和自己过去两三年比。越早开始记,越早能用。