量化角度看春节:A股的春节效应
量化投资与机器学习微信公众号,是业内垂直于量化投资、对冲基金、Fintech、人工智能、大数据等领域的主流自媒体。公众号拥有来自公募、私募、券商、期货、银行、保险、高校等行业30W+关注者,曾荣获AMMA优秀品牌力、优秀洞察力大奖,连续4年被腾讯云+社区评选为“年度最佳作者”。
华泰金工研报一般把腊月十八到次年的正月十八作为“农历春节效应月”。
兴业金工研报将“春节月”定义为包含春节假期在内的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()
def get_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==1 or x.month==2 or 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_
def ret_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') #计算各指数春节日的收益率
行业的“春节效应”
def get_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年的数据,所以当期间较长时,需要分段提取并合并,该函数是一年取一次,取得是日度数据
def get_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
def ret_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') #计算各指数春节日的收益率
微信扫码关注该文公众号作者
戳这里提交新闻线索和高质量文章给我们。
来源: qq
点击查看作者最近其他文章