量化角度看春节:A股的春节效应
量化投资与机器学习微信公众号,是业内垂直于量化投资、对冲基金、Fintech、人工智能、大数据等领域的主流自媒体。公众号拥有来自公募、私募、券商、期货、银行、保险、高校等行业30W+关注者,曾荣获AMMA优秀品牌力、优秀洞察力大奖,连续4年被腾讯云+社区评选为“年度最佳作者”。
A 股市场在春节期间的表现通常优于平日,存在较为显著的春节效应。大家可以通过阅读下文图表来感受一下 A 股市场的春节效应。
华泰金工研报一般把腊月十八到次年的正月十八作为“农历春节效应月”。
兴业金工研报将“春节月”定义为包含春节假期在内的4周时间,即春节休市前的5个交易日和春节开市后的10个交易日。春节前后或春节月的收益率采用对数差分收益率的计算方式,其中𝑟𝑡表示第t期的收益率,𝑃𝑡表示第t期的收盘指数点位:
基于上述公式,我们可以推出,第 i 期收盘到第 j 期收盘这段时间的收益率就等于:
本文所指的“春节月”为包含春节假期在内的前后 4 周时间,即春节休市前的 5 个交易日和春节开市后的 10 个交易日,春节前后或春节月的收益率采用的是对数收益率。
核心代码:
from WindPy import *
from WindCharts import *
import pandas as pd
import numpy as np
from collections import OrderedDict
w.start()
defget_spring_datas(df,method,n=10):#输入参数:df为提取的前收盘价和收盘价数据、method为获取的是时间段(spring_before为春节前,spring_later为春节后,spring_all为春节月)
df.index.names=['date'] #给索引取名字
#part1:计算对数收益率
datas=df.reset_index() #将时间索引转化为日期date变量
#part2:提取春节开始前最后一个交易日和春节结束后的第一个交易日
datas['date_bef']=datas['date'].shift(1) #提取前一日的交易日期
datas['periods']=datas.date-datas.date_bef #计算相邻两个交易日的时间差
dates=datas[['date','date_bef','periods']].loc[datas.date.apply(lambda x: x.month==1or x.month==2or x.month==3)] #提取阳历为1、2、3月份的日期
dates_=dates[dates.periods>=pd.Timedelta(7,unit='d')] #提取时间间隔大于等于7的时间段,即为春节休市期间
spr_beg=dates_[['date_bef']] #提取各年春节开始休市的前一天交易日
spr_end=dates_[['date']] #提取各年春节休市结束后的首个交易日,注:此处的日期必须为dataframe形式,以为还要借助日期对应的索引提取休市前后N日的收益率
datas_close=datas.iloc[:,:2] #只提取第一、二列(日期和收盘价)
#part3:根据不同需求提取数据
if method=='spring_before': #提取春节前的数据
spr_bef_datas=OrderedDict()
for index,date in spr_beg.itertuples(): #返回的是索引值和日期
spr_bef_datas[date.year]=datas_close.iloc[index-n:index].set_index(keys='date',drop=True) #提取休市前N日的收益率,并重新将日期设置为索引
datas_=pd.concat(spr_bef_datas.values(),keys=spr_bef_datas.keys())
elif method=='spring_later': #提取春节后的数据
spr_end_datas=OrderedDict()
for index,date in spr_end.itertuples(): #返回的是索引值和日期
spr_end_datas[date.year]=datas_close.iloc[index:index+n].set_index(keys='date',drop=True) #提取休市前N日的收益率,并重新将日期设置为索引
datas_=pd.concat(spr_end_datas.values(),keys=spr_end_datas.keys())
elif method=='spring_all': #提取春节月的数据,春节月的时间采用的是兴业金工研报的定义方式
n1=5#设置春节前的交易日数
n2=10#设置春节后的交易日数
spr_datas=OrderedDict()
for index,date in spr_beg.itertuples(): #返回的是索引值和日期
spr_datas[date.year]=datas_close.iloc[index-n1:index+n2].set_index(keys='date',drop=True) #提取休市前N日的收益率,并重新将日期设置为索引
datas_=pd.concat(spr_datas.values(),keys=spr_datas.keys())
return datas_ ,dates_ #返回春节期间收盘价数据datas_、提取的春节前后休市开市日期dates_
指数的“春节效应”
提取沪深两市中9大常用指数——"00001.SH"("上证综指")、"399001.SZ"("深证成指")、"000016.SH"("上证50")、"000903.SH"("中证100")、"000300.SH"("沪深300")、"000905.SH"("中证500")、"000852.SH"("中证1000")、"399005.SZ"("中小板指数")、"399006.SZ"("创业板指数") 的收盘数据。
春节效应期间的定义方式采用的是兴业金工研报的定义方式:春节休市前的5个交易日和春节开市后的10个交易日。
大家也可通过修改get_spring_datas函数中的n1和n2变量来自行设置春节效应的期间范围。
核心代码:
defret_comperate(begdate,enddate,codes,method,n=10):
ret_all=pd.DataFrame() #初始化收益序列
for code,name in codes.items():
_,datas=w.wsd(code, "close",begdate, enddate, "PriceAdj=F",usedf=True) #提取各指数的收盘数据
close_df,dates=get_spring_datas(method=method,n=n,df=datas)
ret=close_df.groupby(level=0).apply(lambda x: np.log(x.iloc[-1]/x.iloc[0])) #计算春节期间的对数收益率
ret.columns=[name]
ret_all=pd.concat([ret_all,ret],axis=1)
ret_all.loc['mean']=ret_all.mean(axis=0) #按列求平均
print(method+" success")
return dates,round(ret_all,4) #收益率计算结果保留4为小数
#初始化有关参数
indexs={"000001.SH":"上证综指","399001.SZ":"深证成指","000016.SH":"上证50","000903.SH":"中证100","000300.SH":"沪深300","000905.SH":"中证500","000852.SH":"中证1000","399005.SZ":"中小板指数","399006.SZ":"创业板指数"}
begdate='2010-01-01'#起始时间
enddate='2022-12-31'#结束时间
dates,ret=ret_comperate(begdate,enddate,codes=indexs,method='spring_all') #计算各指数春节日的收益率
最近 3 年 2020-2022 年的春节月期间,各指数收益都不理想,负收益居多;小盘股收益整体上优于大盘股收益。
从历史春节月期间的平均收益来看,各指数都呈现一定的春节效应,其中中证1000、中证500、创业板指、中小板指在春节月期间都能取得 5% 以上的收益。
各指数,春节后的表现都要优于春节前的表现;春节前10天里,越靠近春节,表现越优。
上证综指春节月和春节前后涨跌表现
沪深300春节月和春节前后涨跌表现
中证500春节月和春节前后涨跌表现
中证1000春节月和春节前后涨跌表现
创业板指春节月和春节前后涨跌表现
行业的“春节效应”
各行业也呈现春节效应,大部分行业春节月期间都能取得 5% 以上的收益,而且也是节后收益贡献较大。
核心代码:
defget_industry_name():
industry=['b101000000000000','b102000000000000','b103000000000000','b104000000000000','b105000000000000','b106000000000000','b107000000000000','b108000000000000','b109000000000000','b10a000000000000',\
'b10b000000000000','b10c000000000000','b10d000000000000','b10e000000000000','b10f000000000000','b10g000000000000','b10h000000000000','b10i000000000000','b10j000000000000','b10k000000000000',\
'b10l000000000000','b10m000000000000','b10n000000000000','b10o000000000000','b10p000000000000','b10q000000000000','b10r000000000000','b10s000000000000','b10t000000000000']
names=['石油石化','煤炭','有色金属','电力及公用事业','钢铁','基础化工','建筑','建材','轻工制造','机械','电力设备','国防军工','汽车',\
'商贸零售','餐饮旅游','家电','纺织服装','医药','食品饮料','农林牧渔','银行','非银行金融','房地产','交通运输','电子元器件','通信','计算机','传媒','综合']
indus_dic={}
for (indus,name) in zip(industry,names):
indus_dic[indus]=name
return indus_dic
#定义板块提取时间序列数据函数:因为wses最多只能提取3年的数据,所以当期间较长时,需要分段提取并合并,该函数是一年取一次,取得是日度数据
defget_datas(begdate,enddate,code):
beg_year=begdate[:4]
end_year=enddate[:4]
years=np.arange(int(beg_year),int(end_year))
years_beg=["%d-01-01"%i for i in years] #形成每年1月1日的日期
years_end=["%d-12-31"%i for i in years] #形成每年12月31日的日期
datas=pd.DataFrame()
for beg,end in zip(years_beg,years_end):
data=w.wses(code, "sec_close_avg",beg,end,"",usedf=True)[1] #提取算术平均收盘价
datas=pd.concat([datas,data],axis=0)
return datas
defret_comperate_industry(begdate,enddate,codes,method,n=10):
ret_all=pd.DataFrame() #初始化收益序列
for code,name in codes.items():
datas=get_datas(begdate,enddate,code) #提取各行业的日度收盘数据
close_df,dates=get_spring_datas(method=method,n=n,df=datas)
ret=close_df.groupby(level=0).apply(lambda x: np.log(x.iloc[-1]/x.iloc[0])) #计算春节期间的对数收益率
ret.columns=[name]
ret_all=pd.concat([ret_all,ret],axis=1)
print(code,name,"success")
ret_all.loc['mean']=ret_all.mean(axis=0) #按列求平均
print(method+" success")
return dates,round(ret_all,4) #收益率计算结果保留4为小数
indexs_ind=get_industry_name()
dates,ret=ret_comperate_industry(begdate,enddate,codes=indexs_ind,method='spring_all') #计算各指数春节日的收益率
中信一级行业历年春节月涨跌明细
明天就是大年三十了
最后祝大家新年快乐,玩得开心!
QIML将在新年不定期为大家奉献精彩的内容~
阅读原文 最新评论
推荐文章
作者最新文章
你可能感兴趣的文章
Copyright Disclaimer: The copyright of contents (including texts, images, videos and audios) posted above belong to the User who shared or the third-party website which the User shared from. If you found your copyright have been infringed, please send a DMCA takedown notice to [email protected]. For more detail of the source, please click on the button "Read Original Post" below. For other communications, please send to [email protected].
版权声明:以上内容为用户推荐收藏至CareerEngine平台,其内容(含文字、图片、视频、音频等)及知识版权均属用户或用户转发自的第三方网站,如涉嫌侵权,请通知[email protected]进行信息删除。如需查看信息来源,请点击“查看原文”。如需洽谈其它事宜,请联系[email protected]。
版权声明:以上内容为用户推荐收藏至CareerEngine平台,其内容(含文字、图片、视频、音频等)及知识版权均属用户或用户转发自的第三方网站,如涉嫌侵权,请通知[email protected]进行信息删除。如需查看信息来源,请点击“查看原文”。如需洽谈其它事宜,请联系[email protected]。