引言
你是否曾经追过一个看似强势的行情,最后才发现——整个指数的上涨其实只靠两三只股票在撑?这就是所谓的"窄幅上涨",它脆弱且危险。
2021 年发表在 Economic Modelling 上的一篇论文,研究了 64 个国家从 1973 年到 2018 年的市场数据,发现**市场广度(Market Breadth)**是未来股票收益的稳健预测因子。简单来说,市场广度衡量的是"有多少只股票在真正参与上涨"。
今天我们就来拆解这个概念,并用 Python 实现一个简单的市场广度过滤器,帮助你在实际交易中做出更理性的判断。
什么是市场广度?
市场广度的核心问题是:这波行情是真的吗?
论文将市场广度定义为:一个投资组合中,上涨股票数量与下跌股票数量的差值。
举个形象的例子:想象你的投资组合是一部电梯。价格是电梯显示屏上的楼层数,而广度则代表电梯里到底站满了人,还是只有一个拎着大包小包的人在猛按按钮。
当广度强劲时,上涨的股票多于下跌的股票。这虽然不能保证你一定赚钱,但这种动量更加"分散受力",也更加稳健。
论文的关键发现包括:
- • 高广度组合显著跑赢低广度组合,且在控制了规模、动量、波动率、偏度、风格等因素后依然成立。
- • 广度效应在套利限制较高的市场、牛市之后以及集体主义文化的社会中尤其显著——这支持了行为金融学的解释。
- • 广度与羊群效应有关:有时候羊群行为是信息在系统中传播,有时候则是踩踏。
小心交易成本吞噬你的信号
在实际交易中,一个看似有效的信号可能被交易成本完全吃掉。来看一个简单的算术:
假设一个基于广度的国家轮动策略,每月毛收益为 +0.30%(约年化 +3.6%)。每次调仓的摩擦成本(价差 + 滑点 + 佣金)为买入 0.10% + 卖出 0.10% = 0.20%。
按月调仓:
净收益 = 0.30% − 0.20% = 0.10%/月,仍然为正。
按周调仓(每月约 4 次):
月成本 = 0.20% × 4 = 0.80%
净收益 = 0.30% − 0.80% = −0.50%/月,直接亏损!
论文也明确指出:频繁调仓会导致交易成本侵蚀策略的盈利能力。所以,先算账,再交易。
Python 实现:市场广度计算器
下面是一个用 Python 实现的市场广度计算函数,代码简洁且实用:
import pandas as pd
import numpy as np
def calculate_breadth(close_prices: pd.DataFrame) -> pd.DataFrame:
"""
计算市场广度指标。
参数:
close_prices: DataFrame,每列为一只股票的收盘价,索引为日期。
返回:
包含广度指标的 DataFrame。
"""
# 计算每日收益率
ret = close_prices.pct_change().fillna(0)
# 统计上涨和下跌的股票数量
up = (ret > 0).sum(axis=1)
# 当日上涨的股票数
down = (ret < 0).sum(axis=1) # 当日下跌的股票数
total = close_prices.shape[1] # 股票总数
# 计算广度指标
breadth = up - down # 原始广度值
breadth_pct = 100.0 * (breadth / total) # 广度百分比
return pd.DataFrame({
'up': up, # 上涨数量
'down': down, # 下跌数量
'breadth': breadth, # 广度值
'breadth_pct': breadth_pct # 广度百分比
})
实战案例:5 天广度冲刺实验
论文的理论很扎实,但最好的学习方式是亲手实验。下面是一个你可以在一周内完成的实战方案。
第 1 步:选择一个股票池
可以是某个指数的成分股、一组国家 ETF,或者你自己的 30–60 只股票观察清单。
第 2 步:定义广度指标
使用最简单的公式:
每日广度 = 当日上涨股票数 − 当日下跌股票数
如果需要标准化:
广度百分比 = ((上涨数 − 下跌数) / 总数) × 100
第 3 步:每天记录一次
每天收盘后记录:总股票数、上涨数、下跌数、广度值、当日指数收益率。
第 4 步:制定下周决策规则
在第 5 天,根据 5 天累计广度做出一个决策:
- • 如果 5 天累计广度为正 → 允许买入突破或加仓。
- • 如果 5 天累计广度为负 → 仅减仓、对冲或持有现金。
下面是完整的 Python 示例代码:
import pandas as pd
import numpy as np
def calculate_breadth(close_prices: pd.DataFrame) -> pd.DataFrame:
"""计算市场广度指标"""
ret = close_prices.pct_change().fillna(0)
up = (ret > 0).sum(axis=1)
down = (ret < 0).sum(axis=1)
total = close_prices.shape[1]
breadth = up - down
breadth_pct = 100.0 * (breadth / total)
return pd.DataFrame({
'up': up,
'down': down,
'breadth': breadth,
'breadth_pct': breadth_pct
})
def breadth_filter(breadth_df: pd.DataFrame, window: int = 5) -> pd.Series:
"""
基于滚动窗口的广度过滤器。
参数:
breadth_df: calculate_breadth() 的返回结果。
window: 滚动窗口天数,默认为 5 天。
返回:
布尔型 Series,True 表示允许做多,False 表示应规避风险。
"""
# 计算滚动 N 天的累计广度
rolling_breadth = breadth_df['breadth'].rolling(window=window).sum()
# 累计广度为正时,允许做多;否则规避风险
allow_long = rolling_breadth > 0
return allow_long
# ===== 模拟数据示例 =====
np.random.seed(42)
# 模拟 10 只股票、20 个交易日的收盘价数据
dates = pd.bdate_range(start=
'2026-02-01', periods=20) # 生成工作日日期
stocks = [f'股票_{i+1}' for i in range(10)] # 10 只股票
# 以 100 为基准价格,叠加随机涨跌生成模拟价格
price_data = 100 + np.cumsum(np.random.randn(20, 10) * 0.5, axis=0)
close_prices = pd.DataFrame(price_data, index=dates, columns=stocks)
# 计算广度
breadth_df = calculate_breadth(close_prices)
# 应用 5 天广度过滤器
signal = breadth_filter(breadth_df, window=5)
# 合并结果并展示
result = breadth_df.copy()
result['累计广度信号'] = signal.map({True: '许做多', False: '规避风险'})
print("===== 市场广度分析结果 =====\n")
print(result.to_string())
print("\n===== 最新交易信号 =====")
print(f"最新日期:{result.index[-1].strftime('%Y-%m-%d')}")
print(f"当日广度:{result['breadth'].iloc[-1]}")
print(f"交易建议:{result['累计广度信号'].iloc[-1]}")
运行结果类似如下:
===== 市场广度分析结果 =====
up down breadth breadth_pct 累计广度信号
2026-02-02 0 0 0 0.0 NaN
2026-02-03 5 5 0 0.0 NaN
2026-02-04 6 4 2 20.0 NaN
2026-02-05 4 6 -2 -20.0 NaN
2026-02-06 5 5 0 0.0 ✅ 允许做多
...
===== 最新交易信号 =====
最新日期:2026-02-27
当日广度:2
交易建议:✅ 允许做多
注意:以上为模拟数据,实际结果因随机种子和真实数据而异。
使用广度过滤器的注意事项
广度过滤器虽然简单有效,但也有其局限性。
首先,广度不是预测机器,而是参与度计量器。它告诉你当前行情有多少股票在参与,而不是行情未来会怎么走。
其次,广度可能滞后。市场可能已经开始反转,但广度信号还停留在上一个状态。它也可能在你失去耐心之前一直保持低迷。
第三,任何基于广度的策略都受交易成本制约。正如前面的算术所示,频繁调仓会把正收益变成负收益。做交易之前先做算术。
最后,记住一点:仓位要小到足以让犯错成为学费,而不是灾难。
总结
市场广度是一个被学术研究证实、且在实战中极具价值的工具。它回答了一个核心问题——这波行情到底有多少股票在真正参与?
对于 Python 学习者来说,实现一个广度过滤器是一个很好的练手项目:它涉及 pandas 数据处理、滚动窗口计算、布尔索引等常用技能,同时又能直接应用于真实的交易场景。
核心要点回顾:
- 1. 广度 = 上涨股票数 − 下跌股票数,衡量市场参与度。
- 2. 高广度行情比低广度行情更稳健,这一结论在 64 个国家的数据中得到验证。
- 3. 广度过滤器不是信号生成器,而是风险过滤器——它帮你避开那些"穿着风衣的三只股票"伪装的强势行情。
- 4. 交易成本是信号的隐形杀手,月度调仓优于周度调仓。
-
5. 先用模拟数据跑通代码,再用真实数据做 5 天冲刺实验。
参考文章
加入专注于财经数据与量化投研的知识星球【数据科学实战】,获取本文完整研究解析、代码实现细节。财经数据与量化投研知识社区
2026年全面升级已落地!【数据科学实战】知识星球核心权益如下:
- 1. 双典系统赋能:获赠《财经数据宝典》与《量化投研宝典》完整文档,凝练多年实战经验,构建系统化知识框架;
- 2. 量化因子日更教程(2026重磅新增):每日更新「量化因子专题教程」,配套完整可运行代码与实战案例,深度拆解因子构建、回测与优化全流程;
- 3. 量化文章专题教程库:300+篇星球独有高质量教程式文章,系统覆盖策略开发、因子研究、风险管理等核心领域,内容基本每日更新,并配套精选学习资料与实战参考;
- 4. PyBroker实战课程:赠送《PyBroker-入门及实战》视频课程,手把手教学,快速掌握量化策略开发技能;
- 5. 财经数据支持:定期更新国内外财经数据,为策略研发提供精准、可靠的数据基础;
- 6. 顶尖学者与行业专家分享:年度邀请学术界博士与业界资深专家开展前沿论文精讲与实战案例分享,不少于4场,直击研究前沿与产业实践;
专家直连答疑:与核心开发者及领域专家实时互动,高效解决投研实战难题; - 7. 专业社群与专属福利:加入高质量交流社群,获取课程折扣及更多独家资源。
星球已沉淀丰富内容生态——涵盖量化文章专题教程库、因子日更系列、高频数据集、PyBroker实战课程、专家深度分享与实时答疑服务。无论您是初探量化的学习者,还是深耕领域的从业者,这里都是助您少走弯路、高效成长的理想平台。诚邀加入,共探数据驱动的投资未来!