大数跨境
0
0

【爬虫】python构建本地量化选股系统(三)——组合构建与回测

【爬虫】python构建本地量化选股系统(三)——组合构建与回测 Paper数据分析
2022-10-05
2
导读:爬取服务介绍 本号推出数据爬虫服务,客户可将需要爬取的网址,字段,具体需求等信息发送给下方客服,并进行定

爬取服务介绍

   本号推出数据爬虫服务,客户可将需要爬取的网址,字段,具体需求等信息发送给下方客服,并进行定制化爬取服务,具体收费标准根据难度商议协定。

如需定制,请添加客服1微信

   


本文介绍最后一步,根据筛选出的因子构建投资组合并进行回测。

这里主要使用打分法构建投资组合,即把选取的因子按照大小排序对个股进行打分。对于因子对收益率有正向作用的因子按照个股因子暴露度进行降序排序,并对排第一的股票打264分,排第二的股票打分263分,.....排第263的股票打1分;对于因子对收益率有负向作用的因子按照个股因子暴露度进行升序排序,并对排第一的股票打264分,排第二的股票打分263分,.....排第263的股票打1分。

最后,将各个股票在各个因子上的得分进行加总,即可选出总分前几位的股票进行持有。我这里每个月进行股票池更新(也可更改持仓周期),即每个月最后一个交易日对全部个股进行打分,并且选择总分排名前10的股票在下个月持有,以此类推。

在对各个因子的得分进行加总时,有各种不同的方法,如等权法是将各个因子的得分等权相加获得总分;IC均值法是按照不同因子IC值的大小对各个因子得分赋权并进行分数加权得到总分;IC_IR均值法是按照不同因子IR值的大小对各个因子得分赋权并进行分数加权得到总分。

废话不多说,上代码(只分享了部分代码),

1、首先是读取我之前存储在本地的总表,没有读之前文章的读者可以简单的把这张表看做涵盖指定行业全部股票在指定回测周期内全部基础指标和衍生指标数据的一张总表,这张表很大吗?没错,348MB。

df = pd.read_csv('E:/医药制造/all_data.csv', low_memory=False)

2、然后定义初始资金100万,以及根据经过复权的收盘价计算收益率。这里为什么定义两个列表储存初始资金呢?因为在回测期中需要每个月计算资金情况并添加进列表,并且两个列表分别储存投资组合的资金变化情况和基准组合的资金变化情况。(将平均持有该行业所有股票的组合作为基准组合)

cash = [1000000]
cash1 = [1000000]
def get_month_return(df):
return (df['收盘价_复权'].iloc[-1]-df['收盘价_复权'].iloc[0])/df['收盘价_复权'].iloc[0]

3、在循环中写入回测期,我这里的回测期间为2017年-2020年共48个月,由于每个月固定持有总分排序前10的股票,所以没有考虑交易成本的问题,

for year in range(2017,2021):                 #回测使用2017-2020
for month in range(1,13):
<按月进行股票池更新和资金变动情况更新>

4、在每个截面期,选取前文通过测试的因子,以及下一期收益率,构成回测表df_test

df_test = df_month[['股票代码','净资产收益率加权(%)','基本每股收益','流通市值','成交量','换手率_y','收益率','收盘价_复权']]

5、对不同因子对各个股票进行排序,这里分别举一个正向排序的因子“净资产收益率”和一个负向排序的因子“成交量”为例,

df_test = df_test.sort_values(by = '净资产收益率加权(%)',ascending = True).reset_index()
score_roe = []
for i in range(1,len(df_test['净资产收益率加权(%)'])+1):
score_roe.append(i)
df_test['净资产收益率得分'] = score_roe


df_test = df_test.sort_values(by = '成交量',ascending = False)
score_vol = []
for i in range(1,len(df_test['成交量'])+1):
score_vol.append(i)
df_test['成交量得分'] = score_vol

6、按照IC_IR加权法对各个因子的得分进行加总,并选取总分前10的股票作为股票池

df_test['总分'] = 0.176226928*df_test['净资产收益率得分']+0.205027372*df_test['基本每股收益得分']+0.111404009*df_test['流通市值得分']+0.234245808*df_test['成交量得分']+0.273095882*df_test['换手率得分']
stock = df_test.sort_values(by = '总分',ascending = False).head(10).reset_index()

7、分别计算上个月所选择的股票池在本月的收益情况,并更新资金总量。这里简化处理,即将资金总量平均分配在10支股票上

new =cash[-1]
for i in range(len(stock['收益率'])):
new += cash[-1]*(1/len(stock['收益率']))*stock['收益率'][i]
cash.append(new)

8、计算基准组合的资金变化情况

ave = cash1[-1]
for i in range(len( df_test['收益率'])):
ave += cash[-1]*(1/len( df_test['收益率']))* df_test['收益率'][i]
cash1.append(ave)

9、将组合资金曲线和基准资金曲线进行存储

final = pd.DataFrame(columns = ['组合资金净值','基准资金净值'])
final ['组合资金净值']=cash
final ['基准资金净值']=cash1

因为总表已经完成了大部分的计算,所以上面这9步完成起来还是很快的,只用了5.56秒。

10 、打开存在本地的资金曲线,根据资金情况添加收益率列,并画出资金变动图(这一步可以在python直接实现,我这里用的excel,请不要嘲笑我)

11、算一下投资组合的最大回撤,28%,对于一个粗略的框架而言,还算说得过去。

总结一下,这个本地的量化回测系统总算一步一步实现,虽然比较粗糙,没有考虑交易中的许多限制和交易成本,不过作为一个验证因子有效性的初步框架应该是足够了。当然,目前的回测和持仓频率是一个月,并且对于日度行情数据只是做了简单的月度平均和月度标准差计算,其中能够构造的衍生指标应该还有许多,并且将持仓周期由月改为灵活择时,应该可以对上面图中这种3年不开张,开张吃3年的局面有所改进。


如有以下需求请直接点击红字链接
数据资源
学术指导
数据众筹
Paper

Paper



资源获取方式

加客服1

更多资源,点击下方阅读原文

【声明】内容源于网络
0
0
Paper数据分析
资源分享、科研辅导、数据分析等干货基地
内容 136
粉丝 0
Paper数据分析 资源分享、科研辅导、数据分析等干货基地
总阅读0
粉丝0
内容136