买股票或者买基金,我们经常听到说要低买高卖,但是什么是高,什么是底,究竟用什么衡量比较好?答案是PE,PE代表了估值水平的高低,观看一个股票或者基金的PE变化,就可以得出当前的估值水平是高还是低,决定是否进行交易。

数据获取

从东财choice软件手动导出数据到excel,并且保存到data目录

In [1]:
!ls data/
PB表.xlsx               收盘价.xlsx             净资产收益率.xlsx
PE表.xlsx               股息率.xlsx

数据提取

先从文件中读取所有excel,并将里面各个sheet单独保存成csv文件供后面分析

In [2]:
import pandas as pd
from streamz import Stream
In [3]:
def parse_file(filename):
    return filename.split('/')[-1].split('.')[0],pd.ExcelFile(filename)

def parse_sheet(tuple_excel_file):
    filename,excel_file=tuple_excel_file
    return [(sheetname,filename,excel_file.parse(sheetname)) for sheetname in excel_file.sheet_names]

def get_sheets(excel_file):
    return excel_file.sheet_names

def to_csv(tuple_sheet):
    sheetname,filename,df = tuple_sheet
    df.to_csv('sheets/'+filename+'_'+sheetname+'.csv')

def notNaNdf(tuple_sheet):
    sheetname,filename,df = tuple_sheet
    return not df.empty
In [4]:
source = Stream.filenames('data/')\
                    .map(parse_file)\
                    .map(parse_sheet).flatten()\
                    .filter(notNaNdf)\
                    .sink(to_csv)
source.start()
In [5]:
!ls sheets/
PB表_300一级行业.csv                 PE表_策略风格指数.csv
PB表_300三级行业.csv                 PE表_历史行情参数页.csv
PB表_300二级行业.csv                 PE表_历史行情参数页1.csv
PB表_800一级行业.csv                 PE表_历史行情参数页2.csv
PB表_800二级行业.csv                 PE表_历史行情参数页3.csv
PB表_全A一级行业.csv                 PE表_历史行情参数页4.csv
PB表_全A三级行业.csv                 PE表_历史行情参数页5.csv
PB表_全A二级行业.csv                 PE表_历史行情参数页6.csv
PB表_产业指数.csv                    收盘价_300一级行业.csv
PB表_精选指数.csv                    收盘价_300三级行业.csv
PB表_策略风格指数.csv                收盘价_300二级行业.csv
PB表_历史行情参数页.csv              收盘价_800一级行业.csv
PB表_历史行情参数页1.csv             收盘价_800二级行业.csv
PB表_历史行情参数页2.csv             股息率_Sheet1.csv
PB表_历史行情参数页3.csv             收盘价_全A一级行业.csv
PB表_历史行情参数页4.csv             收盘价_全A三级行业.csv
PB表_历史行情参数页5.csv             收盘价_全A二级行业.csv
PB表_历史行情参数页6.csv             收盘价_产业指数.csv
PE表_300一级行业.csv                 收盘价_精选指数.csv
PE表_300三级行业.csv                 收盘价_策略风格指数.csv
PE表_300二级行业.csv                 收盘价_历史行情参数页.csv
PE表_800一级行业.csv                 收盘价_历史行情参数页1.csv
PE表_800二级行业.csv                 收盘价_历史行情参数页2.csv
PE表_全A一级行业.csv                 收盘价_历史行情参数页3.csv
PE表_全A三级行业.csv                 收盘价_历史行情参数页4.csv
PE表_全A二级行业.csv                 收盘价_历史行情参数页5.csv
PE表_产业指数.csv                    收盘价_历史行情参数页6.csv
PE表_精选指数.csv                    净资产收益率_Sheet1.csv

初步分析

选取非行业和产业的PE数据,绘图查看PE(估值高低)的走势

In [6]:
l = []
source = Stream.filenames('sheets/')\
                    .filter(lambda x:'PE' in x and '行业' not in x and '产业' not in x and '历史' not in x)\
                    .rate_limit(1).map(pd.read_csv)

l = source.sink_to_list()
source.start()
In [7]:
def df_process(df):
    df.fillna(0,inplace=True)#填充空值为0
