跳转至

量化投资入门系列(五)——基于BARRA的组合构建

引言

在上一节中,我们提到了BARRA多因子模型,在本节中,我们将基于BARRA的多因子模型来介绍基本的组合构建过程。

BARRA的多因子模型可以表述为:

\[ r_n=f_c+\sum_iX_{n,i}f_i+\sum_sX_{n,s}f_s+spret_n \]

其中:

\( r_n \) 是股票n的收益率

\( f_c \) 是国家因子的收益率

\( f_i \)\( f_s \) 分别为行业和风格因子的收益率

\( X_{n,i} \)\( X_{n,s} \) 分别为股票n在行业因子和风格因子上的暴露

\( spret_n \) 是股票n的特质收益率

式中暴露的计算方法在上一节中已经说明,本节不再赘述,下面详细说明一下因子收益率的计算。

因子收益率

因子收益率的计算,可以转换为最小化以下方程:

\[ err = \sum_{n=1}^Nw_n(r_n-f_c-\sum_iX_{n,i}f_i-\sum_sX_{n,s}f_s) \]

同时需要满足:

\[ s.t. \sum_{n=1}^N\sum_iX_{n,i}f_i=0 \]

为了方便计算,可以先移除上述限制,并且从最小化方程中移除掉国家因子,从而将最小化方程转换为:

\[ err = \sum_{n=1}^Nw_n(r_n-\sum_iX_{n,i}\tilde{f_i}-\sum_sX_{n,s}f_s) \]

然后通过最小二乘法求解出 \( f_s \)

接下来再重新求解国家因子收益率和加入了行业因子后的行业因子收益率,使得因子收益率满足前述的约束条件。

\[ f_c=\sum_{n=1}^N\sum_iw_nX_{n,i}\tilde{f_i} \]

因子收益率协方差矩阵和特质收益率方差矩阵

同时,我们需要进一步计算因子收益率的协方差矩阵和特质收益率的方差矩阵:

\[ cov(f_i,f_j)=\frac{\sum_{s=0}^T\lambda_{t-s}(f_{i,t-s}-\bar{f_i})(f_{j,t-s}-\bar{f_j})}{\sum_{s=0}^T\lambda_{t-s}} \]

在这里,可以加入权重衰减的概念,即对于近期的数据增加权重,对于更远的数据减少权重,式中 \( \lambda \) 为指数衰减权重,有 \( \lambda_{t-s}=0.5^{s/\tau} \)\( \tau \) 为半衰期,可自行设定。

类似的,也可以基于权重衰减的方式计算特质收益率的方差矩阵:

\[ var(spret_n)=\frac{\sum_{s=0}^T\lambda{t-s}(spret_{n,t-s}-\bar{spret_n})^2}{\sum_{s=0}^T\lambda_{t-s}} \]

结构化风险模型

定义因子收益率的协方差矩阵为F,股票特质收益率的方程矩阵为 \( \Delta \),股票收益率之间的协方差矩阵V可以表示为:

\[ V=XFX^T+\Delta \]

在获取了以上信息后,我们可以计算一个组合的收益率及风险,假设我们有一个股票池p,池中第n只股票的权重为 \( w_n \) ,则组合的收益率可以表述为:

\( r_p=\sum_{n=1}^Nw_n(\sum_{k}X_{n,k}f_k+spret_n) \) 其中k为某个因子,包括国家因子、行业因子和风格因子。

而组合p的风险可以表示为:

\( \sigma_p^2=W^T(XFX^T+\Delta)W \)

有了上述两个式子,我们就根据我们的目标去做组合优化,从而获取收益。

1. 目标为绝对收益,目标函数为:

\[ max(r_p-\lambda\sigma_p^2) \]
\[ s.t. w_n\geq0, \sum w_n=1 \]

2. 目标为超额收益,则 \( w_n \) 应为组合中股票n与基准中股票n的权重之差,目标函数不变,约束条件变为:

\[ s.t. w_n+w_{n,benchmark}\ge0,\sum(w_n+w_{n,benchmark})=1 \]

