1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > 基于百度指数的股票收益率多因子模型研究

基于百度指数的股票收益率多因子模型研究

时间:2023-01-17 17:17:36

相关推荐

基于百度指数的股票收益率多因子模型研究

基于百度指数的股票收益率多因子模型研究

导语数据获取基于qdata获取百度指数基于efiance获取股票数据数据集合并运行数据获取数据处理可视化分析各百度指数间相关性分析话题热度时间及股票收益率总览话题热度分布相关话题热度与股票股价及收益率的关系图多因子模型的搭建CAPM多因子策略

导语

个人投资者购买股票的决策过程大致如下所示

考虑这样一个用户场景:在一个平平无奇的交易日上午,个人投资者习惯性地①打开了某理财APP(同花顺、东方财富、雪球股票等)查看自选股票的涨跌及股价、行业板块涨跌及个股龙虎榜等,看得差不多就去资讯板块查看头条快讯、文章推荐等,看到感兴趣的就会②点击进去浏览,在浏览上面这些信息之后看上某一支股票就会③在搜索栏寻找这只股票,并点击查看相关的具体信息(相关的动态资讯、盘口、研究报告等),然后可能还会在许多资讯类APP(微博、百度、今日头条等)⑦搜索关于该个股的相关话题、相关行业的讯息,最后可能④做出了购买决策。

这时,整个决策过程的路径便是①②③(⑦)④

考虑另一个用户场景:个人投资者在忙碌了一天后回到家中刷起了快手抖音(资讯娱乐类APP),APP上⑤推送了财经类博主的个股或公司解读视频,⑥他很感兴趣所以不知不觉地把视频看完了,翻阅了些视频评论之后在该APP或其他资讯类APP中⑦搜索关于该个股的话题、相关行业的讯息,又或者会③打开理财类APP搜索该个股或相关板块的具体信息,并想着明天开盘就买入。

这时,整个决策过程的路径便是⑤⑥(③)(⑦)④

可以看出来,⑦在资讯类APP上搜索这个行为始终不是用户购买个股这个行为的必经之路,但是由于⑦是一个主动搜索的行为,往往能代表着用户对这类话题或者相关个股的强烈兴趣。而在如今的自媒体时代,种草经济、内容输出的现象盛行,个人投资者都会想要在自己做出购买决策判断前去看看别人的看法和观点,所以⑦这个位置对于个人投资者来说还是很重要的。何况⑦处于用户决策漏斗通往购买决策的最后一道关口,理论上讲转化率会较高,所以如果能够量化⑦的一个搜索量,也算约等于知道有多少用户处于④的购买决策中。

而根据流动性溢价原理,当越来越多人关注到或者想得到某一支个股的时候,即个股的流动性增加甚至膨胀的时候,股价便会一定程度地超过它应有的价值,导致错误定价,即溢价。这时,该个股的短期便会产生超额收益率。当然,个股的长期收益率还是会趋近于他的真实价值,毕竟“市场短期是投票器,长期是称重器“。

所幸有一种方式可以量化⑦搜索量,这就是通过百度指数表示⑦的量化指标,然后探究相关话题搜索量与个股的短期收益率之间的关系来验证以上的论述并期望将相关话题的搜索量可以加入量化投资多因子模型中去,增加量化投资的收益。

#导入第三方包from qdata.baidu_index import get_search_index from mon import split_keywordsfrom datetime import datetime, timedeltaimport timeimport pandas as pdfrom datetime import datetime, timedeltaimport efinance as ef

数据获取

基于qdata获取百度指数

def baidu_index(keywords_list,cookies,start_date,day_diff):#获取百度指数的第三方包原地址:/longxiaofei/spider-BaiduIndexdf_index=pd.DataFrame()keywords_list = keywords_listcookies = cookiesstart_date= start_dateday_diff=day_diff#统一日期格式的输入以便后续获取相同时间段的股票数据start_date_tuple=datetime.strptime(start_date,'%Y-%m-%d')end_date_tuple=start_date_tuple+timedelta(days=day_diff)end_date=end_date_tuple.strftime('%Y-%m-%d')i=0 #控制只保留一列日期数据date_list=[]for keywords in split_keywords(keywords_list):for single_keyword in keywords:print(single_keyword)time.sleep(15)index_list=[]try:for index in get_search_index(keywords_list=[single_keyword],start_date=start_date,end_date=end_date,cookies=cookies):index_list.append(index['index'])date_list.append(index['date'])i+=1if i ==1:df_index['date']=date_listdf_index[index['keyword'][0]]=index_listexcept Exception as e:passdf_index=df_index.head(int(len(df_index)/3)) #亲测qdata获取的百度指数在300条以内的时候是会重复提取3次的,且大于300条时数据会混乱return df_index

