前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >研报复制(四):基于Logistic回归的大小盘轮动

研报复制(四):基于Logistic回归的大小盘轮动

作者头像
量化小白
发布2019-08-29 13:21:11
1.4K0
发布2019-08-29 13:21:11
举报
文章被收录于专栏:量化小白上分记

说明

上一篇提到,一般有两种方式构造大小盘轮动策略:

一种是从技术面出发,基于量价指标建立模型,典型的比如上篇复制的基于相对强弱指标的大小盘轮动策略

另一种是从基本面出发,考虑影响股票回报的各项因素,以此为基础构建模型。

本文属于第二种,文章主要参考报告包括:

《国泰君安-风格投资IV:A股大小盘风格轮动研究-11112》、《20161202-申万宏源-申万宏源兼谈FOF构建中的市场风格识别:解密大小盘风格轮动之logistic模型》、《安信证券-四维视角下的大小盘风格轮动-因子法》。

报告、数据和代码后台回复“代码”获取。

02

股价影响因素

[1]中将影响股票回报率的因素分为估值因素、动量因素、货币因素、经济增长因素四大类,我们结合三篇报告,最终使用如下各项因子进行建模:

共计13项指标,数据来自WIND,提取数据代码略。各项因子的分析不再说明,参见报告。

由于数据披露的滞后性,为了防止出现未来信息,回测时对各项因子进行滞后处理。比如滞后两期的意思是,当期为10月时,使用8月份的数据。

各因子相关性如图。

03

基于Logistic回归模型的大小盘轮动

基本面数据与量价数据的最大不同在于,量价因子的及时性高但持续性弱,基本面数据披露有一定滞后性,响应没有量价因子那么迅速强烈,但持续时间较长。因此回测时采用月频调仓

Logistic回归模型的原理不具体说明,python中可以直接通过函数sklearn.LogisticRegression完成。

总体思路为,通过logistic模型预测未来市场是大盘走强还是小盘走强,因变量Y用小盘指数收益率和大盘指数收益率的差值定义,Y = 1 若差值大于0,表明小盘走强;Y = 1 若差值小于0,表明大盘走强。

每一期末,利用历史数据预测下一期Y为0还是1,为1则下一期配置小盘指数,为0则下一期配置大盘指数。

采用这种策略的收益上下界可以预期,分别对应模型预测准确率100%,0%的情况,分别对应图中蓝色橙色曲线。

04

轮动策略1

回测区间:2005年5月-2018年7月

大盘指数:HS300(000300.SH)

小盘指数:ZZ500(000905.SH)

使用所有13个因子作为自变量,建立Logistic模型,代码如下

代码语言:javascript
复制
def backtest(j,datause):
    datause['predict'] = np.nan
    for i in range(5,datause.shape[0]):
        X = datause.iloc[max(0,i - j):i,1:14].values
        Y = datause.iloc[max(0,i - j):i,14].values    
        X_pred = datause.iloc[i,1:14].values.reshape(1, -1)
        clf = LogisticRegression(random_state=0, solver='lbfgs').fit(X, Y)
        datause.loc[i,'predict'] = clf.predict(X_pred)[0]  
    flags = datause[['ym','predict','next_Y']].dropna()
    flags['next_ym'] = flags.ym.apply(lambda x: x + 1 if x%100 < 12 else (x//100 + 1)*100+1)
    result = pd.merge(Indexprice,flags,left_on = 'ym',right_on = 'next_ym')    
    result['net_zz'] = result['ZZ500']/result['ZZ500'][0]
    result['net_hs'] = result['hs300']/result['hs300'][0]
    result['ret_zz'] = result['ZZ500'].pct_change(1).fillna(0)
    result['ret_hs'] = result['hs300'].pct_change(1).fillna(0)
    result['strategy_ret'] = result.ret_zz*(result.predict ==1) + result.ret_hs*(result.predict == 0)
    result['net_strategy'] = (result.strategy_ret + 1).cumprod()

    return result

其中,j为用来训练模型的数据期数。如果每次使用过去所有数据训练模型,结果如下

明显优于大盘指数,但不如小盘指数。

考虑滚动的方式,每次只使用过去j期的数据,我们对j从10-100进行循环计算每个参数下的策略净值和预测准确率,结果如下

j = 20时,预测准确率62.19%,策略净值2.28

代码语言:javascript
复制
result20 = backtest(20,datause)
X = np.arange(result20.shape[0])
xticklabel = result20.stockdate
xticks = np.arange(0,result20.shape[0],np.int((result10.shape[0]+1)/7))

plt.figure(figsize = [20,5])
SP = plt.axes()      
SP.plot(X,result20['net_strategy'],label = 'net_strategy',color = 'deepskyblue',linewidth = 3)  
SP.plot(X,result20['net_zz'],label = 'net_zz',color = 'cornflowerblue',linewidth = 2)   
SP.plot(X,result20['net_hs'],label = 'net_hs',color = 'darkred',linewidth = 2) 


SP.set_xticks(xticks)
SP.set_xticklabels(xticklabel[xticks],size = 20)
plt.legend()
plt.show()

05

轮动策略2

策略2出发点为,不同因素在不同时刻对于股价的影响不尽相同,因此建立Logistic模型时,考虑只使用与当期所用数据中因变量相关性最高(相关系数绝对值最大)的5个因子,其余同策略1。

代码语言:javascript
复制
# j 训练模型使用的数据长度
def backtest2(j,datause):

    datause['predict'] = np.nan
    for i in range(5,datause.shape[0]):
        col = pd.DataFrame(datause[max(0,i - j):i - 1].corr()['Y'][1:14].abs()).sort_values('Y',ascending = False)[:5].index.tolist()
        X = datause.loc[max(0,i - j):i - 1,col].values
        
        Y = datause.loc[max(0,i - j):i - 1,'Y'].values    
        X_pred = datause.loc[i,col].values.reshape(1, -1)
        clf = LogisticRegression(random_state=0, solver='lbfgs').fit(X, Y)
        datause.loc[i ,'predict'] = clf.predict(X_pred)[0]  
    flags = datause[['ym','predict','next_Y']].dropna()
    flags['next_ym'] = flags.ym.apply(lambda x: x + 1 if x%100 < 12 else (x//100 + 1)*100+1)
    result = pd.merge(Indexprice,flags,left_on = 'ym',right_on = 'next_ym')    
    result['net_zz'] = result['ZZ500']/result['ZZ500'][0]
    result['net_hs'] = result['hs300']/result['hs300'][0]
    result['ret_zz'] = result['ZZ500'].pct_change(1).fillna(0)
    result['ret_hs'] = result['hs300'].pct_change(1).fillna(0)
    result['strategy_ret'] = result.ret_zz*(result.predict ==1) + result.ret_hs*(result.predict == 0)
    result['net_strategy'] = (result.strategy_ret + 1).cumprod()

    return result

不同j净值及准确率如下

j = 10时,预测准确率61.4%,策略净值2.38

整体来看,策略效果并不好,练手, 看看就好,欢迎指正!!!

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-12-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 量化小白躺平记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档