量化交易:因子风险暴露

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

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

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

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

通过对历史收益率进行建模,可以分析出收益中有多少是来自因子收益率,有多少来自资产特质波动(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 True
    else:
        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 True
    else:
        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 True
    else:
        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 True
    else:
        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])
        # 获取beta
        b = betas.loc[t][factor]
        # 获取主动风险
        AR = active_risk_squared.loc[t]
        # 估计当天的FMCAR
        FMCAR[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显示我们可以显著的拒绝其为正态分布,可见对于未来这些因素会导致多少风险暴露是很难估计的,所以在使用这些统计模型去估计风险暴露并以此为依据来对冲是需要万分小心的。

 

 

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Vue框架学习笔记——键盘事件

文章目录 前文提要键盘事件&#xff08;并不是所有按键都能绑定键盘事件&#xff09;常用的按键不同的tab和四个按键keyCode绑定键盘事件&#xff08;不推荐&#xff09;Vue.config.keyCode.自定义键名 键码 神奇的猜想div标签和click.enterbutton标签和click.enter 前文提要 …

定长子网划分和变长子网划分问题_二叉树解法_通俗易懂_配考研真题

引入:定长子网划分和变长子网划分的基本概念 定长子网划分和变长子网划分的基本概念 目前常用的子网划分&#xff0c;是基于CIDR的子网划分&#xff0c;也就是将给定的CIDR地址块划分为若干个较小的CIDR地址块。 定长子网划分: 使用同一个子网掩码来划分子网&#xff0c;因…

【版本管理 | Git】Git rebase 命令最佳实践!确定不来看看?

&#x1f935;‍♂️ 个人主页: AI_magician &#x1f4e1;主页地址&#xff1a; 作者简介&#xff1a;CSDN内容合伙人&#xff0c;全栈领域优质创作者。 &#x1f468;‍&#x1f4bb;景愿&#xff1a;旨在于能和更多的热爱计算机的伙伴一起成长&#xff01;&#xff01;&…

智能优化算法应用:基于斑点鬣狗算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于斑点鬣狗算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于斑点鬣狗算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.斑点鬣狗算法4.实验参数设定5.算法结果6.参考…

VM虚拟机中Ubuntu14.04安装VM tools后仍不能全屏显示

1、查看Ubuntu所支持的分辨率大小。 在终端处输入&#xff1a; xrandr&#xff0c;回车 2、输入你想设置的分辨率参数。 我设置的为1360x768&#xff0c;大家可以根据自己的具体设备设置。 在终端输入&#xff1a;xrandr -s 1360x768 注意&#xff1a;这里1360后边是字母 x 且…

<JavaEE> Thread线程类 和 Thread的常用方法

目录 一、Thread概述 二、构造方法 三、常用方法 1.1 getId()、getName()、getState()、getPririty() 1.2 start() 1.3 isDaemon()、setDaemon() 1.4 isAlive() 1.5 currentThread() 1.6 Interrupt()、interrupted()、isInterrupted() 1.6.1 方法一&#xff1a;添加共…

S25FL系列FLASH读写的FPGA实现

文章目录 实现思路具体实现子模块实现top模块 测试Something 实现思路 建议读者先对 S25FL-S 系列 FLASH 进行了解&#xff0c;我之前的博文中有详细介绍。 笔者的芯片具体型号为 S25FL256SAGNFI00&#xff0c;存储容量 256Mb&#xff0c;增强高性能 EHPLC&#xff0c;4KB 与 6…

Java中static、final、static final的区别

文章目录 finalstaticstatic final final final可以修饰&#xff1a;属性&#xff0c;方法&#xff0c;类&#xff0c;局部变量&#xff08;方法中的变量&#xff09; final修饰的属性的初始化可以在编译期&#xff0c;也可以在运行期&#xff0c;初始化后不能被改变。 final修…

nginx配置文件的简单结构

nginx的配置文件&#xff08;nginx.conf&#xff09;整体上可分为三个部分&#xff1a;全局块、events块、http块 区域职责全局块配置和nginx运行相关的全局配置events块配置和网络连接相关的配置http块配置代理、缓存、日志记录、虚拟主机等配置在http块中&#xff0c;可以包含…

python:傅里叶分析,傅里叶变换 FFT

使用python进行傅里叶分析&#xff0c;傅里叶变换 FFT 的一些关键概念的引入&#xff1a; 1.1.离散傅里叶变换&#xff08;DFT&#xff09; 离散傅里叶变换(discrete Fourier transform) 傅里叶分析方法是信号分析的最基本方法&#xff0c;傅里叶变换是傅里叶分析的核心&…

摆脱无用代码的负担:TreeShaking 的魔力

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

【教学类-06-12】20231126 (一)如何让加减乘除题目从小到大排序(以1-20之间加法为例,做正序排列用)

结果展示 优化后 优化前 背景需求&#xff1a; 生成列表 单独抽取显示题目排序方法 存在问题: 我希望 00 01 02……这样排序&#xff0c;但是实际上&#xff0c;除了第一个加数会从小到大排序&#xff0c;第二个被加数的第十位数和个位数都会从小到大排序&#xff0c;也就是…

NeoPreference延伸:为SharedPreferences配置项生成配置页面

代码地址&#xff1a;https://github.com/Nagi1225/NeoPreference.git 最初在开发NeoPreference这个SharedPreferences工具的时候&#xff0c;就期望完成三个目标&#xff1a; 代码简洁&#xff0c;新增配置项的时候一行代码&#xff08;最多两行&#xff09;&#xff1b;读写…

线程的常用方法-wait和notify以及线程的结束方式

再复习一下Java中的线程的状态图 wait和sleep的区别是&#xff1a;wait需要先持有锁&#xff08;wait需要再synchronized代码块中执行&#xff09;&#xff0c;执行后会让出锁。而sleep不需要先持有锁&#xff0c;执行后也不会释放锁&#xff08;有锁的话抱着锁睡觉&#xff09…

SpringBoot 环境使用 Redis + AOP + 自定义注解实现接口幂等性

目录 一、前言二、主流实现方案介绍2.1、前端按钮做加载状态限制&#xff08;必备&#xff09;2.2、客户端使用唯一标识符2.3、服务端通过检测请求参数进行幂等校验&#xff08;本文使用&#xff09; 三、代码实现3.1、POM3.2、application.yml3.3、Redis配置类3.4、自定义注解…

基于Haclon的标签旋转项目案例

项目要求&#xff1a; 图为HALCON附图“25interleaved_exposure_04”&#xff0c;里面为旋转的二维码标签&#xff0c;请将其旋转到水平位置。 项目知识&#xff1a; 在HALCON中进行图像平移和旋转通常有以下步骤&#xff1a; &#xff08;1&#xff09;通过hom_mat2d_ident…

jQuery_03 dom对象和jQuery对象的互相转换

dom对象和jQuery对象 dom对象 jQuery对象 在一个文件中同时存在两种对象 dom对象: 通过js中的document对象获取的对象 或者创建的对象 jQuery对象: 通过jQuery中的函数获取的对象。 为什么使用dom或jQuery对象呢&#xff1f; 目的是 要使用dom对象的函数或者属性 以及呢 要…

<JavaEE> 线程的五种创建方法 和 查看线程的两种方式

目录 一、线程的创建方法 1.1 继承 Thread -> 重写 run 方法 1.2 使用匿名内部类 -> 继承 Thread -> 重写 run 方法 1.3 实现 Runnable 接口 -> 重写 run 方法 1.4 使用匿名内部类 -> 实现 Runnable 接口 -> 重写 run 方法 1.5 使用 lambda 表达式 二…

Self Distillation 自蒸馏论文解读

paper&#xff1a;Be Your Own Teacher: Improve the Performance of Convolutional Neural Networks via Self Distillation official implementation&#xff1a; https://github.com/luanyunteng/pytorch-be-your-own-teacher 前言 知识蒸馏作为一种流行的压缩方法&#…

五种多目标优化算法(MOGWO、MOLPB、MOJS、NSGA3、MOPSO)求解微电网多目标优化调度(MATLAB代码)

一、多目标优化算法简介 &#xff08;1&#xff09;多目标灰狼优化算法MOGWO 多目标应用&#xff1a;基于多目标灰狼优化算法MOGWO求解微电网多目标优化调度&#xff08;MATLAB代码&#xff09;-CSDN博客 &#xff08;2&#xff09;多目标学习者行为优化算法MOLPB 多目标学习…