#     df.set_axis(df.iloc[0]],'columns',inplace=True)#设置第一行为列名
    df.set_axis(df.iloc[1],'columns',inplace=True)#设置第二行为列名
    df.drop(df.index[[0,1,2]],inplace=True)#删除前三行无用数据

    #行名变更
    cl =list(df.columns)
    cl[0] = 'first'
    cl[1] = 'date'
    df.columns = cl

    df.drop(df.index[-1],inplace=True)#删除行尾的版权申明
    df = df.set_index(pd.to_datetime(df.date))#转换时间列,并将其设置为索引
    df.drop(['first','date'],axis=1,inplace=True)#删除无用列
    return df
In [8]:
ll = [df_process(i) for i in l]
In [9]:
#合并数据
from functools import reduce
df = reduce(lambda x, y: pd.merge(x, y, on = 'date',how='outer'), ll)
In [10]:
df.columns
Out[10]:
Index(['基本面50_x', '红利低波', '红利价值', '300成长', '300价值', '500成长', '500价值', '800成长',
       '800价值', '东方财富全A', '中证100', '沪深300', '中证500', '中证800', '基本面50_y',
       '中证红利', '证券公司', '中证白酒', '800地产', '中证环保', '中证军工', '医药100', '养老产业'],
      dtype='object')
In [11]:
#df.drop('399967.SZ',inplace=True,axis=1)#去掉某个不想要的指数
df.drop('中证军工',inplace=True,axis=1)
In [12]:
df = df.sort_index()
df = df.iloc[1:,:]#去掉首行1970年数据
df = df.applymap(float)
df.fillna(0,inplace=True)#空值替换为0
df.describe().T
Out[12]:
count mean std min 25% 50% 75% max
基本面50_x 4348.0 6.138706 6.694311 0.0 0.000000 6.562977 9.782215 30.174498
红利低波 4348.0 2.449569 4.150877 0.0 0.000000 0.000000 5.548560 14.299807
红利价值 4348.0 2.166117 3.607633 0.0 0.000000 0.000000 5.393331 12.932741
300成长 4348.0 8.952539 8.383897 0.0 0.000000 10.019960 14.362437 38.756384
300价值 4348.0 6.869756 6.552023 0.0 0.000000 8.069730 10.495316 33.113817
500成长 4348.0 7.258194 12.995520 0.0 0.000000 0.000000 14.028997 55.824183
500价值 4348.0 5.758604 10.433708 0.0 0.000000 0.000000 10.779707 47.087808
800成长 4348.0 3.753553 6.685082 0.0 0.000000 0.000000 7.244136 22.416038
800价值 4348.0 2.683768 4.691369 0.0 0.000000 0.000000 6.851109 15.308229
东方财富全A 4348.0 28.145927 15.214146 0.0 17.246668 21.736516 36.571439 70.754387
中证100 4348.0 11.012353 10.406951 0.0 0.000000 10.262600 14.126665 48.268991
沪深300 4348.0 12.889368 10.469403 0.0 8.299290 12.570859 15.738556 50.286863
中证500 4348.0 28.590187 25.254170 0.0 0.000000 29.367176 43.976125 98.593178
中证800 4348.0 12.317041 11.631413 0.0 0.000000 12.278119 16.429359 52.227114
基本面50_y 4348.0 6.138706 6.694311 0.0 0.000000 6.562977 9.782215 30.174498
中证红利 4348.0 7.647656 12.123395 0.0 0.000000 7.550183 9.862573 82.437119
证券公司 4348.0 7.448182 12.447122 0.0 0.000000 0.000000 15.523253 56.052543
中证白酒 4348.0 5.465730 10.663574 0.0 0.000000 0.000000 0.000000 39.381016
800地产 4348.0 4.827805 7.159516 0.0 0.000000 0.000000 11.425632 27.707149
中证环保 4348.0 10.948712 15.545373 0.0 0.000000 0.000000 28.138047 59.492842
医药100 4348.0 15.022499 17.587051 0.0 0.000000 0.000000 34.062120 62.800863
养老产业 4348.0 6.269902 10.910327 0.0 0.000000 0.000000 18.928913 36.181800
In [13]:
df = df.loc['2005-01-01':]
df = df.resample('3M').mean()
In [14]:
from hvplot import pandas
df.hvplot()
Out[14]:

虽然股价经常鸡飞狗跳,但是估值水平PE基本还是比较稳定的。