Press "Enter" to skip to content

浅谈估值模型 (二): PE指标II——PE Band

1:本文主要介绍一个小众的估值指标——PE Band;

 

2:本文主要为理念的讲解,模型也是笔者自建;

 

3:本文主要数据均通过Tushare(ID:444829)金融大数据平台接口获取;

 

4:笔者希望搭建出一套交易体系,原则是只做干货的分享。后续将更新更多模块,但工作学习之余的闲暇时间有限,更新速度慢还请谅解;

 

5:文中假设与观点是基于笔者对模型及数据的一孔之见,若有不同见解欢迎随时留言交流;

 

6:模型实现基于python3.8;

 

目录

 

2. PE Band的不合理性及问题

 

3. PE Band重构与其意义

 

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指标。有机会笔者再继续进行分享其它好玩又有用的估值方式。您若不弃,我们风雨共济。

Be First to Comment

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注