投投资策略平台
署名 老K
策略库/指数与行业估值分位

风险提示 本站内容为个人研究整理,仅供学习参考,不构成任何投资建议,据此操作风险自担。本策略的规则取自公开资料,并非个人独创交易体系。

指数与行业估值分位

算清楚当前估值在过去一段时间里排第几,并说清用的是哪套口径。

引擎 + 公开数据源通用规则适用:基金
全贯穿全链路1选标的主用2定买点3定仓位4定卖点5复盘
下载完整策略包 12.1 KB · 5 个文件 · 解压即用
下载 .zip

内容指纹(SKILL.md 的 sha256 前 16 位):804e29e1863561f5 —— 下载解压后可用 shasum -a 256 SKILL.md 自行核对。

策略说明

适用场景

你想判断某个指数或行业的估值现在是偏贵还是偏便宜,并且希望这个判断可以被复核——而不是接受一个来路不明的「估值分位 23%」数字。适合做定期估值跟踪表。

输入

标的(指数代码或行业名称)+ 估值指标(PE 或 PB)+ 历史窗口(默认 10 年,可改)。数据由脚本从公开源获取。

输出

当前值、历史分位、窗口内极值、以及该分位在历史序列上的位置图。附一份口径说明:窗口多长、是否剔除负值、用什么加权方式。

核心逻辑
  1. 拉取估值时间序列,按标的与指标筛出需要的列。
  2. 按既定口径清洗:剔除亏损导致的负值(PE 口径),记录剔除了多少条。
  3. 把当前值放进历史序列排序,用 (i-1)/(n-1)×100 算分位——这是常见的通行写法,不同机构对是否用这个公式、窗口取多长并无统一规定,所以口径必须随结果一起输出。
  4. 标注适用性的边界:强周期行业更宜看 PB,尚未盈利或净资产为负的标的两个指标都失去意义。
  5. 输出结果与口径说明,两者不可分离。
依赖

Python >=3.9;依赖包:akshare、pandas;数据:akshare(主)、baostock(备);估值序列的获取依赖公开数据源;部分指数的历史估值序列公开渠道不全,脚本会明确标注缺失区间。

文件清单
  • LICENSE 2.2 KB
  • SKILL.md 6.9 KB
  • references/sources.md 3.3 KB
  • requirements.txt 115 B
  • scripts/valuation_percentile.py 10.9 KB

风险与局限

分位数对窗口长度极其敏感:同一指数取 3 年、5 年、10 年或全历史,可以算出完全不同的分位,而且没有任何机构对此有统一规定。分位低不等于会上涨——低估可以持续很久,也可能是因为基本面已经永久性改变。强周期行业在盈利高点时 PE 最低,此时「低 PE」恰恰是危险信号,应改用 PB。

出处

共 8 条

SKILL.md 全文

下面这段就是下载包里 SKILL.md 的完整内容,未做删减。指纹 804e29e1863561f5。

指数与行业估值分位

回答一个问题:当前估值在过去一段时间里排第几——并且把「过去一段时间」是多长、用哪个公式算的,一并交出去。

这个 skill 的重点不在算法(算法只有三行),而在口径的显式化。同一个指数,取 3 年、5 年、10 年或全历史,可以算出完全不同的分位。任何不告诉你窗口长度的分位数,都不要拿去用。

适用场景

  • 你想判断某个指数或行业现在偏贵还是偏便宜,并且希望这个判断可被复核。
  • 你在做定期的估值跟踪表,需要口径每次一致。
  • 你看到一个「估值分位 23%」的数字,想知道它是怎么算出来的。

输入

输入 说明
标的 指数代码(如 000300)或行业名称
估值指标 PE 或 PB
历史窗口 默认 10 年,可改。这个参数必须写进结论
数据 在线取数,或用 --csv 喂一份自己的估值序列

输出

当前值、历史分位、窗口内最低/中位/最高、有效样本数、以及一份口径说明。结果与口径不可分离输出——只交出一个百分数,等于交出一个无法复核的数字。

核心逻辑

第一步:把定义摆正

  • 市盈率 PE = 每股市价 / 每股收益。行业通常的整体加权算法是 ∑(收盘价×发行数量) / ∑(每股收益×发行数量),并剔除亏损及暂停上市的公司。年报数据更新时点统一为每年 5 月 1 日。
  • 市净率 PB = 每股市价 / 每股净资产。
  • 三种 PE 不能混用:静态 PE 用上一会计年度每股收益;TTM(滚动 PE) 用最近四个季度每股收益之和;预测 PE 用季报数据折算的年每股收益。中文语境里的「动态市盈率」在不同数据商指向不同,引用时必须问清是哪一个。