基于efiance获取股票数据

def stock_data(stock_code,start_date,day_diff):#获取股票数据第三方包原地址:/Micro-sheep/efinancestock_code = stock_codestart_date= start_dateday_diff=day_diffstart_date_tuple=datetime.strptime(start_date,'%Y-%m-%d')end_date_tuple=start_date_tuple+timedelta(days=day_diff)start_day= start_date_tuple.strftime('%Y%m%d')end_day= end_date_tuple.strftime('%Y%m%d')df_stock = ef.stock.get_quote_history(stock_code, beg=start_day, end=end_day)df_stock=df_stock[['日期','收盘']]df_stock.columns=['date','close']df_sh = ef.stock.get_quote_history('上证指数', beg=start_day, end=end_day)df_sh=df_sh[['日期','收盘']]df_sh.columns=['date','sh']df_stock=pd.merge(df_stock,df_sh)return df_stock

数据集合并

def initial_data(df_stock,df_index):#合并百度指数和股票指数的数据集df_backup=pd.merge(df_stock,df_index,on='date',how='right')df_backup.fillna(method='ffill',inplace=True)df_backup['date']=pd.to_datetime(df_backup['date'],format='%Y-%m-%d')for i in range(3,len(df_backup.columns)):df_backup.iloc[:,i]=df_backup.iloc[:,i].astype('int')return df_backup

运行数据获取

