公众号:跨界韭菜

0%

选股 - 股息支付率(payout ratio)、基本每股收益(eps) 来选股

前言

其实这篇文章几个星期前已经写好,不过只是发布在自己的个人blog上,不过想来想去还是同时发布在这里吧,毕竟跟金融有关的。

一直股票的价值几何一般往往是由公司未来的盈利所决定的。 在企业的估值中,最常使用的就是现金流折现模型(DCF模型)。 这里的现金可以是公司的分红、自由现金流等。在这里,我们用公司分红作为例子。一家公司是否长期连续分红往往决定了能否用DCF模型来估值。同理,我们也可以通过是否连续分红来筛选股票。

下面我们将用到tushare.pro的数据来筛选有连续分红的上市公司。

PS: 下面有些表格的标题可能重叠了,但是没有办法,应该是版面问题。将就一下吧。

免费注册Tushare.pro账号

首先,我们需要从tushare.pro注册一个账号并调用其API获取股票日线数据。可能大多数的童稚是第一次接触tushare.pro, 那我就直接贴上官方介绍:

Tushare是一个免费提供各类金融数据和区块链数据 , 助力智能投资与创新型投资的python财经数据接口包。拥有丰富的数据内容,如股票、基金、期货、数字货币等行情数据,公司财务、基金经理等基本面数据。

第一部分,利用分红、股息支付率(payout_ratio_diluted)、基本每股收益(eps) 来选股

1
2
3
4
5
import tushare as ts
import pandas as pd
import time

pro = ts.pro_api('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx') #这里需要填写你注册好的Tushare的TOKEN凭证
1
2
3
#获取最新的股票列表
stock_tickers = pro.stock_basic(exchange='', list_status='L', fields='ts_code,symbol,name')
stock_tickers.head()

输出:

- ts_code symbol name
0 000001.SZ 000001 平安银行
1 000002.SZ 000002 万科A
2 000004.SZ 000004 国农科技
3 000005.SZ 000005 世纪星源
4 000006.SZ 000006 深振业A
1
2
3
4
5
6
7
8
9
#新建一个DataDrame
div_stocks_sample = pd.DataFrame()
#遍历所有的stock_tickers,获取股票分红并全部合并在一个DataDrame里面,为了演示,下面只获取前5只股票
for ticker,name in zip(stock_tickers['ts_code'][:5],stock_tickers['name'][:5]):
div = pro.dividend(ts_code=ticker)
div['stock_name'] = name
div_stocks_sample = div_stocks_sample.append(div)
time.sleep(1)
div_stocks_sample.head()

输出:

- ts_code end_date ann_date div_proc stk_div stk_bo_rate stk_co_rate cash_div cash_div_tax record_date ex_date pay_date div_listdate imp_ann_date stock_name
0 000001.SZ 20180630 20180816 预案 0.0 NaN NaN 0.0000 0.000 None None None None None 平安银行
1 000001.SZ 20171231 20180315 实施 0.0 NaN NaN 0.1360 0.136 20180711 20180712 20180712 None 20180706 平安银行
2 000001.SZ 20161231 20170317 实施 0.0 NaN NaN 0.1580 0.158 20170720 20170721 20170721 None 20170717 平安银行
3 000001.SZ 20151231 20160310 实施 0.2 NaN 0.2 0.1530 0.153 20160615 20160616 20160616 20160616 20160608 平安银行
4 000001.SZ 20141231 20150313 实施 0.2 NaN 0.2 0.1653 0.174 20150410 20150413 20150413 20150413 20150407 平安银行

以上步骤只是为了演示如何获取所有股票的分红,为了节省时间,直接读取准备好了的excel文件

名称 描述
ts_code TS代码
end_date 分红年度
ann_date 预案公告日
div_proc 实施进度
stk_div 每股送转
stk_bo_rate 每股送股比例
stk_co_rate 每股转增比例
cash_div 每股分红(税后)
cash_div_tax 每股分红(税前)
record_date 股权登记日
ex_date 除权除息日
pay_date 派息日
div_listdate 红股上市日
imp_ann_date 实施公告日
base_date 基准日
base_share 基准股本(万)

div_stocks.xlsx 的下载地址:链接: https://pan.baidu.com/s/1Ljvah3jAjCKIwH6Qm9J-mA 提取码: sixw

1
2
div_stocks = pd.read_excel('div_stocks.xlsx')
div_stocks.head(10)

输出:

- ann_date cash_div cash_div_tax code div_listdate div_proc end_date ex_date imp_ann_date pay_date record_date stk_bo_rate stk_co_rate stk_div stock_name ts_code type
0 NaN 0.07494 0.200 1 19970827.0 实施 19961231 19970825.0 19970819.0 19970829.0 19970822.0 0.50 NaN 0.50 平安银行 000001.SZ dividend
1 NaN 0.00000 0.300 1 19950927.0 实施 19941231 19950925.0 19950915.0 19950927.0 19950922.0 0.20 NaN 0.20 平安银行 000001.SZ dividend
2 19960314.0 0.00000 0.000 1 19960529.0 实施 19951231 19960527.0 19960523.0 NaN 19960524.0 0.50 0.5 1.00 平安银行 000001.SZ dividend
3 19990717.0 0.49000 0.600 1 NaN 实施 19990630 19991018.0 19991011.0 19991022.0 19991015.0 NaN NaN 0.00 平安银行 000001.SZ dividend
4 NaN 0.00000 0.300 1 19930524.0 实施 19921231 19930524.0 19930509.0 19930524.0 19930521.0 0.35 0.5 0.85 平安银行 000001.SZ dividend
5 20120816.0 0.09000 0.100 1 NaN 实施 20120630 20121019.0 20121012.0 20121019.0 20121018.0 NaN NaN 0.00 平安银行 000001.SZ dividend
6 20170317.0 0.15800 0.158 1 NaN 实施 20161231 20170721.0 20170717.0 20170721.0 20170720.0 NaN NaN 0.00 平安银行 000001.SZ dividend
7 20070524.0 0.00110 0.009 1 20070620.0 实施 20070615 20070620.0 20070614.0 20070620.0 20070615.0 0.10 NaN 0.10 平安银行 000001.SZ dividend
8 20030424.0 0.12000 0.150 1 NaN 实施 20021231 20030929.0 20030923.0 20030929.0 20030926.0 NaN NaN 0.00 平安银行 000001.SZ dividend
9 20180315.0 0.13600 0.136 1 NaN 实施 20171231 20180712.0 20180706.0 20180712.0 20180711.0 NaN NaN 0.00 平安银行 000001.SZ dividend

接下来,我们需要验证一下数据

1
div_stocks.info()

输出:

<class 'pandas.core.frame.DataFrame'>
Int64Index: 31075 entries, 0 to 31074
Data columns (total 17 columns):
ann_date        30535 non-null float64
cash_div        31075 non-null float64
cash_div_tax    31075 non-null float64
code            31075 non-null int64
div_listdate    8673 non-null float64
div_proc        31075 non-null object
end_date        31075 non-null int64
ex_date         27484 non-null float64
imp_ann_date    27509 non-null float64
pay_date        24369 non-null float64
record_date     27509 non-null float64
stk_bo_rate     2737 non-null float64
stk_co_rate     7321 non-null float64
stk_div         31075 non-null float64
stock_name      31075 non-null object
ts_code         31075 non-null object
type            31075 non-null object
dtypes: float64(11), int64(2), object(4)
memory usage: 4.3+ MB

从上面可以看出,有些数据是存在缺失

1
div_stocks.describe()

输出:

- ann_date cash_div cash_div_tax code div_listdate end_date ex_date imp_ann_date pay_date record_date stk_bo_rate stk_co_rate stk_div
count 3.053500e+04 31075.000000 31075.000000 31075.000000 8.673000e+03 3.107500e+04 2.748400e+04 2.750900e+04 2.436900e+04 2.750900e+04 2737.000000 7321.000000 31075.000000
mean 2.011806e+07 0.116059 0.130616 308279.551215 2.009181e+07 2.010783e+07 2.010751e+07 2.010752e+07 2.011682e+07 2.010754e+07 0.274645 0.633765 0.173522
std 6.064584e+04 0.191410 0.209326 278970.459003 6.950803e+04 6.465745e+04 6.306698e+04 6.305408e+04 5.495106e+04 6.305243e+04 0.213189 0.411149 0.352825
min 1.991032e+07 0.000000 0.000000 1.000000 1.992123e+07 1.990123e+07 1.991061e+07 1.991063e+07 1.993042e+07 1.991053e+07 0.003986 0.001377 0.000000
25% 2.008033e+07 0.010000 0.020000 2152.000000 2.004102e+07 2.007123e+07 2.007013e+07 2.007021e+07 2.008063e+07 2.007021e+07 0.120000 0.300000 0.000000
50% 2.013082e+07 0.076000 0.100000 300299.000000 2.011052e+07 2.012123e+07 2.012091e+07 2.012090e+07 2.013061e+07 2.012091e+07 0.200000 0.500000 0.000000
75% 2.017041e+07 0.150000 0.171360 600558.000000 2.015053e+07 2.016123e+07 2.016053e+07 2.016052e+07 2.016062e+07 2.016053e+07 0.300000 1.000000 0.200000
max 2.019010e+07 10.999000 10.999000 603999.000000 2.018111e+07 2.018123e+07 2.018120e+07 2.018113e+07 2.018120e+07 2.018120e+07 3.000000 3.000000 3.000000

投资者是以登记日来决定是否取得股票分红的,所以这里我们以登记日“record_date”为准来计算全年的分红。 当然,你也可以选择其他日期如end_date作为统计

1
2
div_stocks['record_date'] = pd.to_datetime(div_stocks['record_date'], format='%Y%m%d')
div_stocks['record_date'].head()

输出:

0   1997-08-22
1   1995-09-22
2   1996-05-24
3   1999-10-15
4   1993-05-21
Name: record_date, dtype: datetime64[ns]

接下来我们要通过groupby来计算出一年总的分红

1
2
div_stocks = div_stocks.dropna(subset=['record_date'])
div_stocks.head(10)

输出:

- ann_date cash_div cash_div_tax code div_listdate div_proc end_date ex_date imp_ann_date pay_date record_date stk_bo_rate stk_co_rate stk_div stock_name ts_code type
0 NaN 0.07494 0.200 1 19970827.0 实施 19961231 19970825.0 19970819.0 19970829.0 1997-08-22 0.50 NaN 0.50 平安银行 000001.SZ dividend
1 NaN 0.00000 0.300 1 19950927.0 实施 19941231 19950925.0 19950915.0 19950927.0 1995-09-22 0.20 NaN 0.20 平安银行 000001.SZ dividend
2 19960314.0 0.00000 0.000 1 19960529.0 实施 19951231 19960527.0 19960523.0 NaN 1996-05-24 0.50 0.5 1.00 平安银行 000001.SZ dividend
3 19990717.0 0.49000 0.600 1 NaN 实施 19990630 19991018.0 19991011.0 19991022.0 1999-10-15 NaN NaN 0.00 平安银行 000001.SZ dividend
4 NaN 0.00000 0.300 1 19930524.0 实施 19921231 19930524.0 19930509.0 19930524.0 1993-05-21 0.35 0.5 0.85 平安银行 000001.SZ dividend
5 20120816.0 0.09000 0.100 1 NaN 实施 20120630 20121019.0 20121012.0 20121019.0 2012-10-18 NaN NaN 0.00 平安银行 000001.SZ dividend
6 20170317.0 0.15800 0.158 1 NaN 实施 20161231 20170721.0 20170717.0 20170721.0 2017-07-20 NaN NaN 0.00 平安银行 000001.SZ dividend
7 20070524.0 0.00110 0.009 1 20070620.0 实施 20070615 20070620.0 20070614.0 20070620.0 2007-06-15 0.10 NaN 0.10 平安银行 000001.SZ dividend
8 20030424.0 0.12000 0.150 1 NaN 实施 20021231 20030929.0 20030923.0 20030929.0 2003-09-26 NaN NaN 0.00 平安银行 000001.SZ dividend
9 20180315.0 0.13600 0.136 1 NaN 实施 20171231 20180712.0 20180706.0 20180712.0 2018-07-11 NaN NaN 0.00 平安银行 000001.SZ dividend
1
2
div_stocks = div_stocks.set_index('record_date').groupby(['ts_code','stock_name'])["cash_div"].resample("Y").sum()
div_stocks.head()

