传统的多因子模型处理共线性的方法,如IC加权、IR加权,ICIR加权等,都以IC值为基础确定各因子在模型中的权重。而IC是当期因子暴露与下一期收益间的相关系数。
传统方法的缺陷是:如果因子间存在较强的相关性,通过上述加权方式,最终会导致因子对于某种风格的因子重复暴露。使得整个组合的表现严重偏向于该因子,削弱其他因子的效果。
具体来说,当因子表现好时,组合会获得更高的超额收益,当因子表现不好时,会出现更大幅的回撤。
这个时候,便需要采取因子正交处理的方式解决此问题。
正交化目的是消除因子间的相关性,并保持因子对于收益的解释度不变。
from atrader import *
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import math
import statsmodels.api as sm
import datetime as dt
import scipy.stats as stats
import seaborn as sns
# Z-Score标准化
def standardize_z(dt):
mean = dt.mean() # 截面数据均值
std = dt.std() # 截面数据标准差
return (dt - mean)/std
# 获取截面因子数据,单日多标的多因子
names = ['REVS60','REVS120','BIAS60','CCI20','PVT','MA10Close','DEA','RC20','RSTR63','DDI']
factors = get_factor_by_day(factor_list= names, target_list=list(get_code_list('hs300').code), date='2019-05-31')
factors = factors.set_index('code').fillna(0)
factors_standardize = standardize_z(factors) # 标准化
M = (factors_standardize.shape[0]-1)* np.cov(factors_standardize.T.astype(float)) # 矩阵M
D,U = np.linalg.eig(M) # 获取特征值和特征向量
U = np.mat(U) # 转换为np中的矩阵
d = np.mat(np.diag(D**(-0.5))) # 对特征根元素开(-0.5)指数
S = U * d * U.T # 获取过度矩阵S
factors_orthogonal_mat = np.mat(factors_standardize) * S # 获取对称正交矩阵
factors_orthogonal= pd.DataFrame(factors_orthogonal_mat,columns = names,index=factors_standardize.index) # 矩阵转为dataframe
# 因子相关性
F_o = factors_orthogonal.fillna(0).corr() # 正交化后的因子相关性
F = factors.fillna(0).corr() # 正交化前的因子相关性
# 相关性画图
fig = plt.figure()
plt.subplots(figsize=(8, 6.4)) # 设置画面大小
sns.heatmap(F, annot=True, vmax=1, vmin=-1, square=True, cmap="CMRmap_r",)
plt.show()
plt.subplots(figsize=(8, 6.4)) # 设置画面大小
sns.heatmap(F_o, annot=True, vmax=1, vmin=-1, square=True, cmap="CMRmap_r",)
plt.show()
# 正交化前后的因子相关性
corr = list()
for i in range(factors.shape[1]):
c = factors_standardize.iloc[:,i].astype(float).corr(factors_orthogonal.iloc[:,i].astype(float))
corr.append(c) # 获取正交前后因子的相关性
corr_df = pd.DataFrame(np.asarray(corr).T,index=names,columns=['corr']) # 转为DataFrame
corr_mean = corr_df.mean()
print(corr_df)