1:本文主要介绍一个小众的估值指标——PE Band;
2:本文主要为理念的讲解,模型也是笔者自建;
3:本文主要数据均通过Tushare(ID:444829)金融大数据平台接口获取;
4:笔者希望搭建出一套交易体系,原则是只做干货的分享。后续将更新更多模块,但工作学习之余的闲暇时间有限,更新速度慢还请谅解;
5:文中假设与观点是基于笔者对模型及数据的一孔之见,若有不同见解欢迎随时留言交流;
6:模型实现基于python3.8;
目录
1. 引言
之前看到这么一篇文章:
机构投资者最喜欢用的一个估值指标 指数宝最近新上线了一个指标功能:PE Band(以及PB Band、PS Band),这个指标是机构投资者很喜欢用的一个... - 雪球 (xueqiu.com)
笔者一搜本站:
什。。什么,竟然没人写过。不过转念一想在C站像笔者这样的财经作者本就不多,都去雪球头条什么的混流量了。可这一条条的代码放给雪球上的人又有几人能懂,最后笔者还是选了C站, 顺便还能瞻仰瞻仰其他人的代码大作。
废话不说多,专家远在天边近在眼前,既然没人写过,马上开整。
1.1 PE Band简介
简单来说就是布林线版的PE指标,其理念在于均值回归。别人在这篇文章中已经写得非常详细了,没见过这个指标的可以读一读。
不知道您读完是什么感受;如果是之前就见过并且用过这个指标的投资者也可以交流下心得。总之,笔者认为这个指标虽好缺也存在着很大缺陷。
请看图一,这是根据链接文章中PE Band作出的通道线,选取250天移动区间,黑线为实际PE,红线绿线分别为 band,橙色和紫色为 band, 蓝线为PE均值。那么接下来我们只要遵循碰黄线卖出,碰绿线或紫线买入,可以说是屡试不爽,多空之下收获颇丰。
图一:PE Band 上的交易时机
那么接下来同样是这幅图:
图二:走势预测【1】
目前PE正位于过去250天的低位,您认为这支股票之后的PE走势是怎么样的:
A: 上涨突破红线
B: 橙线绿线间震荡平盘
C: 跌破绿线,跌跌不休
D: 给的信息太少,无法判断
(答案将在文章结尾公布)
2. PE Band的不合理性及问题
2.1 正态分布假设
引用那篇文章里的一句话: "根据“3sigma法则”,PE的波动范围不超过上下各3倍标准差的概率为99.73%,因此,我们设置的这个PE Band从理论上讲,基本上可以覆盖到所有的PE值"。
此话一出就是第一个问题——PE Band作出了股价服从正态分布的假设,这显然不合理。笔者在很早就提到过股价的分布千奇百怪,如果以正态分布去计算无疑很容易走到陷阱中。
2.2 技术分析假设
PE Band所用到的数据完全是历史数据,说穿了它就是一种另类的布林线。从PE指数计算公式的角度上看,PE指标的走法在一个财报期内和股价的走势并无二致,若果用短期移动平均作为band,它不就直接退化成了布林线。不知道有多少读者是根据布林线交易的,请问你们幸福吗?
2.3 参数
这篇文章中所提到的Band是一种怎样的Band,请问它以过去多长时间的标准差为依据计算出的3σ band,以这段时间的标准差计算又是否合理?其实笔者在Choice数据库上也有这个指标,并且很多参数可以自定义,但是一来Choice的付费服务不是每个投资者都有,二来Choice这Band风格笔者并不喜欢。
图三:Choice数据库上的PE Band(数据来源:Choice数据库)
最后,在计算时怎么保证PE指标是合理的?笔者早在上一期关于PE指标的文章中就提到PE指标非常容易受到财报操控的影响,如果您目前使用的PE指标都是有偏的,那么计算出来的结果还是否可靠?
2.4 人性
这点放文末谈,再来个看图说话(条件同图一):
图四:走势预测【2】
目前PE正位于过去的高位,您认为这支股票之后的PE走势是怎么样的:
A: 继续上涨突破红线
B: 跌回绿线
C: 高位横盘
D: 给的信息太少,无法判断
(答案将在文章结尾公布)
3. PE Band重构与其意义
根据笔者以上列出的不合理因素是否有行之有效的解法?对于分布来说很容易解决,只要使用更合理的分布计算Band区间就可以了。但其它很难,或许对于有偏的PE指标我们还能通过财务手段剔除不合理因素;但对于人性,对于技术分析假设就是PE Band天生的缺陷,至少笔者目前没办法解决。如果有人有好的点子欢迎私信或留言交流。
4. 代码实现
下面笔者以上证指数为例,自建一个PE Band供大家参考。数据笔者选用了Tushare金融大数据接口,注册一个账号便可以用自己的Token请求数据,十分简单方便,救笔者于爬虫的焦头烂额之中。网站如下:Tushare大数据社区
首先导入模块,作图主要依靠matplotlib和seaborn:
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
import tushare as ts
import pandas as pd
请求数据,区间选定为上证指数12年到今年的PE数据,除PE外还支持ttm PE,PB等指标,读者可阅读Tushare的技术文档自行设置(日线行情请求参数:Tushare大数据社区)
df = pro.index_dailybasic(ts_code=”000001.SH", start_date="20120101", end_date="20220620", fields='trade_date, pe')
接下来看看分布:
final_dis = np.array(df["pe"])
sns.kdeplot(final_dis)
plt.axvline(np.average(final_dis), label='mean {:.3f}'.format(np.average(final_dis)), linestyle='-.', color='r')
plt.axvline(np.median(final_dis)+np.std(final_dis)*3, label="+3Xstd {:.3f}".format(np.median(final_dis)), linestyle=':', color='g')
plt.axvline(np.median(final_dis)-np.std(final_dis)*3, label="-3Xstd {:.3f}".format(np.median(final_dis)), linestyle=':', color='g')
plt.legend()
plt.title("Distribution from 2012-2022")
plt.show()
来观察一下上证的PE分布,不难发现它是个奇奇怪怪的形状。笔者用绿色虚线标注了正态分布的3σ位置,可以明显看到当处于PE很低的时期,最低也不会碰到负3σ线,当市场处于亢奋时期则很容易冲过正3σ,上证近10年的PE均值目前(截至今年6月20日)是13.4左右。
图五:上证指数20120101-20220620 PE分布
因为Band包含上下两根轨道,这里的轨道计算封个函数吧,方便后面调用。轨道笔者打算只显示两条:3倍和1.5倍σ的,即multiple传参3和1.5。至于band上下轨就利用分布标准化公式:
def sig_calc(data, multiple):
sig = np.std(data["pe"])
mean = np.average(data["pe"])
probably = norm.cdf(multiple) * 100
positive = np.percentile(data["pe"], probably)
negative = np.percentile(data["pe"], 100 - probably)
sig_left_tail = (mean - negative) / sig
sig_right_tail = (positive - mean) / sig
return sig_left_tail, sig_right_tail
sig_three = sig_calc(df, 3) # 3 Sigma
sig_ahalf = sig_calc(df, 1.5) # 1.5 Sigma
其中,下面这两行是关键,它根据上证分布的独特性从概率上反向推出Band轨道位置,是改造PE Band的关键步骤(有点类似于做假设检验时候的P-value 和 Z值,都是一样的概念,但笔者利用概率在特殊分布上反推出Z值)。
probably = norm.cdf(multiple) * 100
positive = np.percentile(data["pe"], probably)
negative = np.percentile(data["pe"], 100 - probably)
得到函数Return出的sig_left_tail(下轨), sig_right_tail(上轨)后事情就简单多了,设定一个移动区间,将这十年的数据以Band的形式展示出来。剩下的做法和布林线差不多,就不细讲了。
def lines_data(df, move_average):
sig_three = sig_calc(df, 3) # 第一个数是左尾
sig_ahalf = sig_calc(df, 1.5)
negative_three, positive_three = [], []
negative_ahalf, positive_ahalf = [], []
mean_value = []
print(sig_ahalf)
for i in range(len(df["pe"][move_average:])):
if np.average(df["pe"][i:move_average + i]) != None:
stdiv = np.std(df["pe"][i:move_average + i])
negative_three.append(np.average(df["pe"][i:move_average + i]) - sig_three[0] * stdiv)
positive_three.append(np.average(df["pe"][i:move_average + i]) + sig_three[1] * stdiv)
negative_ahalf.append(np.average(df["pe"][i:move_average + i]) - sig_ahalf[0] * stdiv)
positive_ahalf.append(np.average(df["pe"][i:move_average + i]) + sig_ahalf[1] * stdiv)
mean_value.append(np.average(df["pe"][i:move_average + i]))
else:
negative_three.append(None)
positive_three.append(None)
negative_ahalf.append(None)
positive_ahalf.append(None)
mean_value.append(None)
lst = {"negative_three": negative_three,
"positive_three": positive_three,
"negative_ahalf": negative_ahalf,
"positive_ahalf": positive_ahalf,
"average": mean_value
}
lines = pd.DataFrame(lst)
return lines
函数返回的lines就是Band的上下轨数据,剩下的就是把它们都展示到图上,都是基本操作,大家可以根据自己的喜好选择用matplotlib或者Seaborn画图,笔者用了matplotlib:
def plot_generator(df, lines, move_average):
plt.figure(figsize=(16, 5))
plt.plot(df["trade_date"][move_average:], lines["positive_three"], linewidth=1, color="r", linestyle="--", label="3sig PE")
plt.plot(df["trade_date"][move_average:], lines["negative_three"], linewidth=1, color="g", linestyle="--", label="-3sig PE")
plt.plot(df["trade_date"][move_average:], lines["positive_ahalf"], linewidth=1, color="orange", linestyle="--",
label="1.5sig PE")
plt.plot(df["trade_date"][move_average:], lines["negative_ahalf"], linewidth=1, color="purple", linestyle="--",
label="-1.5sig PE")
plt.plot(df["trade_date"][move_average:], lines["average"], linewidth=1, color="blue", linestyle="--",
label="average PE")
plt.plot(df["trade_date"][move_average:], df["pe"][move_average:], linewidth=0.4, color="black", linestyle="-", label="PE")
plt.xticks(df["trade_date"][move_average::50], rotation=320)
plt.xlabel("date")
plt.ylabel("PE")
plt.legend()
plt.show()
5. PE Band 展示
图六:上证指数PE Band(200天移动标准差)
可以看到,上证指数上轨(1.5σ)黄线在大多数情况下是较为敏感的,很多时期只要碰到黄线就会经历下跌。而绿线(3σ)下轨则反应较为迟钝,有很多时期虽然碰了绿线下轨却也跌跌不休。但总体而言,短期的移动平均使Band变得不可靠。
或者您也可以拉长周期,例如下图是以三年为移动区间计算的Band:
图七:上证指数PE Band(720天移动标准差)
在长周期上看,PE碰到绿线基本可以有很大把握是在估值底部区域,此时买入从长期投资的角度来看是十分划算的;当PE碰到黄线说明偏高,可以选择卖出一部分持仓;当碰到红线,那么在长周期上看这都是十分危险的。总的来说,如果您是长线的投资者这也不失为一种懒人择时选股法。
笔者认为长周期的PE band有较高参考价值。但仅仅只是参考,结合分析师的专业判断是十分有必要的,别忘了笔者之前提到PE Band的缺点。
6. 答案
第一题,走势预测【1】C: 跌破绿线,跌跌不休
第二题,走势预测【2】A: 继续上涨突破红线
不知道您有没有猜对呢?
关于人性:
"It's going down this much already, can't go any lower."
"It's gone this high already, I gonna possibly go lower."
"It's 3$, how much can I loose?"
-- Peter Lynch
正如上一篇文章所提到的,PE指标远远不是表面上那么简单,不知道读完笔者两期的PE指标有没有让你认识到一个不一样的PE指标。有机会笔者再继续进行分享其它好玩又有用的估值方式。您若不弃,我们风雨共济。