keywords_list=[['中兴通讯'],['zte'],['5G'],['边缘计算'],['物联网'],['新能源汽车'],['自动驾驶'],['车联网'],['ICT'],['数字经济'],['通讯行业'],['智慧城市'],['人工智能'],['网络安全']]cookies = """BIDUPSID=187E54B46AD95D7D0C6CA7C17A441A00; PSTM=1652806892; BDORZ=B490B5EBF6F3CD402E515D22BCDA1598; BAIDUID=8769DC8382346675420D39751AB8C7F4:FG=1; Hm_lvt_d101ea4d2a5c67dab98251f0b5de24dc=1654905894; delPer=0; PSINO=6; ZFY=MwsVhdDRPk111Nng:AhOi4P1nZQRrR1Mc6azfnAjjqKo:C; BAIDUID_BFESS=8769DC8382346675420D39751AB8C7F4:FG=1; BDRCVFR[feWj1Vr5u3D]=I67x6TjHwwYf0; BA_HECTOR=210k2ha4252ha00h8g1hahv6d15; H_PS_PSSID=36426_36559_36624_36592_36455_31253_36511_36452_36420_36166_36520_26350_36469_36314; BCLID=7189016615800227754; BDSFRCVID=iNPOJexroG0leprDmD978gjVjopWxY5TDYrELPfiaimDVu-VJeC6EG0Pts1-dEu-EHtdogKK3gOTH4AF_2uxOjjg8UtVJeC6EG0Ptf8g0M5; H_BDCLCKID_SF=tR30WJbHMTrDHJTg5DTjhPrMLN3dWMT-MTryKKJs54JKshOnBn7b-q4vXp5jLbvkJGnRh4oNBUJtjJjYhfO45DuZyxomtfQxtNRJQKDE5p5hKq5S5-OobUPUjfc9LUkqW2cdot5yBbc8eIna5hjkbfJBQttjQn3hfIkj2CKLtCvEDRbN2KTD-tFO5eT22-usMeQR2hcHMPoosIJ1bJ3KQ5K8b4vf5lRRB5rj--nwJxbUotoHXh3tMt_thtOp-CrpWDTm_q5TtUJMqIDzbMohqfLn5MOyKMniJCj9-pPKWhQrh459XP68bTkA5bjZKxtq3mkjbPbDfn028DKuDjREh40822Ta54cbb4o2WbCQfnkV8pcN2b5oQT8jbq3H0T57JGQf3x7gB-o2SPnXjqOUWJDkXb3ha4o0amnpL66CWJ5TMl5jDh3MKToDb-otexQ7bIny0hvcJR6cShPCyUjrDRLbXU6BK5vPbNcZ0l8K3l02V-bIe-t2XjQhDHR02t3-MPoa3RTeb6rjDnCry-5UXUI82h5y05OQ56RHKIQh556bHf7eXn523nk4jJORXRj4BNRhBRjValb4fj6Ky4oTjxL1Db3Jb5_L5gTtsl5dbnboepvojtcc3MvByPjdJJQOBKQB0KnGbUQkeq8CQft20b0EeMtjW6LEtR30WJbHMTrDHJTg5DTjhPrMMtTTWMT-MTryKKJs54JKsb6eejtWbPIZMxnjLbvkJGnRh4oNBUJtjJjYhfO45DuZyxomtfQxtNRJQKDE5p5hKq5S5-OobUPUDUJ9LUkJ0mcdot5yBbc8eIna5hjkbfJBQttjQn3hfIkj2CKLK-oj-D8Ge5u53e; BCLID_BFESS=7189016615800227754; BDSFRCVID_BFESS=iNPOJexroG0leprDmD978gjVjopWxY5TDYrELPfiaimDVu-VJeC6EG0Pts1-dEu-EHtdogKK3gOTH4AF_2uxOjjg8UtVJeC6EG0Ptf8g0M5; H_BDCLCKID_SF_BFESS=tR30WJbHMTrDHJTg5DTjhPrMLN3dWMT-MTryKKJs54JKshOnBn7b-q4vXp5jLbvkJGnRh4oNBUJtjJjYhfO45DuZyxomtfQxtNRJQKDE5p5hKq5S5-OobUPUjfc9LUkqW2cdot5yBbc8eIna5hjkbfJBQttjQn3hfIkj2CKLtCvEDRbN2KTD-tFO5eT22-usMeQR2hcHMPoosIJ1bJ3KQ5K8b4vf5lRRB5rj--nwJxbUotoHXh3tMt_thtOp-CrpWDTm_q5TtUJMqIDzbMohqfLn5MOyKMniJCj9-pPKWhQrh459XP68bTkA5bjZKxtq3mkjbPbDfn028DKuDjREh40822Ta54cbb4o2WbCQfnkV8pcN2b5oQT8jbq3H0T57JGQf3x7gB-o2SPnXjqOUWJDkXb3ha4o0amnpL66CWJ5TMl5jDh3MKToDb-otexQ7bIny0hvcJR6cShPCyUjrDRLbXU6BK5vPbNcZ0l8K3l02V-bIe-t2XjQhDHR02t3-MPoa3RTeb6rjDnCry-5UXUI82h5y05OQ56RHKIQh556bHf7eXn523nk4jJORXRj4BNRhBRjValb4fj6Ky4oTjxL1Db3Jb5_L5gTtsl5dbnboepvojtcc3MvByPjdJJQOBKQB0KnGbUQkeq8CQft20b0EeMtjW6LEtR30WJbHMTrDHJTg5DTjhPrMMtTTWMT-MTryKKJs54JKsb6eejtWbPIZMxnjLbvkJGnRh4oNBUJtjJjYhfO45DuZyxomtfQxtNRJQKDE5p5hKq5S5-OobUPUDUJ9LUkJ0mcdot5yBbc8eIna5hjkbfJBQttjQn3hfIkj2CKLK-oj-D8Ge5u53e; BDUSS=3Q0fndZYmhwTUx1clRIakN3MGFQZ1dvdVFoTVRYYXZodjd5aGNTY3QxWXdqdEJpSVFBQUFBJCQAAAAAAAAAAAEAAACFwjdLanVubmp1bm5iaGFwcHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADABqWIwAalia; SIGNIN_UC=70a2711cf1d3d9b1a82d2f87d633bd8a04052555077nxoxWNVqgLJ6Xa0qo%2F6rmA4PAvmTQkcjbUJg35LkCEWutkQ74GGWD038uzCXIfqCas7eHeIAN%2Bv%2BPVN55Wx8xvWfWFiBOEYRPMOwl2abJVMRF4lMo2oHx8ECV4qxoJ93XMBJGtQgEdvUET6q5H0buMrQaULeAQp%2Bi2oLaW2E8gr3boMVotEfJngpS98GYj8ICGLjCD0NYN%2FVOrtGOeaTXpNqMdMUX1AODWyflIby6TyoMXhFGZ82ofRnZgpXpl05YLqOoCgJXa4yYhzwzknhZGMhtWbqPQPNlUdAbZQwpm4%3D96416976362718933879039618364210; __cas__rn__=405255507; __cas__st__212=f7adc00a94a71e45793164597a0f3e17f64a496e22409f08bb0a3d40204c45fa694168b8a1de0d302a1a387f; __cas__id__212=40859543; CPID_212=40859543; CPTK_212=30581114; Hm_up_d101ea4d2a5c67dab98251f0b5de24dc=%7B%22uid_%22%3A%7B%22value%22%3A%221261945477%22%2C%22scope%22%3A1%7D%7D; bdindexid=kpp4j4d1kq6vuhqu55f1n3dkl5; Hm_lpvt_d101ea4d2a5c67dab98251f0b5de24dc=1655243068; ab_sr=1.0.1_ZThlZmY5MWJjZDcyMDk0ZGY4NTY5OTM5ZGNkMjkzOWY3MDZkYzE0NTY0MWIwYWRjZDFhMjAwMzM5ZTA3MzlhOTA5MjAxMjc5M2ZmMDIzNTUyOTNmZWY1MzRjMjIxMzJlMWM5ZGYzN2YxMmMxNmRhNTQ1MTEwMDEwNTc2YzA2ZGEyYTBjN2JkYjcwZjg1MmFhMGRjMDU4NjYxMDMwMTQ3NQ==; BDUSS_BFESS=3Q0fndZYmhwTUx1clRIakN3MGFQZ1dvdVFoTVRYYXZodjd5aGNTY3QxWXdqdEJpSVFBQUFBJCQAAAAAAAAAAAEAAACFwjdLanVubmp1bm5iaGFwcHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADABqWIwAalia; RT="z=1&dm=&si=j93mjd353ci&ss=l4eowfjs&sl=f&tt=10hw&bcn=https%3A%2F%%2Flog%2Fweirwood%3Ftype%3Dperf&ld=34nb&ul=3ppr"""start_date= '-01-02'day_diff=300 #获取百度指数的总天数。注意:亲测qdata获取的百度指数在300条以内的时候是会重复提取3次的,且大于300条时数据较乱,所以尽量控制day_diff<=300stock='中兴通讯'Rf_year=0.04 #无风险年化利率diff_num=3 #几日收益率threshold=1.2df_index=baidu_index(keywords_list,cookies,start_date,day_diff)df_stock=stock_data(stock,start_date,day_diff)df_backup=initial_data(df_stock,df_index)df_backup

