请 [注册] 或 [登录]  | 返回主站

量化交易吧 /  量化平台 帖子:3365835 新帖:10

【笔记】单因子有效性分析(二):行业市值中性化

外汇交易达人发表于:5 月 10 日 07:10回复(1)

在第一篇中介绍了数据处理的各种方法,接下来到了一个很关键的地方,其实它也属于数据处理的一部分,但是由于我觉得他比较重要,所以单独拎出来说一下。

行业中性化分为以下几个步骤
1、为什么要做行业中性化
2、如何做行业市值中性化

1、为什么要做行业中性化

众所周知,行业和市值是两个十分显著对因子有影响力的因素。在进行截面回归判断每个单因子的收益情况和显著性时,需要特别关注这两个十分显著的因素。
我们做因子分析是为了挑选出有效因子,并对其值进行排序,按顺序或者倒叙来选择股票,但如果不剔除行业或者市值的影响,可能会导致选出的股票集中在某个行业或者是某种市值范围内,从而导致并不能很有效的分散风险,所以我们需要看的是在剔除了这两个因素之外,因子值的有效性。在这里我用聚宽上的因子做一个例子。
选取‘hs300_alpha’因子为例,股票范围选取沪深300指数成分股,行业分类标准选取申万一级行业分类。
echarts.png
从图中我们可以看出“综合”这个行业的因子值显著高于其他行业,这对我们进行因子分析是不利的。加下来就会介绍剔除行业和市值影响的行业市值中性化处理。

2、如何做行业市值中性化

我们通过建立回归方程来剔除行业和市值的影响,我们把想要剔除的因子暴露(如市值)作为X值,而Y值就是因子值本身,通过回归我们想要得到不能被X也就是该因素所解释的部分----残差值。
我们想要得到市值是十分容易的,但是行业要如何剔除呢。我们建立一个矩阵,就是如果股票属于某个行业,则该股票在该行业的因子暴露(因子值)等于1,在其他行业的因子暴露为0.这样就可以得到行业的哑变量矩阵,再通过回归得到残差值,就是我们想要得到的剔除行业中性化的值。
代码:见研究

from jqfactor import Factor, calc_factors
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import statsmodels.api as sm
stock = get_index_stocks('000300.XSHG')

class Hs300Alpha(Factor):
    # 设置因子名称
    name = 'hs300_alpha'
    # 设置获取数据的时间窗口长度
    max_window = 10
    # 设置依赖的数据
    dependencies = ['close']

    # 计算因子的函数, 需要返回一个 pandas.Series, index 是股票代码,value 是因子值
    def calc(self, data):
        # 获取个股的收盘价数据
        close = data['close']
        # 计算个股近10日收益
        stock_return = close.iloc[-1,:]/close.iloc[0,:] -1
        # 获取指数(沪深300)的收盘价数据
        index_close = self._get_extra_data(securities=['000300.XSHG'], fields=['close'])['close']
        # 计算指数的近10日收益
        index_return = index_close.iat[-1,0]/index_close.iat[0,0] - 1
        # 计算 alpha
        alpha = stock_return - index_return
        return alpha
factors = calc_factors(stock, [Hs300Alpha()], start_date='2017-01-01', end_date='2017-12-31')
/opt/conda/envs/python3new/lib/python3.6/site-packages/statsmodels/compat/pandas.py:56: FutureWarning: The pandas.core.datetools module is deprecated and will be removed in a future version. Please use the pandas.tseries module instead.
  from pandas.core import datetools
data=factors['hs300_alpha']
from jqdata import *
sw=get_industries(name='sw_l1').index
a=[0]*len(sw)
for i in range(len(sw)):
    a[i]=data[list(set(data.columns).intersection(set(get_industry_stocks(sw[i]))))].mean().mean()
from pyecharts import Bar
from pyecharts import online
online()
bar = Bar()
names=["农林牧渔","采掘","化工","钢铁",'有色金属','电子','家用电器','食品饮料','纺织服装','轻工制造',
'医药生物','公用事业','交通运输','房地产','商业贸易','休闲服务','综合','建筑材料','建筑装饰','电气设备',
'国防军工','计算机','传媒I','通信','银行','非银金融','汽车','机械设备']
bar.add("各行业因子值均值", names, a,
        is_more_utils=True)
bar
#获得行业哑变量矩阵
from jqdata import *
sw=get_industries(name='sw_l1').index
industry=pd.DataFrame(0,columns=data.columns,index=range(0,28))
for i in range(len(sw)):
    temp=list(set(data.columns).intersection(set(get_industry_stocks(sw[i]))))
    industry.loc[i,temp]=1

#去除市值、行业因素,得到新的因子值 
newx=pd.DataFrame()
for i in range(len(data.index)):
    m= get_fundamentals(query(valuation.circulating_cap,valuation.code).filter(valuation.code.in_(data.columns)), date=data.index[i])
    m.index=np.array(m['code'])
    m=m.iloc[:,0]
    m=(m-mean(m))/std(m)
    x=data.iloc[i,:]
    conc=pd.concat([x,m,industry.T],axis=1).fillna(mean(m))
    est=sm.OLS(conc.iloc[:,0],conc.iloc[:,1:]).fit()
    y_fitted = est.fittedvalues
    newx[i]=est.resid
newx=newx.T
newx.index=data.index
newx=newx.iloc[1:,:]

全部回复

0/140

量化课程

    移动端课程