pandas

您所在的位置:网站首页 excel计算最小方差组合 pandas

pandas

2024-07-13 14:18| 来源: 网络整理| 查看: 265

目录

1. 蒙特卡洛方法绘制组合收益与风险散点图

2. 找出最小方差边界 

 方法一、 微积分+矩阵代数方法

方法二、 scipy 优化器

3. 找出最小方差组合(GMVP)

1. 蒙特卡洛方法绘制组合收益与风险散点图

随机设置10样本的权重,绘制100000个点,看最终形成的图形

2. 找出最小方差边界

用两种方法寻找:

方法一、 微积分+矩阵代数方法

方法二、 scipy 优化器

3. 找出最小方差组合(GMVP)

GMVP全称:Global Min Variance Portfolio, 即全局最小方差点

1. 蒙特卡洛方法绘制组合收益与风险散点图 import pandas as pd import numpy as np import matplotlib.pyplot as plt %matplotlib inline df_004 = pd.read_csv('600004.csv',encoding='utf-8') df_015 = pd.read_csv('600015.csv',encoding='utf-8') df_023 = pd.read_csv('600023.csv',encoding='utf-8') df_033 = pd.read_csv('600033.csv',encoding='utf-8') df_343 = pd.read_csv('600343.csv',encoding='utf-8') df_346 = pd.read_csv('600346.csv',encoding='utf-8') df_183 = pd.read_csv('600183.csv',encoding='utf-8') df_1398 = pd.read_csv('601398.csv',encoding='utf-8') df_050 = pd.read_csv('600050.csv',encoding='utf-8') df_000 = pd.read_csv('600000.csv',encoding='utf-8') df_004['ret_004'] = df_004['closePrice'].pct_change() df_004 = df_004.loc[:,['tradeDate','ret_004']] df_015['ret_015'] = df_015['closePrice'].pct_change() df_015 = df_015.loc[:,['tradeDate','ret_015']] df_023['ret_023'] = df_023['closePrice'].pct_change() df_023 = df_023.loc[:,['tradeDate','ret_023']] df_033['ret_033'] = df_033['closePrice'].pct_change() df_033 = df_033.loc[:,['tradeDate','ret_033']] df_343['ret_343'] = df_343['closePrice'].pct_change() df_343 = df_343.loc[:,['tradeDate','ret_343']] df_346['ret_346'] = df_346['closePrice'].pct_change() df_346 = df_346.loc[:,['tradeDate','ret_346']] df_183['ret_183'] = df_183['closePrice'].pct_change() df_183 = df_183.loc[:,['tradeDate','ret_183']] df_1398['ret_1398'] = df_1398['closePrice'].pct_change() df_1398 = df_1398.loc[:,['tradeDate','ret_1398']] df_050['ret_050'] = df_050['closePrice'].pct_change() df_050 = df_050.loc[:,['tradeDate','ret_050']] df_000['ret_000'] = df_000['closePrice'].pct_change() df_000 = df_000.loc[:,['tradeDate','ret_000']] ten_df = pd.merge(df_004,df_015,on='tradeDate') ten_df = pd.merge(ten_df,df_023,on='tradeDate') ten_df = pd.merge(ten_df,df_033,on='tradeDate') ten_df = pd.merge(ten_df,df_343,on='tradeDate') ten_df = pd.merge(ten_df,df_346,on='tradeDate') ten_df = pd.merge(ten_df,df_183,on='tradeDate') ten_df = pd.merge(ten_df,df_1398,on='tradeDate') ten_df = pd.merge(ten_df,df_050,on='tradeDate') ten_df = pd.merge(ten_df,df_000,on='tradeDate') ten_df.dropna(inplace=True) ten_df['tradeDate'] = pd.to_datetime(ten_df['tradeDate']) ten_df.set_index('tradeDate',inplace=True) ten_df.head()