数据处理

百度指数的官方定义是:以网民在百度的搜索量为数据基础,以关键词为统计对象,科学分析并计算出各个关键词在百度网页搜索中搜索频次的加权。

所以每个关键词之间都可能有数量级的差异,这会一定程度上夸大数量级大的关键词的作用且忽略数量级小的关键词。在实际场景中,某一关键词的百度指数的变化或者说异常高的点比它的绝对值更具有参考价值,因为互联网用户对关键词搜索关注程度的突发性爆发会更能代表某一股票的流动性爆发从而造成市场的错误定价。所以要先以百度指数为基础新设立一个新的指标–话题指数change_index来量化当天的一个关键词的百度指数偏离了多少该关键词平均的百度指数。

1.先用pairplot函数查看百度指数的数值分布。

sns.pairplot(df_backup)

2.如图上所示,百度指数的数值分布近似于正态分布,这时异常值检测最基础的方法就是标记出与平均值偏差k倍sigma(标准差)的数值,但由于这种异常值检测是相对于一整个时间段而言的,检测出来的异常值始终是大于某一特定数值,这时互联网用户对关键词的爆发就相对于一个较长的时间段而言了。而一种更进阶的做法是,设定一个时长为5天的时间窗口,标记出与前5天平均值偏差k倍sigma的数值作为异常值,就能不仅能标记出绝对峰值,也能标记出百度指数的绝对峰值了。

