赞
踩
引言
杜鲁门说,“你不能预测未来的唯一问题,就在于你不了解历史”。欧奈尔在《笑傲股市》一书中,通过总结1880-2008年表现最为强劲的100多只股票价格形态图来洞察牛股的选股和把握时机,并结合基本面分析提出了CANSLIM选股法则。美国股市有200多年历史,经历了各种跌宕起伏,如同一位饱经风霜的老人,有无尽的人生经验值得分享。而A股才将近30年,像一个潮气蓬勃的少年,跌跌撞撞,却又对未来满怀期待。那么A股近30年以来,市场整体收益率情况如何?有哪些公司股票经得起时间考验,取得了持续的高收益率,又有哪些公司股票从终点回到起点,甚至跌到怀疑人生?
本文基于A股2005-2020.2期间所有个股的交易数据,使用Python考察市场收益率统计分布,以及累计涨(跌)幅居前的股票及其特征,为大家挖掘中长期牛股提供一定的技术参考和分析路径。“授人以鱼不如授人以渔”,所以下面着重从Python量化的角度为大家展示数据的处理和分析过程,而结果的解读仁者见仁,不做深入展开,文中提及的股票也不构成任何投资建议。
01
获取数据
考虑到2005年股权分置改革以前,A股市场制度较不健全,上市公司数量相对较少,因此考察的是2005-2020.2年期间的样本数据,不含已退市个股。数据使用tushare pro下载并保存到当地sqlite3数据库中。csv格式数据(截至2020.2.24)已分享在百度网盘上,在公众号后台回复“A股数据”或“20200225”可获取下载链接。如需获取本地数据库下载和调用数据的所有完整源码,可通过加入知识星球。关于数据库管理与操作参见推文【手把手教你】Python面向对象编程入门及股票数据管理应用实例。
- import pandas as pd
- #以下是自己写的脚本文件,包括数据获取和画图
- from base import ts_pro,sql_engine
- pro=ts_pro()
- from update_sql import update_sql,get_trade_date,info_sql
- from RPS import get_data,RPS
- from plot_stock import stock_plot
- #更新数据库
- update_sql(table_name='daily_data')
- #数据库已更新至20200225日数据
使用本地脚本文件从数据库中调取2004年2020年2月24日所有A股的前复权价格数据。下表展示的是最近5个交易日3307只个股的价格数据。
- all_df=get_data(date='20040101')
- all_df.index=pd.to_datetime(all_df.index)
- all_df.tail()
(点击查看大图)
02
2020年以来涨跌统计分析
由于新冠肺炎疫情的黑天鹅事件,2月3日春节后第一天开盘上证综指暴跌接近8个点,出现千股跌停的惨况,但是这只黑天鹅并未吓退自2019年年底以来的科技股和特斯拉行情。科技股的半导体、元器件和芯片概念个股涨幅惊人,新股斯达半导连续16个一字板,收益率达到318%。特斯拉概念的奥特佳和模塑科技股价均实现了翻番。不少踏空的人感叹,这波行情来得太特么出乎意料了,难道新冠肺炎对经济没有影响吗?其实事实有时候不是很重要的,人们对事实的反应才是最重要的。在股市上,基本面和消息本身不是最重要的,最重要的是人们对它的理解和反应。股价不是对基本面的反映,而是对想象力的反映股市对新东西的炒作有自己的逻辑,这个逻辑是先把股价炒上天,再用时间来还债。这就是很多人看不懂股市而天天喊风险、喊泡沫的原因。
- def plot_2020_stock(r=False):
- from pyecharts import Bar
- #注意这里用的pyecharts为0.5.11旧版本
- df_2020=all_df['2020']
- df_2020_ret=df_2020.apply(lambda x:(((x/x.shift(1)-1).fillna(0)+1.0).cumprod()).iloc[-1]-1)
- df=df_2020_ret.sort_values(ascending=r)[:10]
- attr=df.index
- v=df.values.round(2)
- title='涨' if r==False else '跌'
- bar=Bar(f'2020年以来最大{title}幅',
- width=900,height=400,title_pos='center')
- bar.add('',attr,v,is_splitline_show=False,
- is_label_show=True,xaxis_label_textsize=9,
- is_datazoom_show=False)
- return bar
- plot_2020_stock()
plot_2020_stock(r=True)
03
2005-2020年历年收益率统计分析
接下来分析A股2005年以来历年的个股收益率情况。首先对2006年-2020年历年收益率进行描述性统计分析。
- #从数据库从调用数据
- def describe_ret():
- engine=sql_engine()
- dec_df=pd.DataFrame()
- for y in range(2006,2021):
- d1=str(y)+'0000'
- d2=str(y+1)+'0000'
- sql=f"select * from daily_data where trade_date>{d1} and trade_date<{d2}"
- sql_df=pd.read_sql(sql,engine)
- data=sql_df.sort_values(['ts_code','trade_date'])
- data['adjclose']=data.groupby('ts_code').apply(lambda x:x.close*x.adj_factor/x.adj_factor.iloc[-1]).values
- df=data.set_index(['trade_date','ts_code'])['adjclose']
- #数据重排,列名为代码
- df_close=df.unstack()
- df_ret=df_close.apply(lambda x:(((x/x.shift(1)-1).fillna(0)+1.0).cumprod()).iloc[-1]-1)
- dec_df[str(y)]=df_ret.describe().round(3)
- return dec_df
describe_ret()
(点击查看大图)
- def find_annual_stock(df):
- #将时间索引转化为年
- new_df=df.to_period('Y')
- #根据年进行聚类求每一年的累计收益率
- dd=new_df.groupby(new_df.index).apply(lambda x: (((x/x.shift(1)-1).fillna(0)+1.0).cumprod()).iloc[-1])
- #获取每一年收益率最大的个股及其收益率
- final_df=pd.DataFrame()
- final_df['股票名称']=dd.T.idxmax()
- final_df['累计收益率']=dd.T.max()-1
- #股票代码
- code_list=pro.stock_basic(list_status='L').ts_code.values
- name_list=pro.stock_basic(list_status='L').name.values
- stock_dict=dict(zip(name_list,code_list))
- #将代码隐射为股票名称
- final_df['code']=[stock_dict[name] for name in list(final_df['股票名称'])]
- return final_df
- #画图,更直观化
- def plot_annual_stock(df):
- from pyecharts import Bar
- #2020年已经分析过了
- attr=df.股票名称[1:-1]
- attr=[str(i)+'\n'+str(j) for (i,j) in zip(attr.values,attr.index)]
- v=df.累计收益率[1:-1].round(2)
- bar=Bar('历年涨幅最大个股\n2005年-2020年',
- width=900,height=400,title_pos='center')
- bar.add('',attr,v,is_splitline_show=False,
- is_label_show=True,xaxis_label_textsize=9,
- is_datazoom_show=False)
- return bar
- final_df=find_annual_stock(all_df)
- plot_annual_stock(final_df)
stock_plot('暴风集团',250*5).kline_plot(ktype=0)
stock_plot('万集科技').kline_plot(ktype=0)
04
2005-2020年区间累计涨幅
前面是以某一年为分析期间,如果把时间拉长,有哪些公司股票能够长期持续领跑呢?又有哪些公司是跌到妈都不认得的?
(1)以2005年为起点,考察往后1至15年各股的累计收益率情况。2005-XX年(XX=2005, 2006,...,2020)期间累计行情排名前五以及倒数前五的由下图所示。一眼望去,涨幅居前的是我们常说的大白马股,其中生物医药和白酒板块的个股十分抢眼,尤其是恒瑞医药,股价十五年实现了141倍增长,难怪高瓴资本的张磊特别偏好生物医药股。跌幅居前的个股就不说了,中国石油一出场即是颠覆,此后便坐上了滑翔机。
- def ret_2005_xx():
- ret_df=pd.DataFrame()
- for y in range(2005,2021):
- year=str(y)
- data=all_df[:year]
- total_ret=data.apply(lambda x: (((x/x.shift(1)-1).fillna(0)+1.0).cumprod()).iloc[-1]-1)
- tret=total_ret.sort_values(ascending=False).round(2)
- ret_df[year]=list(zip(tret.index,tret.values))
- return ret_df
ret_2005_xx()
(点击查看大图)
( 点击查看大图 )stock_plot('恒瑞医药',n=15*250).kline_plot(ktype=0)
(2)以2020.2.25日为终点,考察往前1至15年各股的累计收益率情况。XX-2020年(XX=2005, 2006,...,2020)期间累计行情排名前五以及倒数前五的由下图所示。结果与(1)相比有些差异,近三年来涨幅居前的主要是科技和新兴主题概念股(如网红经济星期六),当然这些短期暴涨股很可能走的是先透支后还债的行情。不出意外,时间一拉长,涨幅居前的仍然是生物医药股,其中泰康生物是股群中最靓的仔,连续七八年位列涨幅前五。看来长期牛股是经得起时间考验并不断创新高的,欧奈尔在总结美股牛股的时候提出,“当股价涨至接近年度最高点时买入股票,千万不要在股价跌得很低从而看似很便宜的情况下买入。应该买那些价格更高而不是价格更低的股票。”
- def cal_cum_ret(year):
- year=str(year)
- data=all_df[year:]
- total_ret=data.apply(lambda x: (((x/x.shift(1)-1).fillna(0)+1.0).cumprod()).iloc[-1]-1)
- first_=(total_ret.sort_values(ascending=False)[:10]).round(2)
- last_=(total_ret.sort_values(ascending=False)[-10:]).round(2)
- return first_,last_
-
- def ret_rank():
- up,down=pd.DataFrame(),pd.DataFrame()
- for year in range(2005,2021):
- u,d=cal_cum_ret(year)
- up[str(year)]=list(zip(u.index,u.values))
- down[str(year)]=list(zip(d.index,d.values))
- return up,down
up_ret,down_ret=ret_rank()
up_ret
(点击查看大图)
down_ret
(点击查看大图)
05
2005年至2019收益率评价指标
下面结合绩效评价指标,考察2005至2019期间个股的累计总收益率、年化收益率、最大回撤和夏普比率情况。
- def performance(all_df):
- cum_ret=all_df[:'2019'].apply(lambda x: ((x/x.shift(1)-1).fillna(0)+1.0).cumprod())
- total_ret=(cum_ret.iloc[-1]-1).sort_values(ascending=False)
- annual_ret=total_ret.apply(lambda x:pow(1+x,1/15)-1)
- dd=(cum_ret.cummax()-cum_ret)/cum_ret.cummax()
- d=dd.max()
- exReturn=all_df.apply(lambda x: (x/x.shift(1)-1).fillna(0)-0.03/250)
- sharper_atio=np.sqrt(len(exReturn))*exReturn.mean()/exReturn.std()
- perf_df=pd.DataFrame()
- perf_df['总收益率']=round(total_ret,3)
- perf_df['年化收益率%']=round(annual_ret*100,2)
- perf_df['最大回撤%']=round(d*100,2)
- perf_df['夏普比率']=round(sharper_atio,2)
- return perf_df
查看年化收益率排名前十五的个股情况,恒瑞医药2005-2019年累计收益率为139.99%,年化收益39%,最大回撤39.22%,夏普比率为3.97,作为“买入持有策略”当之无愧的王者,当然排在第二的贵州茅台似乎知名度更高。其他上榜的个股年化超过25%,夏普比率大于2.5,但最大回撤均接近或超过60%,金证股份更高达90%。
- perf_df=performance(all_df)
- perf0=perf_df.sort_values('年化收益率%',ascending=False)
- perf0[:15].T
最后,看下所有A股2005-2019年期间收益率和业绩评价指标的描述性统计。A股十五年总收益率均值为200%,年化均值4.65%,最大回撤75.94%,夏普比率0.84,似乎不太理想。但是回到“炒股是少数人赚钱的游戏”上又似乎很合理,因为个股之间的分化非常大,强者恒强!
perf_df.describe().round(2)
结语
本文使用Python对A股2005-2020历史数据进行了统计分析,试图从个股收益率的维度为大家揭示市场的某种微观结构及其演变。本文并未对中长期牛股及其涨跌背景深入展开分析,对此感兴趣的读者可以结合宏观背景、公司基本面进一步总结国内牛股的特征,分析某些行业某些个股之所以能持续走强的深层次原因。尽管过去不能代表未来,但历史总是惊人的相似。多层次多维度去总结和分析股市的历史走势,有助于我们更好的把握当下和未来。实际上任何技术、方法、工具都必须依托在对股市本质认识的基础上。经历、教育背景、资金大小、交易周期等不同,对股市的理解必然不一样,但关键是要形成与自己操作风格相匹配的股市交易系统。比如你做长线投资,必须从长线的角度去理解股市长期波动的主导因素是什么。
当前疫情的阴霾还未退散,经济难言触底反弹,很多人感到迷茫与彷徨,但我坚信我们生活在一个拥有无穷机会的时期,是一个新理念、新产业和新领域层出不穷的时代。但是,你只有系统地学习和不断总结,才能学会如何认清并充分利用这些新机遇。
关于Python金融量化
专注于分享Python在金融量化领域的应用。加入知识星球,可以免费获取量化投资视频资料、量化金融相关PDF资料、公众号文章Python完整源码、量化投资前沿分析框架,与博主直接交流、结识圈内朋友等。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。