量化交易:因子风险暴露

本文介绍了如何计算因子风险暴露的内容。

判断风险暴露的建模是否合理

通常,此分析是基于历史数据,而对历史风险暴露的估计可能会影响未来的风险暴露。 因此,计算因子风险暴露是不够的。 必须对风险暴露保持信心,并明白对风险暴露的建模是否合理。

运用多因子模型计算因子风险暴露,可以运用多因子模型分析一个组合中风险和收益的来源,多因子模型对收益的分解如下:

通过对历史收益率进行建模,可以分析出收益中有多少是来自因子收益率,有多少来自资产特质波动(epsilon)。 我们也可以研究投资组合所面临的风险来源,即投资组合的因子暴露

在风险分析中,我们经常对主动回报(相对于基准的回报)和主动风险(主动回报的标准差,也称为跟踪误差或跟踪风险)进行建模。

例如,我们可计算到一个因子对主动风险的边际贡献——FMCAR。 对于因子j,表示为:

b_j表示组合对因子j的风险暴露,b_i表示组合对因子i的风险暴露,K表示一共K个因子。FMCAR_j这项指标这告诉我们,假设其他条件不变,暴露在因子j下我们增加了多少风险。

策略案例

附件:运用Fama-French三因子模型演示因子风险暴露

# 导入要用到的模块
import numpy as np
import statsmodels.api as sm
import scipy.stats as stats
from statsmodels import regression
import matplotlib.pyplot as plt
import pandas as pd

获取总市值、总市值排序、市净率、市净率排序、日收益率

start_date = '2016-01-01'
end_date = '2017-05-10'
raw_data = D.features(D.instruments(),start_date,end_date,fields=     ['market_cap_0','rank_market_cap_0','pb_lf_0','rank_pb_lf_0','daily_return_0']) 
# 每日股票数量
stock_count = raw_data[['date','instrument']].groupby('date').count()
result=raw_data.merge(stock_count.reset_index('date'), on=['date'], how='outer') 
result = result.rename(columns={'instrument_x':'instrument','instrument_y':'stock_count'})

我们将市值最小的600只股票记为smallest组,将市值最大的600只股票记为biggest组

我们将市净率最小的600股票记为lowpb组,将市净率最大的600只股票记为highpb组

def is_smallest(x): if x.rank_market_cap_0 < 600/x.stock_count:return Trueelse:return False
result['smallest'] = result.apply(is_smallest,axis=1)def is_biggest(x): if x.rank_market_cap_0 > 1-600/x.stock_count:return Trueelse:return False
result['biggest'] = result.apply(is_biggest,axis=1)def is_lowpb(x): if x.rank_pb_lf_0 < 600/x.stock_count:return Trueelse:return False
result['lowpb'] = result.apply(is_lowpb,axis=1)def is_highpb(x): if x.rank_pb_lf_0 > 1-600/x.stock_count:return Trueelse:return False
result['highpb'] = result.apply(is_highpb,axis=1)result = result.set_index('date')

计算每日因子收益率

# 因子收益的定义,以市值因子举例,市值因子收益率=biggest组的平均收益率-smallest组的平均收益率
R_biggest = result[result.biggest]['daily_return_0'].groupby(level=0).mean()
R_smallest = result[result.smallest]['daily_return_0'].groupby(level=0).mean()
R_highpb = result[result.highpb]['daily_return_0'].groupby(level=0).mean()
R_lowpb = result[result.lowpb]['daily_return_0'].groupby(level=0).mean()
# 市值因子和市净率因子收益率
SMB = R_smallest - R_biggest
HML = R_lowpb - R_highpb

因子累计收益率并绘图

SMB_CUM = np.cumprod(SMB+1)
HML_CUM = np.cumprod(HML+1)plt.plot(SMB_CUM.index, SMB_CUM.values,)
plt.plot(HML_CUM.index, HML_CUM.values)
plt.ylabel('Cumulative Return')
plt.legend(['SMB Portfolio Returns', 'HML Portfolio Returns']);

计算风险暴露程度

下面我们运用多因素模型和线性回归工具来计算某只股票的回报率相对于这些因子的风险暴露程度。我们以某个资产组合的主动收益作为被解释变量,对因子做回归,一个因子对主动收益贡献越大,那么这个资产组合的主动收益对于该因子的暴露程度也越高。

