宽度指标构建:上涨家数占比、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()}")
知识体系总览
下面这张图是我自己梳理的宽度指标框架,方便你理解它们之间的关系:
组合使用策略
单独用任何一个指标,都容易出错。我自己的策略里,会把五个指标组合成一个「宽度评分系统」:
- 上涨家数占比 > 60% → +1分
- ADL线处于上升趋势 → +1分
- 麦克莱伦指标 > 0 → +1分
- 新高新低比 > 50% → +1分
- 宽度推力触发信号 → +2分
总分0-2分:轻仓或空仓;3-4分:半仓;5-6分:重仓。这个系统帮我躲过了好几次假突破,也让我在真行情来临时不会踏空。
最后说一句:宽度指标不是万能的。在极端行情下(比如2020年3月流动性危机),所有宽度指标都会失效。那时候,保命比赚钱重要。
公众号:蓝海资料掘金营,微信deep3321