输出:

ts_code    stock_name  record_date
000001.SZ  平安银行     1993-12-31     0.00000
                       1994-12-31     0.00000
                       1995-12-31     0.00000
                       1996-12-31     0.00000
                       1997-12-31     0.07494
Name: cash_div, dtype: float64

正如你们所见,用groupby统计后的record_date是以12-31日为结尾,那么我们干脆将其column名称改为end_date

1
2
3
sum_div_stocks = div_stocks.reset_index()
sum_div_stocks.rename(columns={'record_date':'end_date'}, inplace=True)
sum_div_stocks.head()

输出:

- ts_code stock_name end_date cash_div
0 000001.SZ 平安银行 1993-12-31 0.00000
1 000001.SZ 平安银行 1994-12-31 0.00000
2 000001.SZ 平安银行 1995-12-31 0.00000
3 000001.SZ 平安银行 1996-12-31 0.00000
4 000001.SZ 平安银行 1997-12-31 0.07494

接下来需要利用股票对应的基本每股收益(eps)来计算得出股息支付率(payout ratio)

获取各个股票的net income的具体方法跟上面的获取分红的类似

1
2
3
4
5
6
7
eps_stocks_sample = pd.DataFrame()
#遍历所有的stock_tickers,获取股票的指标并全部合并在一个DataDrame里面,为了演示,下面只获取前5只股票
for ticker,name in zip(stock_tickers['ts_code'][:5],stock_tickers['name'][:5]):
div = pro.fina_indicator(ts_code=ticker, fields='end_date,eps,dt_eps,roe') #这里选取了基本每股收益、稀释每股收益、净资产收益率
div['stock_name'] = name
eps_stocks_sample = eps_stocks_sample.append(div)
time.sleep(1)

eps_stocks.xlsx 的下载地址:链接: https://pan.baidu.com/s/1C6suTOKzE6qU-MipA9E0Cg 提取码: ypt5

1
2
eps_stocks = pd.read_excel('eps_stocks.xlsx',converters={'end_date':str})
eps_stocks.head()

输出:

- dt_eps end_date eps roe ts_code
0 1.14 20180930 1.14 8.9467 000001.SZ
1 0.73 20180630 0.73 5.9405 000001.SZ
2 0.33 20180331 0.33 2.9611 000001.SZ
3 0.33 20180331 0.33 2.9611 000001.SZ
4 1.30 20171231 1.30 10.9324 000001.SZ

从上面的第2和第3条数据可以发现,数据表中有数据重复,那么我们要先去重

1
2
eps_stocks.drop_duplicates(inplace=True)
eps_stocks.head()

输出:

- dt_eps end_date eps roe ts_code
0 1.14 20180930 1.14 8.9467 000001.SZ
1 0.73 20180630 0.73 5.9405 000001.SZ
2 0.33 20180331 0.33 2.9611 000001.SZ
4 1.30 20171231 1.30 10.9324 000001.SZ
6 1.06 20170930 1.06 9.1144 000001.SZ

鉴于在做此数据统计的时间为2019年1月5日,上市公司的最新财务报表为3季度的,还没有出2018年的年度报告,所以我们需要更改一下end_date的日期方便分红和eps这两个数据表的合并

因为tushare获取到的eps都是累计收益,所以提取日期最新的就可以

1
2
3
eps_stocks['end_date']= eps_stocks['end_date'].map(lambda x: '20181231' if x=='20180930'else x)
eps_stocks['end_date'] = pd.to_datetime(eps_stocks['end_date'], format='%Y%m%d')
eps_stocks.head()

输出:

- dt_eps end_date eps roe ts_code
0 1.14 2018-12-31 1.14 8.9467 000001.SZ
1 0.73 2018-06-30 0.73 5.9405 000001.SZ
2 0.33 2018-03-31 0.33 2.9611 000001.SZ
4 1.30 2017-12-31 1.30 10.9324 000001.SZ
6 1.06 2017-09-30 1.06 9.1144 000001.SZ
1
2
3
eps_div_stocks = sum_div_stocks.merge(eps_stocks, on=['ts_code','end_date'])
eps_div_stocks.drop_duplicates(inplace=True)
eps_div_stocks.info()

输出:

<class 'pandas.core.frame.DataFrame'>
Int64Index: 28077 entries, 0 to 28076
Data columns (total 7 columns):
ts_code       28077 non-null object
stock_name    28077 non-null object
end_date      28077 non-null datetime64[ns]
cash_div      28077 non-null float64
dt_eps        25388 non-null float64
eps           28009 non-null float64
roe           27739 non-null float64
dtypes: datetime64[ns](1), float64(4), object(2)
memory usage: 1.7+ MB

从上面数据info可以得知,cash_div 和 eps 的数据数目并不对称

1
eps_div_stocks.head()

输出:

- ts_code stock_name end_date cash_div dt_eps eps roe
0 000001.SZ 平安银行 2005-12-31 0.00000 0.16 0.18 6.3868
1 000001.SZ 平安银行 2006-12-31 0.00000 0.68 0.68 22.6025
2 000001.SZ 平安银行 2007-12-31 0.00110 1.22 1.27 27.2057
3 000001.SZ 平安银行 2008-12-31 0.00015 0.20 0.20 4.1761
4 000001.SZ 平安银行 2009-12-31 0.00000 1.62 1.62 27.2887

接下来还是继续做数据清洗

  1. 我们首先求出股息支付率(payout_ratio_basic)和稀释后的股息支付率(payout_ratio_diluted)
  2. 然后将inf和Nan值填充为0
1
2
3
4
5
6
import numpy as np
eps_div_stocks['payout_ratio_basic'] = eps_div_stocks['cash_div'] / eps_div_stocks['eps']
eps_div_stocks['payout_ratio_diluted'] = eps_div_stocks['cash_div'] / eps_div_stocks['dt_eps']
eps_div_stocks.replace([np.inf, -np.inf], np.nan,inplace=True)
eps_div_stocks.fillna(0, inplace=True)
eps_div_stocks.head(20)

输出:

- ts_code stock_name end_date cash_div dt_eps eps roe payout_ratio_basic payout_ratio_diluted
0 000001.SZ 平安银行 2005-12-31 0.00000 0.16 0.18 6.3868 0.000000 0.000000
1 000001.SZ 平安银行 2006-12-31 0.00000 0.68 0.68 22.6025 0.000000 0.000000
2 000001.SZ 平安银行 2007-12-31 0.00110 1.22 1.27 27.2057 0.000866 0.000902
3 000001.SZ 平安银行 2008-12-31 0.00015 0.20 0.20 4.1761 0.000750 0.000750
4 000001.SZ 平安银行 2009-12-31 0.00000 1.62 1.62 27.2887 0.000000 0.000000
5 000001.SZ 平安银行 2010-12-31 0.00000 1.91 1.91 23.2809 0.000000 0.000000
6 000001.SZ 平安银行 2011-12-31 0.00000 2.47 2.47 19.2441 0.000000 0.000000
7 000001.SZ 平安银行 2012-12-31 0.09000 2.62 2.62 16.9537 0.034351 0.034351
8 000001.SZ 平安银行 2013-12-31 0.13150 1.86 1.86 15.4724 0.070699 0.070699
9 000001.SZ 平安银行 2014-12-31 0.15200 1.73 1.73 16.2959 0.087861 0.087861
10 000001.SZ 平安银行 2015-12-31 0.16530 1.56 1.56 14.9530 0.105962 0.105962
11 000001.SZ 平安银行 2016-12-31 0.15300 1.32 1.32 12.4283 0.115909 0.115909
12 000001.SZ 平安银行 2017-12-31 0.15800 1.30 1.30 10.9324 0.121538 0.121538
13 000001.SZ 平安银行 2018-12-31 0.13600 1.14 1.14 8.9467 0.119298 0.119298
14 000002.SZ 万科A 2005-12-31 0.13500 0.00 0.39 18.6105 0.346154 0.000000
15 000002.SZ 万科A 2006-12-31 0.13500 0.39 0.39 19.7768 0.346154 0.346154
16 000002.SZ 万科A 2007-12-31 0.13500 0.73 0.73 21.9160 0.184932 0.184932
17 000002.SZ 万科A 2008-12-31 0.09000 0.37 0.37 13.1866 0.243243 0.243243
18 000002.SZ 万科A 2009-12-31 0.04500 0.48 0.48 15.3888 0.093750 0.093750
19 000002.SZ 万科A 2010-12-31 0.06300 0.66 0.66 17.8489 0.095455 0.095455
1
eps_div_stocks.describe()

输出:

- cash_div dt_eps eps roe payout_ratio_basic payout_ratio_diluted
count 28077.000000 28077.000000 28077.000000 28077.000000 28077.000000 28077.000000
mean 0.116133 0.330946 0.345212 6.638642 0.402828 0.372488
std 0.202428 0.584490 0.617731 86.752395 2.928442 2.904795
min 0.000000 -21.860000 -21.860000 -7988.845800 -71.052632 -71.052632
25% 0.000000 0.059000 0.093000 3.169100 0.000000 0.000000
50% 0.061000 0.230000 0.259600 7.318700 0.211765 0.180000
75% 0.150000 0.490000 0.510000 12.382300 0.434783 0.402685
max 10.999000 21.560000 21.560000 7590.961700 360.000000 360.000000

然后payout_ratio_basic出现负数…..都什么情况,居然有公司亏钱还分红。。。。有些公司居然分红比净利润高3倍还多。 注:这里不排除是由于我们上面将3季度的数据直接当作成全年的数据而造成的数据偏差。

接下来,我们筛选出从15年分红的上市公司 和 股息支付率大于0 和少于 100%的公司

1
2
3
sort_eps_div_stocks = eps_div_stocks.loc[eps_div_stocks['end_date']>'2014-12-31']
sort_eps_div_stocks = sort_eps_div_stocks.loc[sort_eps_div_stocks['payout_ratio_basic'].between(0, 1, inclusive=False)]
sort_eps_div_stocks.info()

输出:

<class 'pandas.core.frame.DataFrame'>
Int64Index: 7957 entries, 10 to 28076
Data columns (total 9 columns):
ts_code                 7957 non-null object
stock_name              7957 non-null object
end_date                7957 non-null datetime64[ns]
cash_div                7957 non-null float64
dt_eps                  7957 non-null float64
eps                     7957 non-null float64
roe                     7957 non-null float64
payout_ratio_basic      7957 non-null float64
payout_ratio_diluted    7957 non-null float64
dtypes: datetime64[ns](1), float64(6), object(2)
memory usage: 621.6+ KB
1
print('股票数:', len(sort_eps_div_stocks['stock_name'].unique()))