# 我们以5只股票的组合(portfolio)举例
instruments = D.instruments()[:5]
Stock_matrix = D.history_data(instruments,start_date,end_date,fields=['close'])
Stock_matrix = pd.pivot_table(Stock_matrix,values='close',index=['date'],columns=['instrument'])
portfolio = Stock_matrix.pct_change()[1:]
# 组合的每日收益率(等权重组合)
R = np.mean(portfolio, axis=1)
# 基准收益率
bench = D.history_data('000300.SHA',start_date, end_date, fields=['close']).set_index('date')['close'].pct_change()[1:]
# 主动收益率
active = R - bench
# 建立一个常数项,为下文回归做准备
constant = pd.TimeSeries(np.ones(len(active.index)), index=active.index)
df = pd.DataFrame({'R': active,'F1': SMB,'F2': HML,'Constant': constant})
# 删除含有缺失值的行
df = df.dropna()

线性回归并获取回归系数

b1, b2 = regression.linear_model.OLS(df['R'], df[['F1', 'F2']]).fit().params
# 因子对于主动收益的敏感性(即因子暴露)
print('Sensitivities of active returns to factors:\nSMB: %f\nHML: %f' %  (b1, b2))

边际贡献

利用前文中的公式,计算因子对主动收益风险平方的边际贡献(factors' marginal contributions to active risk squared,FMCAR )

# 计算因子风险贡献
F1 = df['F1']
F2 = df['F2']
cov = np.cov(F1, F2)
ar_squared = (active.std())**2
fmcar1 = (b1*(b2*cov[0,1] + b1*cov[0,0]))/ar_squared
fmcar2 = (b2*(b1*cov[0,1] + b2*cov[1,1]))/ar_squared
print('SMB Risk Contribution:', fmcar1)
print('HML Risk Contribution:', fmcar2)

余下的风险可以归结于一些特有的风险因素,即我们没有加入模型的因子或者资产组合本身独有的某种风险。 通常我们会关注一下对这些因子的风险暴露随时间如何变化。让我们rolling一下~

# 计算滚动的beta
model = pd.stats.ols.MovingOLS(y = df['R'], x=df[['F1', 'F2']], window_type='rolling', window=100)   
rolling_parameter_estimates = model.beta
rolling_parameter_estimates.plot()
plt.title('Computed Betas');
plt.legend(['F1 Beta', 'F2 Beta', 'Intercept']);

现在我们来看看FMCAR是如何随时间变化的

# 计算方差协方差
# 去除有缺省值的日期,从有实际有效值的日期开始
covariances = pd.rolling_cov(df[['F1', 'F2']], window=100)[99:]
# 计算主动风险
active_risk_squared = pd.rolling_std(active, window = 100)[99:]**2
# 计算beta
betas = rolling_parameter_estimates[['F1', 'F2']]# 新建一个空的dataframe
FMCAR = pd.DataFrame(index=betas.index, columns=betas.columns)# 每个因子循环
for factor in betas.columns:# 每一天循环for t in betas.index:# 求beta与协方差之积的和,见公式s = np.sum(betas.loc[t] * covariances[t][factor])# 获取betab = betas.loc[t][factor]# 获取主动风险AR = active_risk_squared.loc[t]# 估计当天的FMCARFMCAR[factor][t] = b * s / AR

因子对于主动收益风险的边际贡献

plt.plot(FMCAR['F1'].index, FMCAR['F1'].values)
plt.plot(FMCAR['F2'].index, FMCAR['F2'].values)plt.ylabel('Marginal Contribution to Active Risk Squared')
plt.legend(['F1 FMCAR', 'F2 FMCAR'])

存在的问题

了解历史数据中组合对各个因子的暴露程度是很有趣的,但只有将它用在对未来预测上时,它才有用武之地。但我们不是总能够放心地认为未来的情况与现在相同,由于随时间会变化,对风险暴露程度取平均值也很容易出现问题。我们可以给均值加上一个置信区间,但只有当其分布是正态分布或者表现很稳健才行。我们来看看Jarque-Bera测验的结果。

from statsmodels.stats.stattools import jarque_bera
_, pvalue1, _, _ = jarque_bera(FMCAR['F1'].dropna().values)
_, pvalue2, _, _ = jarque_bera(FMCAR['F2'].dropna().values)print('p-value F1_FMCAR is normally distributed', pvalue1)
print('p-value F2_FMCAR is normally distributed', pvalue2)

p_value显示我们可以显著的拒绝其为正态分布,可见对于未来这些因素会导致多少风险暴露是很难估计的,所以在使用这些统计模型去估计风险暴露并以此为依据来对冲是需要万分小心的。

 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/218595.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

详解#define

我们要知道&#xff0c;#define后面定义的标识符只进行替换而不进行计算&#xff0c;我们不能根据惯性自动给它计算了&#xff0c;这样可能会出错。 目录 1.关于#define 1.1#define定义标识符 1.2#define定义宏 1.3#define的替换规则 2.#和## 1.# 2.## 3.带副作用的宏参…

前端vue3——html2canvas给网站截图生成宣传海报

文章目录 ⭐前言⭐选择html2canvas实现网页截图&#x1f496; 截图 ⭐图片url截图显示不出来问题&#x1f496; 解决 ⭐最终效果&#x1f496; 定义海报 ⭐总结⭐结束 ⭐前言 大家好&#xff0c;我是yma16&#xff0c;本文分享关于 前端vue3——html2canvas给网站截图生成宣传…

【超强笔记软件】Obsidian实现免费无限流量无套路云同步

【超强笔记软件】Obsidian如何实现免费无限流量无套路云同步&#xff1f; 目录 一、简介 软件特色演示&#xff1a; 二、使用免费群晖虚拟机搭建群晖Synology Drive服务&#xff0c;实现局域网同步 1 安装并设置Synology Drive套件 2 局域网内同步文件测试 三、内网穿透群…

【设计模式-2.1】创建型——单例模式

说明&#xff1a;设计模式根据用途分为创建型、结构性和行为型。创建型模式主要用于描述如何创建对象&#xff0c;本文介绍创建型中的单例模式。 饿汉式单例 单例模式是比较常见的一种设计模式&#xff0c;旨在确保对象的唯一性&#xff0c;什么时候去使用这个对象都是同一个…

第一百七十九回 自定义SlideImageSwitch

文章目录 1. 概念介绍2. 思路与方法2.1 实现思路 3. 代码与效果3.1 示例代码3.2 运行效果 4. 内容总结 我们在上一章回中介绍了"SlideSwitch组件"相关的内容&#xff0c;本章回中将介绍自定义SlideImageSwitch.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 概…

代码随想录算法训练营 ---第四十二天

今天开始学习 动态规划&#xff1a;背包问题 也是比较难的一部分了 动态规划&#xff1a;背包问题 理论基础 01背包&#xff08;二维数组&#xff09; 有n件物品和一个最多能背重量为w 的背包。第i件物品的重量是weight[i]&#xff0c;得到的价值是value[i] 。每件物品只能用…

网络运维与网络安全 学习笔记2023.11.25

网络运维与网络安全 学习笔记 第二十六天 今日目标 ACL原理与类型、基本ACL配置、高级ACL配置 高级ACL之ICMP、高级ACL之telnet ACL原理与类型 项目背景 为了企业的业务安全&#xff0c;要求不同部门对服务器有不同的权限 PC1不能访问Server PC2允许访问Server 允许其他所…

求集合的笛卡尔乘积

求集合的笛卡尔乘积 一&#xff1a;【实验目的】二&#xff1a;【实验内容】三&#xff1a;【实验原理】四&#xff1a;代码实现&#xff1a; 一&#xff1a;【实验目的】 通过编实现给定集合A和B的笛卡尔积CAA,DAB,EBA,FAAB,GA(A*B&#xff09;. 二&#xff1a;【实验内容】…

【Android Gradle】之Gradle入门及 wrapper 生成(一)

&#x1f604;作者简介&#xff1a; 小曾同学.com,一个致力于测试开发的博主⛽️&#xff0c;主要职责&#xff1a;测试开发、CI/CD 如果文章知识点有错误的地方&#xff0c;还请大家指正&#xff0c;让我们一起学习&#xff0c;一起进步。 &#x1f60a; 座右铭&#xff1a;不…

illuminate/database 使用 四

文档&#xff1a;Hyperf Database: Getting Started - Laravel 10.x - The PHP Framework For Web Artisans 因为hyperf使用illuminate/database&#xff0c;所以按照文章&#xff0c;看illuminate/database代码实现。 一、读写分离 根据文档读写的host可以分开。设置读写分…

系列十六、Spring IOC容器的扩展点

一、概述 Spring IOC容器的扩展点是指在IOC加载的过程中&#xff0c;如何对即将要创建的bean进行扩展。 二、扩展点 2.1、BeanDefinitionRegistryPostProcessor 2.1.1、概述 BeanDefinitionRegistryPostProcessor是bean定义的后置处理器&#xff0c;在BeanDefinition加载后&a…

142.【Nginx负载均衡-01】

Nginx_基础篇 (一)、Nginx 简介1.背景介绍(1).http和三大邮局协议(2).反向代理与正向代理 2.常见服务器对比(1).公司介绍(2).lls 服务器(3).Tomcat 服务器(4).Apache 服务器(5).Lighttpd 服务器(6).其他的服务器 3.Nginx的优点(1).速度更快、并发更高(2).配置简单&#xff0c;扩…