本文采用万矿平台的WindAlpha单因子研究框架,从股票因子的角度探究COVID-19疫情对股市的影响。IC分析发现,疫情严重程度与股市收益具有显著的负相关性,这种负相关性随时间递增并在第10天达到峰值;根据COVID-19疫情因子对股票分组,第一组的收益率显著高于其他组,多空组合能够跑赢大盘。(代码克隆点这里)
目录
1. 因子构建
2. 因子预处理
2. 因子分析
2.1 IC分析
2.2 收益率分析
1. 因子构建
首先获取各省疫情数据的时间序列,获取方法见获取COVID-19疫情历史数据的n种方法。此处的数据源是R语言里的nCov2019库:
library(nCov2019)
x <- load_nCov2019()
data <- summary(x)[1:3]
write.csv(data,"Data/nCovProvince.csv",row.names = FALSE)
然后在万矿平台上提取非ST,非PT的全部A股的注册地和办公地点,找到地点所对应的省份。根据省份信息在此前获取的疫情数据中找到对应的确诊人数,并将确诊人数作为股票当日的因子取值。
from WindPy import *
from datetime import datetime
from scipy import stats, optimize
from WindCharts import *
import pandas as pd
import WindAlpha as wa
w.start(show_welcome=False)
nCov_province = pd.read_csv("data/nCov/nCovProvince.csv",encoding = "gbk",index_col = ["time", "province"])
start_date = nCov_province.index[-1][0]
end_date = nCov_province.index[1][0]
def get_province(address):
province_list = ['上海','云南','内蒙古','北京','台湾','吉林','四川','天津','宁夏','安徽','山东',
'山西','广东','广西','新疆','江苏','江西','河北','河南','浙江','海南','湖北',
'湖南','澳门','甘肃','福建','西藏','贵州','辽宁','重庆','陕西','青海','香港','黑龙江']
for province in province_list:
if province in address:
return province
def factor_prepare(nCov_province):
trade_dates = w.tdays(start_date, end_date, period="d").Data[0]
trade_dates = [dt.strftime("%Y-%m-%d") for dt in trade_dates]
stock_set = w.wset("sectorconstituent", "date="+start_date+";sectorId=a001010f00000000;field=wind_code", usedf=True)
stock_list = list(stock_set[1]['wind_code'])
raw_data=w.wss(stock_list, "address,office", "rptDate= %s" %(start_date),usedf=True)[1]
raw_data["ADDRESS"] = raw_data["ADDRESS"].map(get_province)
raw_data["OFFICE"] = raw_data["OFFICE"].map(get_province)
index=pd.MultiIndex.from_product([trade_dates,stock_list])
factor = pd.Datafr ame(columns=raw_data.columns,
index=index)
for trade_date in trade_dates:
factor.loc[trade_date,"ADDRESS"] = np.asarray(raw_data["ADDRESS"])
factor.loc[trade_date,"OFFICE"] = np.asarray(raw_data["OFFICE"])
for trade_date in trade_dates:
for security_code in stock_list:
for columns in factor.columns :
security_prvince = factor.loc[(trade_date,security_code),columns]
try:
factor.loc[(trade_date,security_code),columns] = nCov_province.loc[(trade_date,security_prvince), "cum_confirm"]
except (KeyError):
factor.loc[(trade_date,security_code),columns] = 0
date_index = [datetime.datetime.strptime(dt,"%Y-%m-%d") for dt in index.levels[0]]
index.set_levels(date_index, level=0, inplace = True)
factor.set_index(index,inplace = True)
inds_ret = wa.load_local_factors(factor)
return inds_ret
raw_ind_ret = factor_prepare(nCov_province)
上传之后的因子数据结构如下,其中最后两列为上传因子的过程中万矿平台自动添加的数据,MKT_CAP_ASHARE表示A股市值(不含限售股),NEXT_RET表示股票的下一期收益。
2. 因子预处理
接下来进行因子的预处理:
- 缺失值处理:直接删除缺失行
- 去极值:进行极值处理会将湖北省的作为极值删除,因此没有进行去极值的处理
- 标准化:采用了市值加权标准化方法,相当于同时进行了市值中性化处理
- 行业中性化:为了消除行业对因子表现的潜在影响,此处通过建立线性回归的形式进行中性化处理,即以原始因子值为因变量,行业哑变量为自变量进行回归,回归得到的残差是原始因子中无法被行业解释的部分,所以提取残差作为中性化后的新因子。
processed_inds_ret = wa.process_raw_data(raw_ind_ret, missing_method = "dele",
extreme_method = False, scale_method = "cap",
neutralize_method = 'sw_1',isinclude_cap = False)
原始因子与处理后的因子对比:
import seaborn as se
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(7,5))
plt.subplot(211)
processed_inds_ret.loc['2020-02-04']["OFFICE"].hist()
plt.subplot(212)
raw_inds_ret.loc['2020-02-04']['OFFICE'].hist()
plt.suptitle(u"Processed Data VS Raw Data(Date:2020-02-04)")