输出:

股票数: 2963

要求连续分红超过4年,这样可以过滤新股和不连续性

1
2
con_stocks = sort_eps_div_stocks.groupby("stock_name").filter(lambda x: len(x) >= 4)
con_stocks.head(12)

输出:

- ts_code stock_name end_date cash_div dt_eps eps roe payout_ratio_basic payout_ratio_diluted
10 000001.SZ 平安银行 2015-12-31 0.1653 1.5600 1.5600 14.9530 0.105962 0.105962
11 000001.SZ 平安银行 2016-12-31 0.1530 1.3200 1.3200 12.4283 0.115909 0.115909
12 000001.SZ 平安银行 2017-12-31 0.1580 1.3000 1.3000 10.9324 0.121538 0.121538
13 000001.SZ 平安银行 2018-12-31 0.1360 1.1400 1.1400 8.9467 0.119298 0.119298
24 000002.SZ 万科A 2015-12-31 0.4750 1.6400 1.6400 19.2403 0.289634 0.289634
25 000002.SZ 万科A 2016-12-31 0.7200 1.9000 1.9000 19.6815 0.378947 0.378947
26 000002.SZ 万科A 2017-12-31 0.7900 2.5400 2.5400 22.7952 0.311024 0.311024
27 000002.SZ 万科A 2018-12-31 0.9000 1.2670 1.2670 10.2572 0.710339 0.710339
42 000006.SZ 深振业A 2015-12-31 0.1121 0.3087 0.3087 9.7743 0.363136 0.363136
43 000006.SZ 深振业A 2016-12-31 0.1200 0.5767 0.5767 16.5687 0.208080 0.208080
44 000006.SZ 深振业A 2017-12-31 0.1800 0.5968 0.5968 15.2396 0.301609 0.301609
45 000006.SZ 深振业A 2018-12-31 0.1810 0.3728 0.3728 8.8331 0.485515 0.485515
1
len(con_stocks['stock_name'].unique())

输出:

1047
1
con_stocks

输出:

- ts_code stock_name end_date cash_div dt_eps eps roe payout_ratio_basic payout_ratio_diluted
10 000001.SZ 平安银行 2015-12-31 0.16530 1.5600 1.5600 14.9530 0.105962 0.105962
11 000001.SZ 平安银行 2016-12-31 0.15300 1.3200 1.3200 12.4283 0.115909 0.115909
12 000001.SZ 平安银行 2017-12-31 0.15800 1.3000 1.3000 10.9324 0.121538 0.121538
13 000001.SZ 平安银行 2018-12-31 0.13600 1.1400 1.1400 8.9467 0.119298 0.119298
24 000002.SZ 万科A 2015-12-31 0.47500 1.6400 1.6400 19.2403 0.289634 0.289634
25 000002.SZ 万科A 2016-12-31 0.72000 1.9000 1.9000 19.6815 0.378947 0.378947
26 000002.SZ 万科A 2017-12-31 0.79000 2.5400 2.5400 22.7952 0.311024 0.311024
27 000002.SZ 万科A 2018-12-31 0.90000 1.2670 1.2670 10.2572 0.710339 0.710339
42 000006.SZ 深振业A 2015-12-31 0.11210 0.3087 0.3087 9.7743 0.363136 0.363136
43 000006.SZ 深振业A 2016-12-31 0.12000 0.5767 0.5767 16.5687 0.208080 0.208080
44 000006.SZ 深振业A 2017-12-31 0.18000 0.5968 0.5968 15.2396 0.301609 0.301609
45 000006.SZ 深振业A 2018-12-31 0.18100 0.3728 0.3728 8.8331 0.485515 0.485515
86 000009.SZ 中国宝安 2015-12-31 0.01900 0.5000 0.5000 19.4651 0.038000 0.038000
87 000009.SZ 中国宝安 2016-12-31 0.07000 0.1100 0.1100 5.2409 0.636364 0.636364
88 000009.SZ 中国宝安 2017-12-31 0.02000 0.0600 0.0600 2.8125 0.333333 0.333333
89 000009.SZ 中国宝安 2018-12-31 0.02000 0.0459 0.0459 1.9550 0.435730 0.435730
141 000014.SZ 沙河股份 2015-12-31 0.01805 0.2626 0.2626 7.6702 0.068736 0.068736
142 000014.SZ 沙河股份 2016-12-31 0.03700 0.1418 0.1418 3.9409 0.260931 0.260931
143 000014.SZ 沙河股份 2017-12-31 0.01500 0.0378 0.0378 1.0332 0.396825 0.396825
144 000014.SZ 沙河股份 2018-12-31 0.01000 0.0112 0.0112 0.3056 0.892857 0.892857
207 000021.SZ 深科技 2015-12-31 0.04750 0.1228 0.1228 3.5563 0.386808 0.386808
208 000021.SZ 深科技 2016-12-31 0.05000 0.1457 0.1457 4.0989 0.343171 0.343171
209 000021.SZ 深科技 2017-12-31 0.05000 0.3679 0.3679 9.7398 0.135906 0.135906
210 000021.SZ 深科技 2018-12-31 0.05000 0.2996 0.2996 7.3247 0.166889 0.166889
237 000023.SZ 深天地A 2015-12-31 0.03800 0.1926 0.1926 7.1644 0.197300 0.197300
238 000023.SZ 深天地A 2016-12-31 0.05000 0.0717 0.0717 2.5804 0.697350 0.697350
239 000023.SZ 深天地A 2017-12-31 0.04000 0.2198 0.2198 7.6296 0.181984 0.181984
240 000023.SZ 深天地A 2018-12-31 0.05000 0.0770 0.0770 2.5683 0.649351 0.649351
252 000026.SZ 飞亚达A 2015-12-31 0.09500 0.3099 0.3099 6.1894 0.306551 0.306551
253 000026.SZ 飞亚达A 2016-12-31 0.10000 0.2522 0.2522 4.7387 0.396511 0.396511
27874 603808.SH 歌力思 2017-12-31 0.26600 0.9100 0.9100 15.8729 0.292308 0.292308
27875 603808.SH 歌力思 2018-12-31 0.26000 0.8000 0.8000 12.0619 0.325000 0.325000
27897 603828.SH 柯利达 2015-12-31 0.14250 0.4700 0.4700 7.5026 0.303191 0.303191
27898 603828.SH 柯利达 2016-12-31 0.13500 0.2800 0.2800 4.8021 0.482143 0.482143
27899 603828.SH 柯利达 2017-12-31 0.10000 0.1700 0.1700 5.5200 0.588235 0.588235
27900 603828.SH 柯利达 2018-12-31 0.02700 0.1700 0.1700 6.0944 0.158824 0.158824
27927 603869.SH 新智认知 2015-12-31 0.07600 0.3500 0.3500 11.5250 0.217143 0.217143
27928 603869.SH 新智认知 2016-12-31 0.10000 0.6800 0.6800 7.8714 0.147059 0.147059
27929 603869.SH 新智认知 2017-12-31 0.15000 0.7700 0.7700 7.4704 0.194805 0.194805
27930 603869.SH 新智认知 2018-12-31 0.25000 0.0000 0.8200 7.7023 0.304878 0.000000
27945 603885.SH 吉祥航空 2015-12-31 0.60000 0.9700 0.9700 39.0026 0.618557 0.618557
27946 603885.SH 吉祥航空 2016-12-31 0.25000 1.0200 1.0200 22.7241 0.245098 0.245098
27947 603885.SH 吉祥航空 2017-12-31 0.25000 0.7400 0.7400 16.2869 0.337838 0.337838
27948 603885.SH 吉祥航空 2018-12-31 0.22800 0.8000 0.8000 15.6596 0.285000 0.285000
27956 603889.SH 新澳股份 2015-12-31 0.47500 0.8200 0.8300 12.9910 0.572289 0.579268
27957 603889.SH 新澳股份 2016-12-31 0.35000 0.5000 0.5000 14.1293 0.700000 0.700000
27958 603889.SH 新澳股份 2017-12-31 0.20000 0.5900 0.5900 12.1545 0.338983 0.338983
27959 603889.SH 新澳股份 2018-12-31 0.25000 0.4200 0.4300 7.3675 0.581395 0.595238
27964 603898.SH 好莱客 2015-12-31 0.23750 0.5800 0.5800 24.4542 0.409483 0.409483
27965 603898.SH 好莱客 2016-12-31 0.17000 0.8500 0.8600 23.9497 0.197674 0.200000
27966 603898.SH 好莱客 2017-12-31 0.25400 1.1400 1.1500 21.6325 0.220870 0.222807
27967 603898.SH 好莱客 2018-12-31 0.32600 0.9700 0.9700 14.0987 0.336082 0.336082
27968 603899.SH 晨光文具 2015-12-31 0.47500 0.9289 0.9289 24.8361 0.511358 0.511358
27969 603899.SH 晨光文具 2016-12-31 0.50000 0.5358 0.5358 21.4457 0.933184 0.933184
27970 603899.SH 晨光文具 2017-12-31 0.25000 0.6892 0.6892 24.0902 0.362739 0.362739
27971 603899.SH 晨光文具 2018-12-31 0.25000 0.6790 0.6790 20.6088 0.368189 0.368189
28066 603997.SH 继峰股份 2015-12-31 0.14250 0.4400 0.4400 16.6785 0.323864 0.323864
28067 603997.SH 继峰股份 2016-12-31 0.13000 0.5900 0.5900 17.4496 0.220339 0.220339
28068 603997.SH 继峰股份 2017-12-31 0.24000 0.4600 0.4600 18.0125 0.521739 0.521739
28069 603997.SH 继峰股份 2018-12-31 0.28000 0.3700 0.3700 13.1534 0.756757 0.756757

要求分红和eps都保持增长

1
monotonic_cash_div = pd.DataFrame()
1
2
3
4
for ticker in con_stocks['ts_code'].unique():
if (con_stocks[con_stocks['ts_code']==ticker]['cash_div'].is_monotonic) and (con_stocks[con_stocks['ts_code']==ticker]['eps'].is_monotonic) :
monotonic_cash_div = monotonic_cash_div.append(con_stocks[con_stocks['ts_code']==ticker])
monotonic_cash_div

输出:

- ts_code stock_name end_date cash_div dt_eps eps roe payout_ratio_basic payout_ratio_diluted
1357 000507.SZ 珠海港 2015-12-31 0.01425 0.0996 0.0996 3.1604 0.143072 0.143072
1358 000507.SZ 珠海港 2016-12-31 0.02000 0.1320 0.1320 4.0523 0.151515 0.151515
1359 000507.SZ 珠海港 2017-12-31 0.02000 0.1781 0.1781 5.2472 0.112296 0.112296
1360 000507.SZ 珠海港 2018-12-31 0.03600 0.1814 0.1814 5.1128 0.198456 0.198456
2031 000568.SZ 泸州老窖 2015-12-31 0.76000 1.0500 1.0500 14.7377 0.723810 0.723810
2032 000568.SZ 泸州老窖 2016-12-31 0.80000 1.3750 1.3750 18.0952 0.581818 0.581818
2033 000568.SZ 泸州老窖 2017-12-31 0.96000 1.7980 1.7980 19.5248 0.533927 0.533927
2034 000568.SZ 泸州老窖 2018-12-31 1.25000 1.8780 1.8780 17.5375 0.665602 0.665602
2789 000661.SZ 长春高新 2015-12-31 0.47500 2.9300 2.9300 23.7469 0.162116 0.162116
2790 000661.SZ 长春高新 2016-12-31 0.80000 2.8500 3.0800 17.0790 0.259740 0.280702
2791 000661.SZ 长春高新 2017-12-31 0.80000 3.8900 3.8900 15.9014 0.205656 0.205656
2792 000661.SZ 长春高新 2018-12-31 0.80000 4.9300 4.9300 17.5577 0.162272 0.162272
3506 000733.SZ 振华科技 2015-12-31 0.02850 0.3800 0.3800 5.1496 0.075000 0.075000
3507 000733.SZ 振华科技 2016-12-31 0.03000 0.3870 0.3870 4.8367 0.077519 0.077519
3508 000733.SZ 振华科技 2017-12-31 0.04000 0.4340 0.4340 5.0051 0.092166 0.092166
3509 000733.SZ 振华科技 2018-12-31 0.05000 0.4500 0.4500 4.9970 0.111111 0.111111
3554 000738.SZ 航发控制 2015-12-31 0.01615 0.1713 0.1713 4.2154 0.094279 0.094279
3555 000738.SZ 航发控制 2016-12-31 0.02000 0.1823 0.1823 4.3150 0.109709 0.109709
3556 000738.SZ 航发控制 2017-12-31 0.02000 0.1900 0.1900 4.3241 0.105263 0.105263
3557 000738.SZ 航发控制 2018-12-31 0.03500 0.2037 0.2037 4.4605 0.171821 0.171821
4509 000860.SZ 顺鑫农业 2015-12-31 0.09500 0.6594 0.6594 7.1823 0.144070 0.144070
4510 000860.SZ 顺鑫农业 2016-12-31 0.10000 0.7231 0.7231 6.7948 0.138293 0.138293
4511 000860.SZ 顺鑫农业 2017-12-31 0.10000 0.7683 0.7683 6.3378 0.130157 0.130157
4512 000860.SZ 顺鑫农业 2018-12-31 0.15000 0.9400 0.9400 7.3474 0.159574 0.159574
6205 002026.SZ 山东威达 2015-12-31 0.04750 0.2300 0.2300 4.9929 0.206522 0.206522
6206 002026.SZ 山东威达 2016-12-31 0.06000 0.2600 0.2600 5.3618 0.230769 0.230769
6207 002026.SZ 山东威达 2017-12-31 0.06000 0.3000 0.3000 5.4724 0.200000 0.200000
6208 002026.SZ 山东威达 2018-12-31 0.06000 0.3500 0.3500 6.1241 0.171429 0.171429
6951 002088.SZ 鲁阳节能 2015-12-31 0.09500 0.2500 0.2500 3.6295 0.380000 0.380000
6952 002088.SZ 鲁阳节能 2016-12-31 0.10000 0.4500 0.4500 6.3698 0.222222 0.222222
22037 600592.SH 龙溪股份 2017-12-31 0.10000 0.1777 0.1777 3.7472 0.562746 0.562746
22038 600592.SH 龙溪股份 2018-12-31 0.10000 0.2103 0.2103 4.5085 0.475511 0.475511
22839 600660.SH 福耀玻璃 2015-12-31 0.71250 1.1000 1.1000 20.6719 0.647727 0.647727
22840 600660.SH 福耀玻璃 2016-12-31 0.75000 1.2500 1.2500 18.2580 0.600000 0.600000
22841 600660.SH 福耀玻璃 2017-12-31 0.75000 1.2600 1.2600 17.0044 0.595238 0.595238
22842 600660.SH 福耀玻璃 2018-12-31 1.15000 1.3000 1.3000 16.4793 0.884615 0.884615
23659 600737.SH 中粮糖业 2015-12-31 0.02850 0.0371 0.0371 1.2821 0.768194 0.768194
23660 600737.SH 中粮糖业 2016-12-31 0.03500 0.2510 0.2510 8.1850 0.139442 0.139442
23661 600737.SH 中粮糖业 2017-12-31 0.13000 0.3607 0.3607 10.7010 0.360410 0.360410
23662 600737.SH 中粮糖业 2018-12-31 0.17000 0.3890 0.3890 10.7262 0.437018 0.437018
23882 600757.SH 长江传媒 2015-12-31 0.01900 0.2700 0.2700 6.6470 0.070370 0.070370
23883 600757.SH 长江传媒 2016-12-31 0.03157 0.4900 0.4900 11.2244 0.064429 0.064429
23884 600757.SH 长江传媒 2017-12-31 0.05000 0.5100 0.5100 10.5569 0.098039 0.098039
23885 600757.SH 长江传媒 2018-12-31 0.10000 0.5200 0.5200 10.0085 0.192308 0.192308
25908 600995.SH 文山电力 2015-12-31 0.06270 0.2200 0.2200 7.2083 0.285000 0.285000
25909 600995.SH 文山电力 2016-12-31 0.07000 0.3300 0.3300 10.4164 0.212121 0.212121
25910 600995.SH 文山电力 2017-12-31 0.10000 0.3300 0.3300 9.5117 0.303030 0.303030
25911 600995.SH 文山电力 2018-12-31 0.10000 0.6900 0.6900 17.8352 0.144928 0.144928
26141 601100.SH 恒立液压 2015-12-31 0.05320 0.1000 0.1000 1.8366 0.532000 0.532000
26142 601100.SH 恒立液压 2016-12-31 0.06000 0.1100 0.1100 2.0166 0.545455 0.545455
26143 601100.SH 恒立液压 2017-12-31 0.06600 0.6100 0.6100 10.3930 0.108197 0.108197
26144 601100.SH 恒立液压 2018-12-31 0.22000 0.8200 0.8200 17.3800 0.268293 0.268293
26584 601588.SH 北辰实业 2015-12-31 0.05700 0.1800 0.1800 5.5217 0.316667 0.316667
26585 601588.SH 北辰实业 2016-12-31 0.06000 0.1800 0.1800 5.2394 0.333333 0.333333
26586 601588.SH 北辰实业 2017-12-31 0.06000 0.3400 0.3400 9.4017 0.176471 0.176471
26587 601588.SH 北辰实业 2018-12-31 0.11000 0.3500 0.3500 9.0395 0.314286 0.314286
27927 603869.SH 新智认知 2015-12-31 0.07600 0.3500 0.3500 11.5250 0.217143 0.217143
27928 603869.SH 新智认知 2016-12-31 0.10000 0.6800 0.6800 7.8714 0.147059 0.147059
27929 603869.SH 新智认知 2017-12-31 0.15000 0.7700 0.7700 7.4704 0.194805 0.194805
27930 603869.SH 新智认知 2018-12-31 0.25000 0.0000 0.8200 7.7023 0.304878 0.000000
1
len(monotonic_cash_div['ts_code'].unique())

