杜鲁门说,“ 你不能预测未来的唯一问题,就在于你不了解历史”。
欧奈尔在《笑傲股市》一书中,通过总结1880-2008年表现最为强劲的100多只股票价格形态图来洞察牛股的选股和把握时机,并结合基本面分析提出了CANSLIM选股法则。美国股市有200多年历史,经历了各种跌宕起伏,如同一位饱经风霜的老人,有无尽的人生经验值得分享。而A股才将近30年,像一个潮气蓬勃的少年,跌跌撞撞,却又对未来满怀期待。 那幺A股近30年以来,市场整体收益率情况如何?
有哪些公司股票经得起时间考验,取得了持续的高收益率,又有哪些公司股票从终点回到起点,甚至跌到怀疑人生?
本文基于A股2005-2020.2期间所有个股的交易数据,使用Python考察市场收益率统计分布,以及累计涨(跌)幅居前的股票及其特征,为大家挖掘中长期牛股提供一定的技术参考和分析路径。“授人以鱼不如授人以渔”,所以下面 着重从Python量化的角度为大家展示数据的处理和分析过程,而结果的解读仁者见仁,不做深入展开,文中提及的股票也不构成任何投资建议。
01
获取数据
考虑到2005年股权分置改革以前,A股市场制度较不健全,上市公司数量相对较少,因此考察的是2005-2020.2年期间的样本数据,不含已退市个股。
数据使用tushare pro下载并保存到当地sqlite3数据库中。
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()
(
点击查看大图
)
2006年市场只有1353只个股,到了2020年增加到3783只。
从收益率的均值来看,只有2008、2011和2018三年为负,其余均为正,看来这十五年里个股平均是涨多跌少啊。
先别急,可能大多是被平均了呢, 何况炒股一直是少数人赚钱的游戏。
从标准差和各分位数不难看,个股之间每年的分化都特别大
,尤其在2007和2015年典型的牛市期间,标准差超过100%。
除了收益率均值为负的那三年,其余年份的标准差均超过20%,涨幅最大的高达几倍至十几二十倍,最差的亏损70%多。
2019年,万集科技搭上了ETC这波快车,业绩大幅增长,2019年股价翻了四倍多。
另外,值得一提的是,2015年的新股次新股明星暴风集团一年实现21倍的收益率,后来却因为业绩困局一路被腰斩,从116.46(前复权)跌至今天的3.25,惨不忍睹。
看来出来混总是要还的, 正所谓佛魔相伴,如果没有基本面支撑,透支行情背后就是还债行情
。
历年涨幅最大个股
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
(
点击查看大图
)
0 5
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历史数据进行了统计分析,试图从个股收益率的维度为大家揭示市场的某种微观结构及其演变。本文并未对中长期牛股及其涨跌背景深入展开分析,对此感兴趣的读者可以结合宏观背景、公司基本面进一步总结国内牛股的特征,分析某些行业某些个股之所以能持续走强的深层次原因。尽管过去不能代表未来,但历史总是惊人的相似。 多层次多维度去总结和分析股市的历史走势,有助于我们更好的把握当下和未来。
实际上
任何技术、方法、工具都必须依托在对股市本质认识的基础上。经历、教育背景、资金大小、交易周期等不同,对股市的理解必然不一样,但关键是要形成与自己操作风格相匹配的股市交易系统。比如你做长线投资,必须从长线的角度去理解股市长期波动的主导因素是什幺
。
当前疫情的阴霾还未退散,经济难言触底反弹,很多人感到迷茫与彷徨,但我坚信 我们生活在一个拥有无穷机会的时期,是一个新理念、新产业和新领域层出不穷的时代
。但是, 你只有系统地学习和不断总结,才能学会如何认清并充分利用这些新机遇
。
Be First to Comment