规模类因子测试

2019-01-22 15:31:54 浏览数 (1)

01

市值因子测试总述

规模因子是A股长期以来非常显著的一个负向因子,单调性表现非常好,本文共测试如下6个规模因子。

测试方法:分层测试、回归测试、IC

测试区间:2010年1月-2018年6月

是否中性化:行业中性,不市值中性

加权方法:等权

IC:rankIC

回测代码说明见文章最后,自娱自乐,不保证正确性,请理性看待,欢迎指正。

整体来看,回测区间内所有规模因子都是非常显著的,但IC相关性很高,说明规模因子同质性非常高,使用时应有所取舍。

接下来对每个因子的具体含义进行说明,并展示各因子测试结果。

每个因子的测试结果用三张图说明:每期IC柱状图和3期移动平均(IC均值,t检验太懒了就不做了,而且个人觉得,分组的结果更能说明问题)、因子分组净值曲线、因子分组后各组在回测区间内总收益的柱状图,所有因子从Group_1到Group_5因子值递增。

02

总市值MC

总市值是最常用的度量股票规模的因子,单个股票的总市值等于对应时间的总股本数乘以股价,反映的是股票按市场价格计算出来的总价值。对总市值因子的测试结果如下

市值因子IC整体偏负,表明这是一个负向因子,同时分层单调性表现非常好,各分组净值依次递减,但2017年之后因子出现明显回撤,一方面是股市整体表现不好的原因,另一方面也说明市值因子可能失效了。

03

总市值对数LNMC

总市值作为因子的问题在于,A股全体股票市值存在严重拖尾,取对数可以使因子值更接近正态分布。但取对数是单调变换,而且市值没有负数,所以LNMC因子的含义其实与MC含义没有本质区别,测试结果如下

测试结果与MC基本一致。

04

流通市值FC

除了总市值MC,流通市值FC也是规模的一个很好度量,流通市值计算方法正如字面意思反映的,是给定时间当时可以交易的股本数乘以当时的股价。因此,与总市值最大的不同在于,FC仅包含可以交易的股本。

总股本 = 流通股本 限售股本

因此如果用市值加权法计算组合收益时也应该使用流通市值而不是总市值,测试结果如下

因子单调性非常好,但2017年之后也出现了明显回撤。

05

流通市值对数LNFC

取对数的原因同LNMC,测试结果如下

测试结果与FC基本一致。

06

FCMC

FCMC指FC/MC,是流通市值占总市值的比例。忘了在哪个报告里看到的这个因子,也不难算,测一下看看结果。

从图1可以看出FCMC是一个跟其他因子相关性很低的因子,但很可惜测试结果来看,IC正负取值比较平均,因子分组单调性也不好,所以没什么用。

07

TC

TC是股票的总资产。市值会随价格的波动不断波动,包含市场估值和情绪的影响,但TC反映在财报中,是对公司真实财务状况的计量结果,不包含市场估值情绪的影响,并且在新的财报公布之前,值是不变化的,相对稳定。

TC因子测试时,每次取最新财报中的值,测试结果如下

TC效果较好,但从图1相关性可以看到,MC,LNMC,FC,LNFC,TC同质性较高。

08

NLSIZE

NLSIZE非线性规模因子,是Barra CNE5中的一个因子,原文定义如下

简单来说,就是MC取对数后三次方,然后用市值正交化之后再标准化。

非线性规模因子强调的是中等规模的因子。为什么是中等规模的因子,我们可以把LNMC和NLSIZE放在一起来说明,可以看到,随着NLSIZE增大,LNMC先增后减,因此,NLSIZE最大的部分对应的正是LNMC的中间部分,也就是中等市值的部分。

测试结果如下

NLSIZE测试效果较好,并且与其他因子的相关性不高。

09

测试框架说明

因子测试框架基于数据库搭建。具体实现过程就不贴了,毕竟不同数据结构代码也不能直接套,分享一下框架结构,不是很完善,如果有写过类似框架的可以指点一下。

整体定义为一个FctorTest类,FactorTest类包含分层测试和回归测试的方法,分层测试pandas中有qcut函数可以快速完成分组,再通过groupbyapply函数可以快速完成收益率计算。 对于每个要测试的因子,用一个因子子类继承FctorTest,定义GetFactor函数后直接调用FactorTest中的各个函数即可完成测试。

框架如下,每个函数都有注释说明。

代码语言:javascript复制
from abc import ABCMeta,abstractmethod
import pyodbc
import numpy as np
import pandas as pd
import numpy.linalg as la
import matplotlib.pyplot as plt
import datetime 
import calendar
import seaborn as sns
import statsmodels.api as sml
import scipy.stats as stats

class FactorTest():       
    __metaclass__ = ABCMeta    
    def __init__(self,startdate,enddate):
        self.startdate = startdate
        self.enddate = enddate
        
        
    @abstractmethod
    def getFactor(self,*args):
        """
        计算因子的函数,返回dataframe
        """
        pass        
    def printdate(self):
        '''
        测试用的函数,看一下日期,同时看一下类是否正常工作
        '''
        print("因子测试开始日期是:{}".format(self.startdate))
        print("因子测试结束日期是:{}".format(self.enddate))
        
        
        
    def stkcode(self,datebuy,lagmonth=3):
        """
        提取给定日期对应的股票列表,剔除ST股,新股,返回list
        """
        
        return(stockcode)     
        

    
    def getswclass(self,data,datein):
        """
        对于给定日期的所有股票,添加申万一级行业,返回dataframe
        """
        return data
    
    def getmkt(self,data,datein):
        """
        对于给定日期的所有股票,添加总市值,返回dataframe
        """
        
        return data
       
    def get_pct1(self,stockcode,datein,dateout):
        """
        计算给定日期期间内所有股票的涨幅,返回dataframe
        """

        return price
               
    def norm(self,data,if_neutral_industry,if_neutral_mktcap):
        """
        中性化函数,对因子进行中性化
        """      
        return data      
    def getIC(self,data, rt, method = 'rank'):
        """
        计算IC
        """
        if method == 'rank' or method == 'Spearman':
            IC = stats.spearmanr(data.values, rt.values)[0]
        elif method == 'normal' or method == 'Pearson':
            IC = data.corr(rt)
   
        return(IC)
     
    def getSingleIC(self,if_neutral_industry,if_neutral_mktcap,datesell):        
        """
        给定日期,计算当期的IC,返回dataframe
        """
        return(result)
                    
    def getICSeries(self,if_neutral_industry,if_neutral_mktcap):
        
        """
        给定回测区间,循环调用getSingleIC计算IC
        """
        return(result)
        
# 分层测试        
    def GroupTest(self,if_neutral_industry,if_neutral_mktcap,group = 5):
        """
        给定区间,循环进行分层测试
        """       
        return(nav)   
        
# 分层测试   回归测试       
    def GroupRegTest(self,if_neutral_industry,if_neutral_mktcap,group = 5):
        """
        给定区间,循环进行分层测试和回归测试
        """
        return(result)

0 人点赞