输出:

28

最后,我们按照筛选的标准得到了28只股票

1
print(monotonic_cash_div['ts_code'].unique().tolist())

输出:

['000507.SZ', '000568.SZ', '000661.SZ', '000733.SZ', '000738.SZ', '000860.SZ', '002026.SZ', '002088.SZ', '002189.SZ', '002360.SZ', '002685.SZ', '300121.SZ', '300269.SZ', '300308.SZ', '600277.SH', '600323.SH', '600326.SH', '600377.SH', '600566.SH', '600567.SH', '600592.SH', '600660.SH', '600737.SH', '600757.SH', '600995.SH', '601100.SH', '601588.SH', '603869.SH']

细心的童稚可能会发现数据表中的ROE好像没有啥用?其实这个ROE是用于计算每只股票的增长率(growth),因为使用现金流折现模型(DCF模型)来估值的时候会输入g(growth)这个值,其实这个值就是通过payout_ratio_basic * ROE 得出来的。他的原理是:公司未来增长率的高低往往取决于公司留了多少资金用于发展,而不是分红。如果大家还要印象的话,18年4月份闹得沸沸扬扬的格力电器不分红事件就是这个道理,董明珠不分红,保留资金用于发展企业。

第二部分:计算股票间的相关性(correlation)和贝塔值(beta)

为啥要计算股票间的相关性? “不要把所有的鸡蛋都放在一个篮子了”, 这里说的就是投资的分散性。 假设我们用刚才得到的28只股票用于构建一个股票投资组合(stock portfolio), 那么一只股票的下跌和另外27只股票的下跌还是上涨往往由股票间的相关性来决定

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
tickers = monotonic_cash_div['ts_code'].unique().tolist()
tickers.append('000001.SH')
#先建立一个字典,用来存储股票对应的价格
all_data = {}
#遍历list里面的股票,可以写入多个股票
for ticker in tickers:
#获取上证指数的日线数据
if ticker == '000001.SH':
all_data[ticker] = pro.index_daily(ts_code=ticker, start_date='20140101', end_date='20190104')
#获取各股票的日线数据
else:
all_data[ticker] = pro.daily(ts_code=ticker, start_date='20140101', end_date='20190104')
#用for循环遍历股票价格并转换为dataframe的形式
price = pd.DataFrame({tic: data['close']
for tic, data in all_data.items()})
#计算股票价格每日变化
returns = price.pct_change()[1:]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np

fig, ax = plt.subplots(figsize=(28,28))


cm = np.corrcoef(returns.values.T)
sns.set(font_scale=1.5)
hm = sns.heatmap(cm,
cbar=True,
annot=True,
square=True,
fmt='.2f',
annot_kws={'size': 15},
yticklabels=returns.columns,
xticklabels=returns.columns,
ax=ax)

输出:

计算贝塔值(beta)

1
2
3
4
5
6
7
8
def calc_beta(s,m):
# m = 指数数据
# s = 个股数据
covariance = np.cov(s,m)[0][1] # 计算两者的协方差
variance = np.var(m) # 计算指数的方差

beta = covariance / variance
return beta
1
2
3
m = returns['000001.SH']
s = returns['600377.SH']
print(calc_beta(s,m))

输出:

0.8200824079335387

第二种方法计算贝塔值(beta)

1
import statsmodels.api as sm
1
2
model = sm.OLS(endog=s, exog=m).fit()
print(model.summary())

输出:

                            OLS Regression Results                            
==============================================================================
Dep. Variable:              600377.SH   R-squared:                       0.456
Model:                            OLS   Adj. R-squared:                  0.455
Method:                 Least Squares   F-statistic:                     1023.
Date:                Sat, 05 Jan 2019   Prob (F-statistic):          1.38e-163
Time:                        09:41:05   Log-Likelihood:                 3518.5
No. Observations:                1222   AIC:                            -7035.
Df Residuals:                    1221   BIC:                            -7030.
Df Model:                           1                                         
Covariance Type:            nonrobust                                         
==============================================================================
                 coef    std err          t      P>|t|      [0.025      0.975]
------------------------------------------------------------------------------
000001.SH      0.8194      0.026     31.988      0.000       0.769       0.870
==============================================================================
Omnibus:                      312.533   Durbin-Watson:                   2.005
Prob(Omnibus):                  0.000   Jarque-Bera (JB):             5298.391
Skew:                          -0.717   Prob(JB):                         0.00
Kurtosis:                      13.100   Cond. No.                         1.00
==============================================================================

Warnings:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.

使用statsmodels的得出的数据更为详细,可以看出000001.SH的coef就是我们想要的beta值。这个0.8194说明了,如果大市上升1%,那么个股会上升0.8%。 但我们要注意的是, R-squared的值只有0.456,这意味着用大市的波动来解释这只个股的波动的可靠性只有45.6%。