#探究移动sigma与整体sigma方法标记异常值(被关注的话题)的效果对比topic=df_comb.columns[4]sigma=(df_comb[topic]-df_comb[topic].mean())/df_comb[topic].std()df_rolling_method=df_comb[df_comb['change_'+topic]>=threshold]df_total_method=df_comb[sigma>=threshold]fig, (ax1,ax2)=plt.subplots(2,sharex=True)ax1.plot(df_comb['date'],df_comb[topic],linestyle='--',color='tab:purple')ax1.plot(df_rolling_method['date'],df_rolling_method[topic],'ro',markersize=2)ax1.set_ylabel('rolling method')ax2.plot(df_comb['date'],df_comb[topic],linestyle='--',color='tab:purple')ax2.plot(df_total_method['date'],df_total_method[topic],'ro',markersize=2)ax2.set_ylabel('total method')#优化日期格式locator = mdates.AutoDateLocator(minticks=10, maxticks=15)formatter = mdates.ConciseDateFormatter(locator)ax1.xaxis.set_major_locator(locator)ax1.xaxis.set_major_formatter(formatter)ax1.xaxis.set_minor_locator(mdates.MonthLocator())fig.savefig('image/相对峰值与绝对峰值.jpg',dpi=500)

3.将话题指数change_index(k)<threshold值的重新赋值为0,表示该关键词百度指数无明显爆发,change_index(k)>threshold值保持不变表示该关键词百度指数爆发了且当日增长了k倍的5日标准差。

4.分别计算上证指数和选定股票的短期收益率

def stock_topic(df):for col in range(3,len(df.columns)):single_col = df.iloc[:,col]moving_avg = single_col.rolling(window=5).mean(center=True) #计算各话题指数的5日移动平均值moving_std = single_col.rolling(window=5).std(center=True) ##计算各话题指数的5日移动标准差值col_name='initial_change_'+df.columns[col]df[col_name]=(single_col-moving_avg)/moving_std col2_name='change_'+df.columns[col]df[col2_name]=df.apply(lambda x:x[col_name] if x[col_name]>=threshold else 0 ,axis=1) #将超过平均值的threshold倍标准差的数值保留,并将没超过的设为0df.fillna(0,inplace=True)df_comb=df.reset_index(drop=True)Rf=(1+Rf_year)**(1/365)-1 #计算无风险日利率df_comb['sh_ret']=(df_comb['sh']/(df_comb['sh']-df_comb['sh'].diff(diff_num))-1-Rf)*100 #计算上证指数的diff_num日收益率百分比数df_comb['close_ret']=(df_comb['close']/(df_comb['close']-df_comb['close'].diff(diff_num))-1-Rf)*100 #计算要研究的股票的diff_num日收益率百分比数df_comb.dropna(inplace=True)df_comb.reset_index(drop=True,inplace=True)return df_combpd.options.display.encoding = 'GBK'df=df_backup.copy()df_comb=stock_topic(df)df_comb

可视化分析

各百度指数间相关性分析

df=df_backup.copy()df_corr = df.corr(method='pearson')cmap = sns.diverging_palette(220, 10, as_cmap=True)fig, ax = plt.subplots(figsize=(10,10))pd.options.display.encoding = 'GBK'sns.heatmap(df_corr, cmap=cmap, vmax=1.0, center=0, fmt='.2f',square=True, linewidths=.5, annot=True, cbar_kws={"shrink": .75})ax.set_title('各特征的皮尔逊系数')plt.savefig('image/各特征的皮尔逊系数.jpg',dpi=300)plt.show()

皮尔逊系数-Pearson代表着两两特征的相关系数,趋近于-1表示线性负相关,趋近于0表示线性不相关,趋近于1表示线性正相关。如图上所示,大部分特征相关性较低,表示后面训练出来的多因子模型不太会受到多重共线性的影响。

话题热度时间及股票收益率总览

import matplotlib.pyplot as pltimport seaborn as snsx_columns_list=[]x_columns_list.append('date')for i in range(3,len(df_backup.columns)):x_columns_list.append('change_'+df_backup.columns[i])df_map=df_comb[x_columns_list]df_map.set_index('date',inplace=True)df_map.Tstock='sh'df_hot=df_comb[df_comb['change_'+topic]>=threshold]cmap = sns.diverging_palette(220, 10, as_cmap=True)fig, (ax1,ax2) = plt.subplots(2,figsize=(10,10))sns.heatmap(df_map.T, cmap=cmap, vmax=1.0, center=0, fmt='.2f',ax=ax1,cbar=False,square=False, linewidths=.5, annot=False, cbar_kws={"shrink": .75},xticklabels=False,yticklabels=True)ax1.set_ylabel('话题热度时间表')ax2.plot(df_comb['date'],df_comb['close_ret'],label=stock+'_stock')ax2.set_ylabel('股票收益率')plt.savefig('image/话题热度时间及股票收益率总览.jpg',dpi=300)plt.show()

话题热度分布

