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

来自:量化小白上分记(微信号:quanthzp),作者:量化小白H

01

说明


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


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


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


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

《国泰君安-风格投资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模型,代码如下

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 xx + 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

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。

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 xx + 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


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


06

参考文献


1.安信证券-四维视角下的大小盘风格轮动-因子法

2.国泰君安-风格投资IV:A股大小盘风格轮动研究-11112

3.20161202-申万宏源-申万宏源兼谈FOF构建中的市场风格识别:解密大小盘风格轮动之logistic模型

推荐↓↓↓
人工智能与大数据
上一篇:我们该怎么玩数据 下一篇:给力!数据分析岗位内部人的建议,可以少走很多弯路