量化入门系列:沪深300、中证500、中证1000的估值百分位
本系列通过一些实例介绍量化的入门知识,适合零基础的初学者。本篇计算三个宽基指数:沪深300、中证500、中证1000的估值百分位,并将其与价格百分位比较。
本文的程序运行前要先导入数据源和pandas库:
import akshare as ak # 导入数据源
import pandas as pd # 导入pandas库
pandas的数据分析功能非常强大,在量化分析中会经常用到,要熟悉掌握。
从上一篇《量化入门系列:四行代码实现A股的估值温度计》可以总结出,此类量化分析通常分为三个步骤:
第一步打开冰箱,不是,第一步是获取数据;
第二步是处理数据;
第三步是输出结果。
我们先来计算沪深300的估值百分位,估值百分位是指当前估值在历史上的百分位数。然后我们将估值和价格进行对比。在集思录上是将估值百分位数和指数的价格曲线直接对比,像这样:
橘色线是PE估值百分位,蓝色线是中证全指的价格曲线。本文为了更直观的体现对比差异,不直接采用指数的价格曲线,而是用指数的价格百分位,价格百分位是指当前价格在历史上的百分位。
hs300_pe_df = ak.stock_a_pe(market="000300.XSHG").iloc[-1708:] # 获取沪深300的PE和收盘价数据
hs300_pe_pct = hs300_pe_df[['middlePETTM','close']].rank(ascending=True, pct=True)*100 # 计算PE和收盘价的历史百分位
hs300_pe_pct.plot(figsize=(16,8),grid=True,title='沪深300估值和价格百分位') # 画图
第一行代码是通过AKShare的数据接口ak.stock_a_pe()接口获取沪深300的PE和收盘价的数据,在计算历史百分位时需要一个时间窗口(即用哪个时段的数据),这个时间窗口太长或太短都不好,A股历史上牛熊周期大概是7年,因此这里取过去7年的数据(7年*244个交易日=1708个交易日),代码中 .iloc[-1708:] 就是取最近1708个数据。取出来的数据是个DataFrame格式的表格,存放在变量hs300_pe_df中,可以用 print 语句来看下这个表格的内容:
print (hs300_pe_df)
其中日期部分是这个DataFrame的索引(index),这个DataFrame有5列(columns),分别为:成分股静态市盈率的均值、成分股TTM市盈率的均值、成分股静态市盈率的中位数、成分股TTM市盈率的中位数、收盘价。
第二行代码用于计算成分股TTM市盈率的中位数和收盘价的历史百分位,用到表格hs300_pe_df的其中两列('middlePETTM' 和 'close'),用rank()函数来计算百分位,计算结果也是个DataFrame表格,存放在变量hs300_pe_pct中,我们可以查看下内容:
print (hs300_pe_pct)
上面表格的索引(index)为日期,表格有两列:PE的历史百分位和收盘价的历史百分位。
第三行代码是将表格hs300_pe_pct用折线图显示出来:
蓝线是PE百分位,橘线是价格百分位,可以看到两者的相关性比较高,毕竟PE的分子就是价格。但两者也有背离的时候,目前PE估值百分位在40%左右,价格百分位在90%左右,说明盈利的增长高于价格的增长。需要注意的是盈利是一个季度披露一次,有滞后性。
同样的方法可以画出中证500的PE的历史百分位和收盘价的历史百分位:
zz500_pe_df = ak.stock_a_pe(market="000905.XSHG").iloc[-1708:] # 获取中证500的PE和收盘价数据
zz500_pe_pct = zz500_pe_df[['middlePETTM','close']].rank(ascending=True, pct=True)*100 # 计算PE和收盘价的历史百分位
zz500_pe_pct.plot(figsize=(16,8),grid=True,title='中证500估值和价格百分位') # 画图
中证1000的PE的历史百分位和收盘价的历史百分位:
zz1000_pe_df = ak.stock_a_pe(market="000852.XSHG").iloc[-1708:] # 获取中证1000的PE和收盘价数据
zz1000_pe_pct = zz1000_pe_df[['middlePETTM','close']].rank(ascending=True, pct=True)*100 # 计算PE和收盘价的历史百分位
zz1000_pe_pct.plot(figsize=(16,8),grid=True,title='中证1000估值和价格百分位') # 画图
可以看到自2021年以来,沪深300、中证500、中证1000的估值百分位和价格百分位都出现了背离,其中以中证500最为显著,价格不断抬高,但估值水平不断下降,呈现出明显的喇叭状。
我们用柱状图来对比一下:
comparison_df = pd.DataFrame()
comparison_df['hs300'] = hs300_pe_pct.iloc[-1] # 沪深300最近一日的估值百分位和价格百分位
comparison_df['zz500'] = zz500_pe_pct.iloc[-1] # 中证500最近一日的估值百分位和价格百分位
comparison_df['zz1000'] = zz1000_pe_pct.iloc[-1] # 中证1000最近一日的估值百分位和价格百分位
comparison_df.T.plot.bar(figsize=(10,5)) # 画图
comparison_df是一个DataFrame表格,用来存储三个指数最近一日的估值百分位和价格百分位,用print查看内容:
print (comparison_df)
comparison_df.T.plot.bar()是将表格comparison_df用柱状图画出来:
上图可以直观的对比估值百分位的位置和价格百分位的位置。
本篇介绍了三个宽基指数估值百分位的实现,下一篇继续介绍行业指数、主题指数、风格指数的估值百分位。想知道医药跌了快半年了,估值够便宜了吗?下篇给你答案。
本文涉及的数据接口的说明文档:
https://www.akshare.xyz/data/stock/stock.html?highlight=stock_a_pe#a-4
量化投资系列的文章目录:
1. 量化入门系列:用Anaconda和AKShare搭建免费的Python量化环境