宽度指标构建:上涨家数占比、ADL线、麦克莱伦指标、新高新低比、宽度推力指标

市场宽度,说白了就是看「多少股票在跟着大盘走」。我刚开始做量化那会儿,总盯着指数涨跌,结果吃了不少亏。有一次指数涨了1.5%,我满心欢喜以为持仓要起飞,结果账户是绿的。后来才明白——指数被几只权重股绑架了,大部分股票其实在跌。

从那以后,宽度指标就成了我策略里的「标配」。今天咱们就把五个核心宽度指标讲透:上涨家数占比、ADL线、麦克莱伦指标、新高新低比、宽度推力指标。

1. 上涨家数占比(Advance Ratio)

这个指标最简单,也最直观。公式就一句话:

上涨家数占比 = 上涨家数 / (上涨家数 + 下跌家数) × 100%

我习惯把它当成「市场情绪的温度计」。数值超过70%,说明市场情绪亢奋;低于30%,说明恐慌情绪蔓延。但这里有个坑——平盘家数怎么处理?

避坑指南:我曾经在回测时直接把平盘家数扔了,结果发现指标在震荡市里频繁发出错误信号。后来我改成:分母只算上涨+下跌,平盘单独记录但不参与计算。这样信号干净多了。

代码实现也很简单:

import pandas as pd

def advance_ratio(up, down):
    """
    计算上涨家数占比
    up: 上涨家数序列
    down: 下跌家数序列
    """
    return up / (up + down) * 100

# 示例:某日上涨1200家,下跌800家
ratio = advance_ratio(1200, 800)
print(f"上涨家数占比: {ratio:.1f}%")
# 输出: 上涨家数占比: 60.0%

2. ADL线(Advance-Decline Line)

ADL线是宽度指标里的「老大哥」。它把每天的上涨家数减去下跌家数,然后累加起来。公式:

ADL = Σ(上涨家数 - 下跌家数)

你想想看,如果ADL线和指数走势出现背离,那往往意味着趋势要变。我记得2020年3月美股熔断那会儿,标普500还在跌,但ADL线已经提前两周开始走平了。这就是典型的「底背离」信号。

核心用法:

  • ADL与指数同步上涨 → 健康牛市
  • ADL创新高,指数没跟上 → 指数可能补涨
  • 指数创新高,ADL没跟上 → 警惕见顶

代码实现:

def adl_line(up, down):
    """
    计算ADL线
    up: 上涨家数序列
    down: 下跌家数序列
    """
    net_advance = up - down
    adl = net_advance.cumsum()
    return adl

# 示例:5日数据
up = pd.Series([1200, 1100, 1300, 900, 1400])
down = pd.Series([800, 900, 700, 1100, 600])
adl = adl_line(up, down)
print(adl)
# 输出: [400, 600, 1200, 1000, 1800]

3. 麦克莱伦指标(McClellan Oscillator)

这个指标是ADL的「升级版」。它用EMA(指数移动平均)对ADL做了平滑处理,公式:

McClellan = EMA(ADL, 19) - EMA(ADL, 39)

为什么选19和39?这是麦克莱伦兄弟当年用大量数据测试出来的最优参数。我个人习惯在A股上微调成20和40,效果差不多。

用法上,我总结了三句话:

  • 指标上穿0轴 → 短期走强
  • 指标下穿0轴 → 短期走弱
  • 指标超过+100或低于-100 → 超买/超卖

小技巧:我在实盘中会把麦克莱伦指标和成交量结合起来看。如果指标上穿0轴时成交量放大,那这个信号的可靠性会高很多。反之,缩量上穿0轴,我一般会再等一天确认。

代码实现:

def mcclellan_oscillator(adl, short_period=19, long_period=39):
    """
    计算麦克莱伦指标
    adl: ADL线序列
    """
    ema_short = adl.ewm(span=short_period, adjust=False).mean()
    ema_long = adl.ewm(span=long_period, adjust=False).mean()
    return ema_short - ema_long