def annualize_rets(returns,n_periods): ''' 给定一系列的收益率和期数,算出年化收益率 ''' # 每一期的平均收益 r_periodic_mean = ((1+returns).prod())**(1/returns.shape[0])-1 return (1+r_periodic_mean)**n_periods-1 def annualize_std(returns,n_periods): ''' 给定一系列的收益率,算出年化的标准差 ''' return returns.std()*np.sqrt(n_periods) def portfolio_return(weights,returns): ''' 计算投资组合收益率,weights和returns需要矩阵形式 weights是组合资产的权重 returns是组合中的资产年化收益率 ''' return weights.T @ returns def portfolio_vol(weights,covmat): ''' 计算投资组合风险(波动率),weights和covmat需要矩阵形式 covmat代表的是协方差矩阵 ''' return np.sqrt(weights.T @ covmat @ weights) annual_rets = annualize_rets(ten_df,252) annual_vols = annualize_std(ten_df,252) annual_cov = np.cov(ten_df,rowvar=False)*252 # 做一个简单的蒙特卡洛模拟,将10样本组合的图画出 pret = [] pvol = [] for p in np.arange(1000000): weights = np.random.random_sample(10) # 生成10个0到1之间的随机数 weights = weights/np.sum(weights) # 令7个权重相加等于1 pret.append(portfolio_return(weights,annual_rets)) pvol.append(portfolio_vol(weights,annual_cov)) ef = pd.DataFrame({'R':pret,'Var':pvol}) ax = ef.plot.scatter(x='Var',y='R',figsize=(8,6),color='blue')

 

2. 找出最小方差边界 

要找出最小方差边界,也就是要找出图中的红色线,也就是要找出落在红色线上的点是由哪些权重值计算得出的

换一种提法,就是给定一个目标收益,要使得方差最小的权重。以下用拉格朗日求极值求解该权重

 方法一、 微积分+矩阵代数方法 # 初步生成矩阵A mat_A = np.zeros((12,12)) mat_A

 

# 将协方差矩阵和1,-1,以及年均收益率等数据传入A矩阵 mat_A[:10,:10] = annual_cov mat_A[:10,10] = -np.ones(10) mat_A[:10,11] = -annual_rets mat_A[10,:10] = np.ones(10) mat_A[11,:10] = annual_rets mat_A = np.matrix(mat_A) mat_A

 

# 生成A矩阵的逆矩阵 A_inv = mat_A.I A_inv

 

# 生成 b 向量,设目标收益为0.08 r_star = 0.08 b = np.zeros(12) b[10] = 1 b[11] = r_star b

 

# 求解w向量 w = A_inv @ b.T # 把b向量转置成列向量才能相乘 w

 

# 将w中的后两个分量去掉,得到我们需要的权重 weights_ = w[0,:10] weights_

 

# 计算该产品的收益率、方差和标准差(风险水平),并转成标量 port_ret = np.asscalar(weights_@annual_rets) port_var = np.asscalar(weights_@annual_cov@weights_.T) port_vol = port_var**0.5 port_ret,port_var,port_vol # out: (0.08000000000000002, 0.03545791214926389, 0.18830271413143224) # 也可以使用之前写好的方程计算收益与风险 portfolio_return(weights_.T,annual_rets) # out: array([0.08]) portfolio_vol(weights_.T,annual_cov) # out: matrix([[0.18830271]])

将以上求解内容形成一个函数

def normal_minimize_vol(target_return,annual_rets,covmat): ''' 最小方差边界函数-微积分矩阵代数方法 target_return 为客户所要求的收益率水平 annual_rets 代表组合中的资产的年化收益率 covmat 代表资产之间的协方差矩阵 ''' n = covmat.shape[0] mat_A = np.zeros((n+2,n+2)) # 将协方差矩阵和1,-1,以及年均收益率等数据传入A矩阵 mat_A[:n,:n] = covmat mat_A[:n,n] = -np.ones(n) mat_A[:n,n+1] = -annual_rets mat_A[n,:n] = np.ones(n) mat_A[n+1,:n] = annual_rets mat_A = np.matrix(mat_A) # 生成A矩阵的逆矩阵 A_inv = mat_A.I # 生成b向量 b = np.zeros(n+2) b[10] = 1 b[n+1] = target_return # 求解w向量 w = A_inv @ b.T # 把b向量转置成列向量才能相乘 # 将w中的后两个分量去掉,得到需要的权重 weights_ = w[0,:10] return weights_ normal_minimize_vol(0.08,annual_rets,annual_cov)

 