df_index_change=df_comb[x_columns_list]df_index_change=df_index_change.iloc[:,1:]empty_num_list=[]specific_num_list=[]for col in df_index_change.columns:empty_num_list.append(sum(df_index_change[col]==0))specific_num_list.append(sum(df_index_change[col]!=0))N = len(empty_num_list)ind = np.arange(N) # the x locations for the groupswidth = 0.35 # the width of the bars: can also be len(x) sequencefig, ax = plt.subplots()p1 = ax.bar(ind, empty_num_list, width, label='话题未被关注的天数')p2 = ax.bar(ind, specific_num_list, width,bottom=empty_num_list,label='话题被关注的天数')ax.axhline(0, color='grey', linewidth=0.8)ax.set_title('话题热度分布')ax.set_xticks(ind, labels=df_index_change.columns)ax.legend()ax.bar_label(p1, label_type='center')ax.bar_label(p2, label_type='center')plt.setp(ax.get_xticklabels(), rotation=90, horizontalalignment='right')plt.legend(loc='lower left')plt.savefig('image/话题热度分布.jpg',dpi=300)plt.show()

在样本量为300天的数据集中,各话题百度指数爆发的天数大约为总样本的10%-20%, 存在真实样本数不足的隐患,后续可以增加样本量的提取以解决此问题。

相关话题热度与股票股价及收益率的关系图

for i in range(3,len(df_backup.columns)):topic=df_backup.columns[i]df_hot=df_comb[df_comb['change_'+topic]>threshold]fig, (ax1,ax2,ax3)=plt.subplots(3,sharex=True)ax1.plot(df_comb['date'],df_comb[topic],linestyle='--',color='tab:purple',label=topic)ax1.plot(df_hot['date'],df_hot[topic],'ro',markersize=2)ax1.set_ylabel(topic+'_index')ax2.plot(df_comb['date'],df_comb['close'],label=stock+'_stock_price')ax2.plot(df_hot['date'],df_hot['close'],'ro',markersize=2)ax2.set_ylabel(stock+'_stock_price')ax3.plot(df_comb['date'],df_comb['close_ret'],linestyle='--',label=stock+'_stock_ret')ax3.plot(df_hot['date'],df_hot['close_ret'],'ro',markersize=2)ax3.set_ylabel(stock+'_stock_ret')locator = mdates.AutoDateLocator(minticks=10, maxticks=15)formatter = mdates.ConciseDateFormatter(locator)ax1.xaxis.set_major_locator(locator)ax1.xaxis.set_major_formatter(formatter)ax1.xaxis.set_minor_locator(mdates.MonthLocator())ax1.set(title='相关话题热度与股票股价及收益率的关系图')fig.legend(prop={'size':8})fig.savefig('image/'+topic+'_'+stock+'.jpg', dpi=500)

部分生成的图如下所示

可见,单一的相关话题热度峰值与股票收益率之间没有明显的关系。

多因子模型的搭建

说到多因子模型就很难能绕开CAPM(资产定价模型)来搭建,这是因为个股往往会一定程度的跟随大盘的走势波动。

CAPM

美国学者夏普、林特尔、特里诺和莫辛等人于1964年在资产组合理论的基础上发展出来了一个资本资产定价模型(简称CAPM模型)。这个模型根据股票本身的风险和市场风险的相关性估算出单个股票的期望收益率。

在公开市场中,越高的收益率往往伴随着越高的风险,这时因为高收益率低风险的资产进入公开市场后势必很快由于大家争相购买而抬高到应有的价格区间中,从而变成低收益低风险的资产,反之亦然。所以现在市场可自由交易的资产中,资产的预期收益率和波动等同于资产的风险。

而资产的收益率和波动很大程度上被系统性风险所影响,其中系统性风险即市场风险-- 通常由大盘指数的波动率来衡量(波动即风险)。这种关系通常被写成

ri=单个股票的风险(预期收益率)

rf=无风险收益率

rM=大盘期望的收益率

βi即为市场因子

import statsmodels.api as sm def capm():X=df_comb['sh_ret']y=df_comb['close_ret']x=sm.add_constant(X)md_capm=sm.OLS(y,x) result=md_capm.fit() return resultcapm().summary()

如上图所示,以市场因子作为唯一影响因子预测股票的收益率的结果为Adj.R-squared=0.384,sh_ret=1.38。该结果表示大盘收益率每上涨1%,中兴通讯的收益率会上涨1.38%,且中兴通讯的波动的38.4%可以用大盘的波动解释,即如果中兴通讯上涨了10%,这10%中有3.84%是由于大盘收益率的上涨。