第二步:把数据洗干净

按 PE 口径,亏损导致的负值必须剔除,并把剔除条数记下来。净资产为负的标的,PB 同样失去意义。

这一步的产出不是"干净的数据",而是"剔除规则 + 剔除了多少",两者都要随结果输出。

第三步:算分位

通行写法:

历史分位数 = (i − 1) / (n − 1) × 100

其中 i 是当前值在窗口内升序排列后的序数,n 是窗口内的样本数。

必须说清楚的边界:这个公式不是监管规定,也不是学术标准。不同机构对是否用这个式子、窗口取 3 年还是 10 年、是否插值,做法都不一样。所以你算出来的数字只有配上口径才能被比较。

第四步:输出适用性检查

  • 窗口越短,分位越容易走到极端。换窗口长度,结论可能翻转。
  • 强周期行业应改用 PB。 周期股在盈利高点时 PE 最低——此时「低 PE」恰恰是危险信号。
  • 尚未盈利或净资产为负的标的,PE 与 PB 都没有判断意义。
  • 分位低不等于会上涨。

依赖与安装

pip install akshare pandas

离线模式(--csv)只需 Python 标准库,不需要装任何东西。

用法

# 在线:算沪深300 的 PE 十年分位
python3 scripts/valuation_percentile.py --code 000300 --metric pe --window 10

# 在线:改用 PB,看五年分位
python3 scripts/valuation_percentile.py --code 000300 --metric pb --window 5

# 离线:喂一份自己的估值序列(推荐先用这个把口径跑通)
python3 scripts/valuation_percentile.py --csv series.csv --value-col PE_TTM --window 10

CSV 需要一个数值列和一个日期列;日期列名会自动识别(日期 / date / trade_date),也可以用 --date-col 指定。

出处

  • 中国证监会甘肃监管局《什么是市盈率?什么是市净率?》—— PE 的标准定义与公式。
  • 上海证券交易所《读懂上市公司定期报告(十五)》—— PB 定义,以及「尚未盈利或净资产为负时 PE/PB 失去判断意义」的边界。
  • 上海证券交易所《上海市场A股市盈率》指标说明 —— 整体加权算法与「剔除亏损及暂停上市公司」的口径,年报数据更新时点统一为每年 5 月 1 日。
  • 中证指数有限公司行业市盈率数据服务 —— 静态市盈率与滚动市盈率(TTM)并列发布,并单列「亏损证券数量」字段。
  • 中证网《静态市盈率、动态市盈率、预测市盈率分别是什么?》—— 三者公式区别。
  • Campbell & Shiller (1988), Stock Prices, Earnings, and Expected Dividends, Journal of Finance 43(3) —— CAPE(10 年通胀调整平均盈利)原始出处。
  • Damodaran, NYU Stern, Implied Equity Risk Premium —— 隐含股权风险溢价 = 预期股票收益 − 国债收益率。

完整清单与逐条说明见包内 references/sources.md。

风险与局限

  1. 分位数对窗口长度极其敏感。 同一指数取 3 年、5 年、10 年或全历史,可以算出完全不同的分位,而且没有任何机构对此有统一规定。这是本 skill 最容易被误用的地方。
  2. 分位低不等于会上涨。 低估可以持续很久,也可能是因为基本面已经永久性改变——用历史分位去推断未来,隐含假设是「估值中枢不变」,而这个假设本身需要你自己论证。
  3. 强周期行业不能用 PE 分位。 盈利高点对应低 PE,此时低 PE 是危险而非机会。
  4. 数据源由第三方维护。 部分指数的历史估值序列在公开渠道不全,脚本会明确标注缺失区间,不会用插值把缺口填上。
  5. 本 skill 不提供买卖判断。 它给出的是「当前估值在历史上的位置」,不是「该不该买」。

常见问题

同一个指数,我用 5 年窗口算出 12%,别人用 10 年算出 68%,谁对? 都对。差异全部来自窗口长度和是否剔除负值。比较两个分位数之前,先确认口径一致;口径不一致的两个数字放在一起比较没有意义。

为什么脚本要打印这么多口径信息? 因为一个不带口径的分位数是不可复核的数字。如果你要把它写进报告,口径信息是报告的一部分。

能不能用分位做择时? 可以把它作为一组观察指标之一,但单独用会很危险:低估可以持续数年。分位回答的是「现在贵不贵」,不回答「什么时候涨」。