看求出的权重结果,里面存在负数,权重为负数意味着要买空,在实际操作中,买空股票的操作困难,所以使用该方法求解的权重值在理论上成立。要在实际操作中使用,需要增加一个约束条件权重不能小于0,使用scipy优化器方法可以在增加这个约束条件下求解最小方差边界。

以上缺点暂且不提,先看以下用该方法绘制出的最小方差边界

# 绘制最小方差边界 prets_normal = [] pvols_normal = [] target_normal = np.linspace(annual_rets.min(),annual_rets.max(),30) weights = [normal_minimize_vol(target_returns,annual_rets,annual_cov) for target_returns in target_normal] for w in weights: prets_normal.append(portfolio_return(w.T,annual_rets)[0]) pvols_normal.append(portfolio_vol(w.T,annual_cov)[0,0]) ef = pd.DataFrame({'R':prets_normal,'Var':pvols_normal}) ef.plot.line(x='Var',y='R',style='.-')

 

方法二、 scipy 优化器 def minimize_vol(target_return,annual_rets,covmat): ''' 最小方差边界函数 target_return 为客户所要求的收益率水平 annual_rets 代表组合中的资产的年化收益率 covmat 代表资产之间的协方差矩阵 ''' from scipy.optimize import minimize n = annual_rets.shape[0] init_guess = np.repeat(1/n,n) bounds = ((0.0,1.0),)*n #每个资产的权重在0~1之间 weights_sum_to_1 = {'type':'eq','fun': lambda weights:np.sum(weights)-1} return_is_target = {'type':'eq','args':(annual_rets,),'fun': lambda weights,annual_rets: portfolio_return(weights,annual_rets)-target_return} weights = minimize(portfolio_vol,init_guess,args=(covmat,),method='SLSQP',bounds=bounds,constraints=(weights_sum_to_1,return_is_target)) return weights.x resweights = minimize_vol(0.08,annual_rets,annual_cov)

 

# 画出最小方差边界 def plot_ef(n_points,rets,cov): ''' 画出有效边界的函数 n_points 需要画的点的数量 rets 组合资产的年化收益率 cov 代表资产之间的协方差矩阵 ''' prets = [] pvols = [] target_rs = np.linspace(rets.min(),rets.max(),n_points) weights = [minimize_vol(target_returns,rets,cov) for target_returns in target_rs] for w in weights: prets.append(portfolio_return(w,rets)) pvols.append(portfolio_vol(w,cov)) ef = pd.DataFrame({'R':prets,'Var':pvols}) return ef.plot.line(x='Var',y='R',style='.-') plot_ef(30,annual_rets,annual_cov)

 

3. 找出最小方差组合(GMVP) # GMVP: Global Min Variance Portfolio def get_gmvp(covmat): ''' 寻找全局最小方差点 covmat 代表资产之间的协方差矩阵 ''' from scipy.optimize import minimize n = covmat.shape[0] init_guess = np.repeat(1/n,n) bounds = ((0.0,1.0),)*n #每个资产的权重在0~1之间 weights_sum_to_1 = {'type':'eq','fun': lambda weights:np.sum(weights)-1} weights = minimize(portfolio_vol,init_guess,args=(covmat,),method='SLSQP',bounds=bounds,constraints=(weights_sum_to_1)) return weights.x gmvp_10samples = get_gmvp(annual_cov) ret_gmvp_10samples = portfolio_return(gmvp_10samples,annual_rets) ret_gmvp_10samples # out: 0.07938558348434649 vol_gmvp_10samples = portfolio_vol(gmvp_10samples,annual_cov) vol_gmvp_10samples # out: 0.18946508819209906 ax = plot_ef(30,annual_rets,annual_cov) ax.plot(vol_gmvp_10samples,ret_gmvp_10samples,color='red',marker="*",markersize=20)



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3