多因子策略

CAPM首先就假设了市场风险是唯一风险因子。但在现实中,仅仅由市场风险是不足以解释资产回报的,因此,人们对CAPM做了改进,认为资产的收益率中的一部分是资产内秉特性,记为αi,那么有

其中,αi可以是成长类因子、估值类因子、现金流类因子、经营效率类因子、财务质量类因子等,而在本文中αi是话题指数因子。

def multi_factor():x_columns_list=[]for i in range(3,len(df_backup.columns)):x_columns_list.append('change_'+df_backup.columns[i])x_columns_list.append('sh_ret')X=df_comb[x_columns_list]y=df_comb['close_ret']x=sm.add_constant(X)md_capm=sm.OLS(y,x) result=md_capm.fit() return resultmulti_factor().summary()

如上图所示,整体效果而言Adj.R-squared=0.384。该结果表示中兴通讯的波动的39%可以用大盘+相关关键词的百度指数的波动解释,总体增加了0.5%的可解释性。

result=multi_factor(Rf_year)x_columns_list=[]for i in range(3,len(df_backup.columns)):x_columns_list.append('change_'+df_backup.columns[i])x_columns_list.append('sh_ret')X=df_comb[x_columns_list]y=df_comb['close_ret']x=sm.add_constant(X)df_comb['close_ret_pred']=result.predict(x)fig, ax1=plt.subplots()ax1.plot(df_comb['date'],df_comb['close_ret'],linestyle='--',color='tab:purple',label='实际收益率')ax2 = ax1.twinx()ax2.plot(df_comb['date'],df_comb['close_ret_pred'],label='预测收益率')locator = mdates.AutoDateLocator(minticks=10, maxticks=15)formatter = mdates.ConciseDateFormatter(locator)ax1.xaxis.set_major_locator(locator)ax1.xaxis.set_major_formatter(formatter)ax1.xaxis.set_minor_locator(mdates.MonthLocator())ax1.set(title='股票收益率拟合')fig.legend(loc='upper right')plt.savefig('image/股票收益率拟合.jpg',dpi=300)fig.show()

fig = plt.figure(figsize=(15,8))fig = sm.graphics.plot_regress_exog(result,"sh_ret", fig =fig)plt.savefig('image/拟合结果分析.jpg',dpi=300)

# 回归系数表汇总提取coef_df = pd.DataFrame({"params": result.params, # 回归系数"std err": result.bse,# 回归系数标准差"t": round(result.tvalues,3), # 回归系数T值"p-values": round(result.pvalues,3) # 回归系数P值})coef_df[['coef_0.025','coef_0.975']] = result.conf_int() # 回归系数置信区间 默认5%,括号中可填具体数字 比如0.05, 0.1coef_df.sort_values('p-values',inplace=True)import numpy as npdf_draw=coef_df.Tdf_box=df_draw.loc[['params','coef_0.025','coef_0.975'],:]fig, (ax1,ax2)=plt.subplots(2)ax1.violinplot(df_box,showmeans=False,showmedians=True)ax1.xaxis.set_ticklabels([])ax1.set_ylabel('coef')ax1.set_title('线性模型拟合结果')bar=ax2.bar(coef_df.index,coef_df['p-values'],width=0.5)ax2.bar_label(bar,padding=3,size=7)ax2.set_ylabel('p-value')ax2.set_xlabel('feature')plt.setp(ax2.get_xticklabels(), rotation=90, horizontalalignment='right')plt.savefig('image/线性模型拟合结果特征分析.jpg',dpi=300)plt.show()

如图上所示,上证指数、车联网、物联网的p-value分别为0、0.074、0.092,这表示当置信度=0.11时,我们有充分理由相信上证指数的短期收益率、“车联网”的百度指数、“物联网”的百度指数可以一定程度地估算出‘中兴通讯’的收益率约等于1.3568上证指数的短期收益率+0.9044

“车联网”的百度指数+0.9411*“物联网”的百度指数。即当互联网用户对车联网或物联网的关注度爆发的那一天,‘中兴通讯’的股价预计获得约为1%的超额收益α。

所以,我们可以将置信度高的相关关键词的百度指数作为选择特定股票的因子作为多因子模型的部分加入到交易策略模型中去。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。