目录
概念与推导
代码
import numpy as np
import pandas as pd
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_004['ret_004'] = df_004['closePrice'].pct_change()
df_015['ret_015'] = df_015['closePrice'].pct_change()
df_004 = df_004.loc[:,['tradeDate','ret_004']]
df_015 = df_015.loc[:,['tradeDate','ret_015']]
two_df = pd.merge(df_004,df_015,on='tradeDate')
two_df['tradeDate'] = pd.to_datetime(two_df['tradeDate'])
two_df.set_index('tradeDate',inplace=True)
two_df.dropna(inplace=True)
two_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需要矩阵形式
'''
return weights.T @ returns
def portfolio_vol(weights,covmat):
'''
计算投资组合风险(波动率),weights和covmat需要矩阵形式
covmat代表的是协方差矩阵
'''
return np.sqrt(weights.T @ covmat @ weights)
# 计算年化收益率和年化波动率
annual_rets = annualize_rets(two_df,252)
annual_vols = annualize_std(two_df,252)
annual_cov = np.cov(two_df,rowvar=False)*252 # rowvar=False取列
绘制有效边界,也叫有效前沿曲线。该曲线是不同权重下的收益与风险
# 取20个点,即生成20个权重数组,用以计算20中权重下的收益与风险,20个收益与风险的结果形成20个点,将这20个点连线
n_points = 20
n_weights = [np.array([w,1-w]) for w in np.linspace(0,1,n_points)] # 线性空间中,20个等分的点
n_weights
pret = []
pvol = []
for w in n_weights:
pret.append(portfolio_return(w,annual_rets))
pvol.append(portfolio_vol(w,annual_cov))
ef = pd.DataFrame({'R':pret,'Var':pvol})
ax = ef.plot(x='Var',y='R',marker='o',figsize=(8,6))
ax
在曲线中找到最小方差组合的点
# 找出最小方差组合
v_a = annual_cov[0,0]
v_b = annual_cov[1,1]
cov_ab = annual_cov[0,1]
# 计算最小方差组合的权重
minw_a = (v_b-cov_ab)/(v_a+v_b-2*cov_ab)
minw_b = 1-minw_a
minw_a,minw_b
# out: (0.5109729204649284, 0.48902707953507163)
min_weights = np.array([minw_a,minw_b])
# 计算最小方差组合的收益与风险
min_ret = portfolio_return(min_weights,annual_rets)
min_vol = portfolio_vol(min_weights,annual_cov)
min_ret,min_vol
# out: (0.006665607147349858, 0.30647044458064293)
# 在曲线中标记出最小方差组合对应的位置
ax = ef.plot(x='Var',y='R',marker='o',figsize=(8,6))
ax.plot(min_vol,min_ret,color='red',marker='*',markersize=20)