在目标函数中有一个很重要的东西就是 \( \lambda \) ,我们称之为风险厌恶系数,当\( \lambda \)较小时,组合更加倾向于追求收益,而当\( \lambda \)较大时,组合在风险控制上更加出色,因此在实际的投资组合的构建中,需要根据个人的风险偏好来给定相应的风险厌恶系数。

在大多数的文献中,在定义目标函数的时候都使用的是组合的方差,并且在方差前面增加了一个½的系数,从而使得在求导的计算更加方便,由于数量级的差异,为了有效的使风险的部分发挥作用,需要给出较大的\( \lambda \)。但是目前随着计算机的计算速度的不断提升,笔者更倾向于使用标准差,从而使得收益与风险基本处于接近的数量级,\( \lambda \)的值的确定会相对方便。

最优化方法

以上的目标函数,本质上是一个最优化的问题,基本的计算方式就是构建拉格朗日方程,当然,各种科学计算包的存在使得我们不需要手动去计算,通常,最常用的就是scipy中的minimize,如果想更快的计算,在tensorflow1.0中的ScipyOptimizerInterface方法是不二选择:

    class OptTF():
        def __init__(self, exposure, covariance, sprisk, factorret, spret, benchmark, lamb):
            self.exposure = tf.constant(exposure)
            self.covariance = tf.constant(covariance)
            self.sprisk = tf.constant(sprisk)
            self.benchmark= tf.constant(benchmark)
            self.factorret = tf.constant(factorret)
            self.spret = tf.constant(spret)
            self.xfx = tf.matmul(self.exposure,tf.matmul(self.covariance,tf.transpose(self.exposure)))
            self.xf = tf.matmul(self.exposure,tf.transpose(self.factorret))
            self.lamb = lamb

        def fun(self, w):
            w_sum = tf.reduce_sum(w)
            w = w / w_sum
            w = w - self.benchmark
            part_0 = tf.matmul(tf.transpose(new_w), self.xf) + tf.matmul(tf.transpose(new_w),self.spret)
            part_1 = tf.matmul(tf.matmul(tf.transpose(new_w),self.xfx),new_w)
            part_2 = tf.matmul(tf.transpose(new_w * self.sprisk),new_w)
            return part_0 * (-1) + self.lamb * tf.sqrt(part_1 + part_2)

        def main(self):
            w = tf.random_uniform(500, minval=0, maxval=1,dtype=tf.float32)
            vector = tf.Variable(w, 'vector') 
            bnds = {vector: (0, 1)}
            constrains = 
            loss = self.fun(vector)
            optimizer = tf.contrib.opt.ScipyOptimizerInterface(loss, method='SLSQP',
                                                               options={'maxiter':50},
                                                               var_to_bounds=bnds) 
            result = None      
            with tf.Session() as session: 
                tf.global_variables_initializer().run() 
                optimizer.minimize(session, 
                    fetches=[loss, vector]) 
                result = vector.eval()
            return result

以上是Scipy OptimizerInterface使用的简单示例,需要注意的几个点是,目标函数为求max,但是在代码里是乘以-1之后求min。而约束条件这里,笔者个人更习惯在代码里做强制性的约束而不是使用方法中自带的equalitiesinequalities参数,这部分取决于个人习惯。

基于BARRA多因子模型,我们可以有效地在追求收益的时候进行风险管理,但是需要注意的是,受制于对冲成本等因素,该模型的收益被大大削弱,其相对适用的场景是指数增强,而如果要追求更高的收益,以上的这些风格及行业因子还远远不够,在下一节,将对技术类因子做集中的论述。

凡本网注明"来源:XXX "的文/图/视频等稿件,本网转载出于传递更多信息之目的,并不意味着赞同其观点或证实其内容的真实性。如涉及作品内容、版权和其它问题,请与本网联系,我们将在第一时间删除内容!
作者: 李浩然, 华泰证券 算法工程师
来源: https://zhuanlan.zhihu.com/p/405380012