# 接上面ADL的例子
mcclellan = mcclellan_oscillator(adl)
print(mcclellan)

4. 新高新低比(NH/NL Ratio)

这个指标看的是「创52周新高和新低的股票数量之比」。公式:

新高新低比 = 新高家数 / (新高家数 + 新低家数) × 100%

嗯,这里要注意——52周是个经验值。我在做短线策略时,会把周期缩短到20个交易日;做长线配置时,才用252个交易日。

为什么这个指标重要?因为它能提前告诉你「领头羊在撤退」。我记得2021年春节后,A股核心资产还在涨,但新高新低比已经连续三周下滑了。我当时就觉得不对劲,减了一半仓位。后来果然迎来了一波调整。

实战阈值:

数值区间市场状态操作建议
> 70%强势市场持股为主
30% - 70%震荡市场高抛低吸
< 30%弱势市场减仓观望

代码实现:

def nh_nl_ratio(new_high, new_low):
    """
    计算新高新低比
    """
    return new_high / (new_high + new_low) * 100

# 示例:某日新高50家,新低10家
ratio = nh_nl_ratio(50, 10)
print(f"新高新低比: {ratio:.1f}%")
# 输出: 新高新低比: 83.3%

5. 宽度推力指标(Breadth Thrust)

这个指标是马丁·茨威格发明的,用来捕捉「市场从极度悲观到乐观的瞬间爆发」。计算方法是:

宽度推力 = 10日EMA(上涨家数占比)

触发条件:宽度推力从低于40%的位置,在10个交易日内快速拉升到61.5%以上。

为什么是61.5%?茨威格当年统计发现,这个阈值能有效过滤掉假信号。我在A股上测试过,效果也不错,但建议把阈值微调到60%。

避坑指南:我曾经在2018年熊市里连续遇到三次「假突破」——宽度推力刚到60%就掉头向下。后来我加了一个过滤条件:必须伴随成交量放大20%以上。从那以后,信号质量提升了不少。

代码实现:

def breadth_thrust(advance_ratio, period=10, threshold=61.5):
    """
    计算宽度推力指标
    """
    ema_ratio = advance_ratio.ewm(span=period, adjust=False).mean()
    # 检测是否从低于40%快速拉升到阈值以上
    low_point = ema_ratio < 40
    thrust_signal = (ema_ratio > threshold) & low_point.shift(period).fillna(False)
    return ema_ratio, thrust_signal

# 示例
import numpy as np
np.random.seed(42)
ratios = pd.Series(np.random.uniform(30, 70, 100))
ema, signals = breadth_thrust(ratios)
print(f"触发信号次数: {signals.sum()}")

知识体系总览

下面这张图是我自己梳理的宽度指标框架,方便你理解它们之间的关系:

市场宽度指标知识体系 市场宽度指标 上涨家数占比 基础情绪温度计 ADL线 累积涨跌差 麦克莱伦指标 ADL的EMA平滑 新高新低比 领头羊强度 宽度推力指标 爆发信号捕捉 五个指标从不同维度刻画市场宽度,建议组合使用 💡 建议:先用上涨家数占比判断情绪,再用ADL和麦克莱伦确认趋势,新高新低比和宽度推力辅助择时

组合使用策略

单独用任何一个指标,都容易出错。我自己的策略里,会把五个指标组合成一个「宽度评分系统」:

  1. 上涨家数占比 > 60% → +1分
  2. ADL线处于上升趋势 → +1分
  3. 麦克莱伦指标 > 0 → +1分
  4. 新高新低比 > 50% → +1分
  5. 宽度推力触发信号 → +2分

总分0-2分:轻仓或空仓;3-4分:半仓;5-6分:重仓。这个系统帮我躲过了好几次假突破,也让我在真行情来临时不会踏空。

最后说一句:宽度指标不是万能的。在极端行情下(比如2020年3月流动性危机),所有宽度指标都会失效。那时候,保命比赚钱重要。


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