对多投资策略的组合进行分析
导入测试数据:
import pandas as pd import numpy as np StockPrices = pd.DataFrame() StockPrices = pd.read_excel('gupiao1.xlsx',index_col=[0]) StockPrices.index.name = '日期' print(StockPrices.head())
计算收益率:
# 计算每日收益率,并丢弃缺失值 StockReturns = StockPrices.pct_change().dropna() # 打印前5行数据 print(StockReturns.head())
结果:
一、给定权重的投资组合:
import matplotlib.pyplot as plt # 将收益率数据拷贝到新的变量 stock_return 中,这是为了后续调用的方便 stock_return = StockReturns.copy() # 设置组合权重,存储为numpy数组类型 portfolio_weights = np.array([0.32, 0.15, 0.10, 0.18, 0.15, 0.10]) StockReturns['Portfolio'] = WeightedReturns.sum(axis=1) print(StockReturns.head())
绘制组合收益随时间变化的图
注意rcParams的使用是为了图形中的坐标不显示乱码
print(StockReturns.head()) import matplotlib matplotlib.rcParams['font.family'] = 'SimHei' matplotlib.rcParams['font.size'] = 10 matplotlib.rcParams['axes.unicode_minus']=False StockReturns.Portfolio.plot() plt.show()
定义累积收益曲线绘制函数cumulative_returns_plot(),并绘制给定权重投资组合的累积收益曲线
def cumulative_returns_plot(name_list): for name in name_list: CumulativeReturns = ((1+StockReturns[name]).cumprod()-1) CumulativeReturns.plot(label=name) plt.legend() plt.show() # 计算累积的组合收益,并绘图 cumulative_returns_plot(['Portfolio'])
二、等权重的投资组合:
# 设置投资组合中股票的数目,有6只产品 numstocks = 6 # 平均分配每一项的权重 portfolio_weights_ew = np.repeat(1/numstocks, numstocks) # 计算等权重组合的收益 StockReturns['Portfolio_EW'] = stock_return.mul(portfolio_weights_ew, axis=1).sum(axis=1) # 打印前5行数据 print(StockReturns.head()) # 绘制累积收益曲线 cumulative_returns_plot(['Portfolio', 'Portfolio_EW'])
三、投资组合的相关性分析:
# 计算相关矩阵 correlation_matrix = stock_return.corr() # 输出相关矩阵 print(correlation_matrix)
矩阵中每一个元素都是其对应股票的相关系数,取值从-1到1,正数代表正相关,负数代表负相关。
我们观察到矩阵的对角线永远是1,因为自己和自己当然是完全相关的。另外相关矩阵也是对称的,即上三角和下三角呈镜像对称。
为了便于观察,可以将数值的相关矩阵用热图的形式展现出来。以下采用了 seaborn 包来绘制热图
import seaborn as sns #创建热图 sns.heatmap(correlation_matrix,annot=True,cmap='rainbow',linewidths=1.0,annot_kws={'size':8}) plt.xticks(rotation=0) plt.yticks(rotation=75) plt.show()
四、投资组合的协方差矩阵
相关系数只反应了股票之间的线性关系,但并不能告诉我们股票的波动情况,而协方差矩阵则包含这一信息。可使用pandas数据框内建的 .cov()
方法来计算协方差矩阵。
注:数据周期为周,一年52周的交易
# 计算协方差矩阵 cov_mat = stock_return.cov() # 年化协方差矩阵 cov_mat_annual = cov_mat * 52 # 输出协方差矩阵 print(cov_mat_annual)
投资组合的风险可以用标准差来衡量,只要知道组合权重和协方差矩阵,就可以通过以下公式进行计算。
在NumPy中,使用.T
属性对数组进行转置,np.dot()
函数用于计算两个数组的点积。
portfolio_volatility = np.sqrt(np.dot(portfolio_weights.T, np.dot(cov_mat_annual, portfolio_weights))) print(portfolio_volatility)
结果:0.05479023349164157
五、探索股票的最有组合
采用蒙特卡洛模拟来进行分析,也就是随机生成一组权重,计算该组合下的收益和标准差,重复这一过程许多次(比如1万次),将每一种组合的收益和标准差绘制成散点图。
# 设置模拟的次数 number = 10000 # 设置空的numpy数组,用于存储每次模拟得到的权重、收益率和标准差 random_p = np.empty((number, 8)) # 设置随机数种子,这里是为了结果可重复 np.random.seed(8) #循环模拟10000次随机的投资组合 for i in range(number): #生成6个随机数,并归一化,得到一组随机的权重数据 random6=np.random.random(6) random_weight=random6/np.sum(random6) #计算年平均收益率 mean_return=stock_return.mul(random_weight,axis=1).sum(axis=1).mean() annual_return=(1+mean_return)**52-1 #计算年化标准差,也成为波动率 random_volatility=np.sqrt(np.dot(random_weight.T,np.dot(cov_mat_annual,random_weight))) #将上面生成的权重,和计算得到的收益率、标准差存入数组random_p中 random_p[i][:6]=random_weight random_p[i][6]=annual_return random_p[i][7]=random_volatility RandomPortfolios=pd.DataFrame(random_p) #设置数据框RandomPortfolios每一列的名称 ticker_list = ['1中性', '2中性', '3中性', '4CTA', '5CTA', '6指数'] RandomPortfolios.columns=[ticker +'_weight' for ticker in ticker_list]+['Returns','Volatility'] #绘制散点图 RandomPortfolios.plot('Volatility','Returns',kind='scatter',alpha=0.3) plt.show()
投资的本质是在风险和收益之间做出选择,上图正是刻画了这两个要素。其中每一个点都代表着一种投资组合的情况,横坐标是代表风险的标准差,纵坐标是收益率。
Markowitz投资组合理论认为,理性的投资者总是在给定风险水平下对期望收益进行最大化,或者是在给定收益水平下对期望风险做最小化。反映在图中也就是红色曲线所示的有效边界,只有在有效边界上的点才是最有效的投资组合。
现在我们知道,理性的投资者都会选择有效边界上的投资组合。
六、投资风险最小的组合:
# 找到标准差最小数据的索引值 min_index = RandomPortfolios.Volatility.idxmin() # 在收益-风险散点图中突出风险最小的点 RandomPortfolios.plot('Volatility', 'Returns', kind='scatter', alpha=0.3) x = RandomPortfolios.loc[min_index,'Volatility'] y = RandomPortfolios.loc[min_index,'Returns'] plt.scatter(x, y, color='red') #将该点坐标显示在图中并保留四位小数 plt.text(np.round(x,4),np.round(y,4),(np.round(x,4),np.round(y,4)),ha='left',va='bottom',fontsize=10) plt.show()
获取风险最小组合的权重如下:
# 提取最小波动组合对应的权重, 并转换成Numpy数组 GMV_weights = np.array(RandomPortfolios.iloc[min_index, 0:numstocks]) # 计算GMV投资组合收益 StockReturns['Portfolio_GMV'] = stock_return.mul(GMV_weights, axis=1).sum(axis=1) #输出风险最小投资组合的权重 print(GMV_weights)
结果:[0.28638297 0.03534933 0.21344995 0.44503954 0.00804945 0.01172876]
七、投资最有组合
(1)夏普比率
夏普比率(Sharpe Ratio)是由诺贝尔奖得主威廉·夏普提出的,用以帮助投资者比较投资的回报和风险。理性的投资者一般都是固定所能承受的风险,追求最大的回报;或者在固定预期回报,追去最小的风险。所以夏普比率计算的是,每承受一单位的总风险所产生的超额回报。计算公式如下:
分子计算了差值,说的是将某项投资与代表整个投资类别的基准进行比较,得到超额回报。分母标准差代表收益的波动率,对应着风险,因为波动越大预示着风险越高。
只要将超额回报的均值除以其标准差,即可得到衡量回报和风险的夏普比率。另外需再乘上sqrt(252) (一年有252个交易日),得到年化的夏普比率。
(2)夏普最优组合的选择
其实我们更想在收益和风险之间找到平衡点,夏普比率这个变量能帮我做出更好的决策,它计算的是每承受一单位的风险所产生的超额回报。
我们首先来计算上述蒙特卡洛模拟的组合所对应的夏普比率,并将之作为第三个变量绘制在收益-风险的散点图中,这里采用颜色这一视觉线索来表征夏普比率。
# 设置无风险回报率为0 risk_free = 0 # 计算每项资产的夏普比率 RandomPortfolios['Sharpe'] = (RandomPortfolios.Returns - risk_free) / RandomPortfolios.Volatility # 绘制收益-标准差的散点图,并用颜色描绘夏普比率 plt.scatter(RandomPortfolios.Volatility, RandomPortfolios.Returns, c=RandomPortfolios.Sharpe) plt.colorbar(label='Sharpe Ratio') plt.show()
我们发现散点图上沿的组合具有较高的夏普比率。接着再找到夏普比率最大的组合,将其绘制在收益-风险的散点图中。
# 找到夏普比率最大数据对应的索引值 max_index = RandomPortfolios.Sharpe.idxmax() # 在收益-风险散点图中突出夏普比率最大的点 RandomPortfolios.plot('Volatility', 'Returns', kind='scatter', alpha=0.3) x = RandomPortfolios.loc[max_index,'Volatility'] y = RandomPortfolios.loc[max_index,'Returns'] plt.scatter(x, y, color='red') #将该点坐标显示在图中并保留四位小数 plt.text(np.round(x,4),np.round(y,4),(np.round(x,4),np.round(y,4)),ha='left',va='bottom',fontsize=10) plt.show()
获取夏普比率最大组合的权重如下:
# 提取最大夏普比率组合对应的权重,并转化为numpy数组 MSR_weights = np.array(RandomPortfolios.iloc[max_index, 0:numstocks]) # 计算MSR组合的收益 StockReturns['Portfolio_MSR'] = stock_return.mul(MSR_weights, axis=1).sum(axis=1) #输出夏普比率最大的投资组合的权重 print(MSR_weights)
结果:[0.39315317 0.0287276 0.0684143 0.00739371 0.33309333 0.16921788]
本文参考:
https://asialee.blog.csdn.net/article/details/89417750