2. 因子分析
2.1 IC分析
信息系数(IC),指每一期因子值与下一期股票收益率之间的相关性。IC的大小反应了因子暴露值与股票表现之间的线性关系,IC的值越大说明因子的预测性越高,选股的效果就越好。此处采用RankIC方法计算IC值,即计算因子暴露值排名与股票下期回报排名的截面相关系数。
ic_ana = wa.ic_analysis(processed_inds_ret)
ind = "OFFICE"
fig_ic=WLine("IC序列:{}".format(ind),"{}-{}".format(start_date, end_date), ic_ana.ic_series.loc[ind])
fig_ic.plot()

IC信号衰减
此前的IC序列计算的是当期的因子值与下一期收益率之间的相关性,也就是因子值与收益率之间相差一个周期。而IC衰减描述的是因子值和相隔LAG期的收益率的相关性。具体的计算方法为,如果一共有N期的因子数据和收益率数据,先把所有i期因子和i+1期收益率的IC值算出来求平均,再把i期因子和i+2收益率的IC求平均…(i=1,…,N-LAG),最终得到LAG个IC的均值,这几个均值就体现了IC的衰减。
ic_ana.ic_decay
|
ADDRESS |
OFFICE |
| LAG0 |
-0.016098 |
-0.014985 |
| LAG1 |
-0.037245 |
-0.035465 |
| LAG2 |
-0.055568 |
-0.054450 |
| LAG3 |
-0.081646 |
-0.080446 |
| LAG4 |
-0.100494 |
-0.099304 |
| LAG5 |
-0.114949 |
-0.112260 |
| LAG6 |
-0.131797 |
-0.132035 |
| LAG7 |
-0.142606 |
-0.145498 |
| LAG8 |
-0.143235 |
-0.149350 |
| LAG9 |
-0.141615 |
-0.150159 |
| LAG10 |
-0.146176 |
-0.154830 |
| LAG11 |
-0.144909 |
-0.152806 |
将IC衰减的结果可视化,可以发现非常明显的规律,疫情严重程度与股市收益具有显著的负相关性,这种负相关性随时间递增并在第10天达到峰值。
ind = "OFFICE"
fig_decay=WBar('{} IC Decay'.format("COVID-19"), '',ic_ana.ic_decay[ind].to_fr ame())
fig_decay.plot()

2.2 收益率分析
按照因子值大小将股票分为5组,并构建多1空5的多空组合,直接用每组每期股票的平均收益率(市值加权)来计算的每组的累计收益率等指标。
direction_dict = {ind: 'descending'}
ret_ana = wa.return_analysis(processed_inds_ret,'881001.WI',start_date, end_date,ind_direction=direction_dict)
将每组收益结果可视化,其中第一组的收益率显著高于其他组,多空组合能够跑赢大盘。
sig_ret_line = WLine("多空组合收益率:{}".format("COVID-19"),"{}-{}".format(start_date, end_date) , round(ret_ana.group_cum_return[['G01','G02','G03','G04','G05','G01-G05','BENCH_RET']].loc[ind],4),auto_yaxis=True)
sig_ret_line.plot()

相关文章
获取COVID-19疫情历史数据的n种方法
Logistic模型拟合COVID-19疫情以及Python实现
AHP | 层次分析法原理及Python实现
以上是本篇的全部内容,欢迎关注我的知乎|简书|CSDN|微信公众号PurePlay , 会不定期分享研究与学习干货。