量化学交易习笔记#寻找稳定收益的股票,可能吗?
本文目的:寻找近年来稳定收益的股票
利用python,通过数据分析,进行的一次小型课题研究。会涉及之前文章里邢老师教的回测框架模块。具体相关邢老师的文章,可以看《Python量化入门》的课程,我的相关笔记传送门:
量化交易学习笔记#Python量化入门课程(第零课)零基础的预备课
最近有个刚开始学习研究股票的朋友问我,有没有什么3-5年来,收益稳定的股票,只要买着不动就可以安心睡觉?
这句话一听,我就笑了。心里想,哥们你来错地方了。天堂(固定收益)在左,地狱(股市)在右。
追求稳定收益就不应该来股市,股权市场天生流通性强,波动性大。单靠个股是很难做到稳定收益的,不然那些金融大咖们,也不需要尝试各种策略,每天做各种研究,使用各种金融衍生品工具了。
但是本着严谨的态度,我觉得还是用该历史数据说话,随手写了个小程序。
运行状态:
20140101-20170930的测试结果:
从上面的结果看,是不是出乎意料的好~!
2014年时有股票2526个,如果在20140101买入并持有的话有2027个股票年化收益率大于了4%,超过了余额宝。
如果我们调整下参数
天哪噜,超过年化10%的股票还有1386只,刚才谁说股票是地狱来着的?
大家快去冲冲冲。。。。客观且慢,如果仅仅因为上面的数据就觉得股权投资好于固定收益类产品,是非常危险的。因为股票有这天然不可避免的风险:
第一点:波动性。 我们引入一个指标max_drawdown,最大回撤,就是买入持有期间,收益最大的回撤幅度。
我们把回撤最小的股票找出来看看
过去3年里回撤最小的股票,也有22%,最大能搞达到90%。当你亏了22%的时候,你真的还能坚持持有吗?有的人说我能。。。毕竟在巨大的收益面前,总是有勇士的。那如果是90%呢?
第二点,买入时间点。看一下,为什么2014年买入的时候,股票收益还是不错的。
看一下上证指数就知道了,2014年的时候是非常接近历史低点的。如果我们把买入时间切换到20150101看看。
居然还有1432个股票跑赢了支付宝。
年化收益超过10%的居然还有868个~whoops
期间最小回撤还是22%
最大回撤90%
好吧,那我们再尝试下从20150512开始,这次就比较惨了
年化收益率大于4%的445个,大于10%的只有251个了。
我们再看下上证最悲惨的3年 20110101-20140101
战胜余额宝的只有410个了,而年化收益率超过10%的只有213个了。
收益率排名靠前的股票:
其中,除了600460华夏幸福,经久不衰。
其他更多的是走出了不同程度的反转
000156 华数传媒
000750 国海证券
600705 中航资本
结论:
1. 可以看出无论何时,只要找到有潜力的股票,总能帮你扛过熊市,获得丰厚的收益,但是找到他们谈何容易。
2. 对于大盘的择时,会提高我们选股的成功率。
3. 历史是否可能重复,更像是薛定谔的猫。
4. 长期持有才是稳定收益的根基。
5. 长期来看,股权投资的收益跑赢固定收益的可能性还是很高的。但是需要你花时间和经历去研究。
实验思路和源代码:
1、获得全量的股票交易数据,如股票代码,名称,高,开,低,收,涨跌幅,交易量等
如果你之前学过邢老师的《Python量化交易入门》系列课程,那你应该已经拿到了一套很完备的A股数据。
如果没有,你也可以通过万得导出数据。
本实验使用过的就是万得数据。
# 从指定文件夹中获取所有股票代码,组成一个list,这里我直接使用了《Python量化交易入门里的框架》stock_list = Functions.get_stock_code_list_in_one_dir_wande()
2、定义一个函数,获取每个股票,在某一段时间内,收益情况分析的表格
获取每个股票,在某一段时间内,收益情况分析的表格
def get_result(start_date='20140101', end_date='20180101', stock_list=[]):
"""
:param start_date: 策略开始日期
:param end_date: 策略结束日期
:param stock_list: 需要模拟的股票列表
:return: 带有股票代码,策略开始时间,策略结束时间,策略期间总收益,策略的年化收益,策略的最大回撤幅度,策略的波动性,策略的sharp比率。
"""
# 定义一张空表,含有需要返回的字段名(列名)
output = pd.DataFrame(columns=['stock_code', 'start_date', 'end_date', 'total_return', 'annual_return', 'max_drawdown', 'volatility', 'sharp_ratio'])
# 利用《Python量化入门》的框架,获取上证指数数据,为了填补非交易日
index_data = Functions.import_index_data_wande()
# 计数器i,初始值为0
i = 0
# 对于在全部股票代码列表里的股票进行遍历
for stock in stock_list:
# 利用《Python量化入门》的框架读取每个股票的数据
df = Functions.import_stock_data_wande(stock)
# 个股数据和指数数据合并,填补非交易日
df = Functions.merge_with_index_data(df, index_data)
# 剔除上市交易日小于3年的(250*3)的,或者起始日期大于最终日期,跳过
if (df.shape[0] < 750) or (df['date'].iloc[0] > pd.to_datetime(end_date)):
continue
# 截取所需要的时间段的股票交易数据
df = df.loc[(df['date'] >= start_date) & (df['date'] <= end_date)]
# 重置index
df.reset_index(drop=True, inplace=True)
# 个股数据的第一天买入
df.loc[0, 'signal'] = 1
# 个股数据的最有一天卖出
df['signal'].iloc[-1] = 0
# 计算仓位
df = equity_cal.position(df)
# 计算资金曲线的简单方法,因为使用buy_hold的策略,交易频率几乎没有,手续费和印花税的交易结果的影响不显著
df = equity_cal.equity_curve_simple(df)
# 输出表格的代码
output.loc[i, 'stock_code'] = stock
# 输出表格的起始日期
output.loc[i, 'start_date'] = start_date
# 输出表格的结束日期
output.loc[i, 'end_date'] = end_date
# 输出表格的期间总收益
output.loc[i, 'total_return'] = df['equity'].iloc[-1] / df['equity'].iloc[0] - 1
# 输出表格的年化收益
output.loc[i, 'annual_return'] = pf_analysis.annual_return(df)
# 输出表格的最大回撤
output.loc[i, 'max_drawdown'] = pf_analysis.max_drawdown(df)[0]
# 输出表格的波动性
output.loc[i, 'volatility'] = pf_analysis.volatility(df)
# 输出表格的夏普比率
output.loc[i, 'sharp_ratio'] = pf_analysis.sharp_ratio(df)
# 计数器+1,下次指向输出表格的下一行
i += 1
# 记录当前的进度
print str(stock) + " is finished, and process is in " + str(stock_list.index(stock)/len(stock_list) * 100.00)
# 将输出表格,保存为output.csv
output.to_csv('D:/all_trading_data/data/output_data/Going_Merry/test_20180103/output.csv', index=False)
# 输出结束
print "finished"
# 返回输出表格
return output
3. 对结果数据进行数据分析,得到全部的股票数据量,收益为正的股票个数,年化收益率大于4%的股票个数
对结果数据进行数据分析,得到全部的股票数据量,收益为正的股票个数,年化收益率大于4%的股票个数
def pf_return(df):
# 根据total_return进行排序
df.sort_values(by='total_return', ascending=False, inplace=True)
# 全部股票数量
print "全部股票数量: " + str(df.shape[0])
# 只选取收益为正的股票
df = df.loc[df['total_return'] > 0 ]
# 重置index
df.reset_index(drop=True, inplace=True)
# 打印结果
print "收益率大于0的股票个数:"+ str(df.shape[0])
df = df.loc[df['annual_return'] > 0.04]
# 重置index
df.reset_index(drop=True, inplace=True)
# 打印结果
print "年化收益率大于4%的股票个数:"+ str(df.shape[0])
# 返回重新排序后的表格
return df
4. 利用上面写好的函数运行
# 获取全部股票数据
stock_list = Functions.get_stock_code_list_in_one_dir_wande()
# 打印结果
print "测试股票数量:" + str(len(stock_list))
# 获得某段时间内所有股票的收益情况
get_result(start_date='20140101', stock_list=stock_list)
可能对于初学者而言,即使有上述源代码,可能还是会觉得较难理解。那么,建议各位想学习python并研究交易的朋友们可以考虑《Python量化入门》课程系列,非常适合零基础的朋友们,获得所有的股票历史数据,并建立自己的交易策略,建议购买课程后深入学习。
课程评价
优点:这套课程特别适合对Python,pandas都没掌握的同学,和“入门”二字很贴切。虽然价要收取一定的费用,但是对于零基础的同学还是墙裂推荐。当然我的笔记是完全免费的,但这个只能作为点心,毕竟正餐才是最有营养的~而且还有大量的源代码A股所有的股票历史交易数据。
缺点:只能用微信访问学习,PC端的话要通过微信客户端访问。
系列总课时约12多个小时,会获得课程讲解的所有源代码。如要深入熟练掌握,课外练习可能需要100小时+。
课程传送门: