看题主的组合才3只股票就搞得很复杂了。。。
这两天刚用python做了下投资组合理论的验证。要是会点编程,别说A、B、C三只股票了,就是整个上证+深证三千多只股票也没问题的。
原文见:【组合管理】——投资组合理论(有效前沿)
源码都贴上了,现在这时代不会点编程都吃不饱饭了,感兴趣的可以搬去用不谢。
------------------------------------------2016.2.26更新----------------------------------------------------
ps:有人问到这个分析是在哪儿做的。我也是对量化策略感兴趣,最近用JoinQuant的平台在做些研究,顺便分享出来和大家一起交流。
--------------------------------------------------------------------------------------------------------------
正态性检验和蒙特卡洛完成投资组合优化by 陈小米。
最近一直在思考怎样有效的配置资产组合。 很多时候根据条件选好股票池之后,通常简单粗暴的等分仓位给每只股票。 其实,这个过程中有很多可以优化的空间。
下面,给大家分享一下如何运用有效前沿进行资产组合优化。
PART ONE: 正态性检验这部分是附赠福利。只对资产组合优化感兴趣的朋友可以直接跳到PART TWO。
(社区回答字数限制,这部分暂且删除,感兴趣的到原文链接自己看哦~)
PART TWO:均值-方差投资组合理论该理论基于用均值和方差来表述组合的优劣的前提。将选取几只股票,用蒙特卡洛模拟初步探究组合的有效前沿。
通过最大Sharpe和最小方差两种优化来找到最优的资产组合配置权重参数。
最后,刻画出可能的分布,两种最优以及组合的有效前沿。
1.选取几只感兴趣的股票000413 东旭光电,000063 中兴通讯,002007 华兰生物,000001 平安银行,000002 万科A
并比较一下数据(2015-01-01至2015-12-31)
In [102]:- stock_set = ['000413.XSHE','000063.XSHE','002007.XSHE','000001.XSHE','000002.XSHE']noa = len(stock_set)df = get_price(stock_set, start_date, end_date, 'daily', ['close'])data = df['close']#规范化后时序数据(data/data.ix[0]*100).plot(figsize = (8,5))
复制代码 Out[102]:- [/code][img]https://beijingoptbbs.oss-cn-beijing.aliyuncs.com/zh/521637-a2788e606c9ae972dcc5d49d0785c04f.jpg[/img]
- [b]2.计算不同证券的均值、协方差[/b]每年252个交易日,用每日收益得到年化收益。
- 计算投资资产的协方差是构建资产组合过程的核心部分。运用pandas内置方法生产协方差矩阵。
- In [103]:
- [code]returns = np.log(data / data.shift(1))returns.mean()*252
复制代码 Out[103]:- 000413.XSHE 0.184516000063.XSHE 0.176790002007.XSHE 0.309077000001.XSHE -0.102059000002.XSHE 0.547441dtype: float64
复制代码 In [104]:Out[104]:
![]()
3.给不同资产随机分配初始权重由于A股不允许建立空头头寸,所有的权重系数均在0-1之间
In [105]:- weights = np.random.random(noa)weights /= np.sum(weights)weights
复制代码 Out[105]:- array([ 0.37505798, 0.21652754, 0.31590981, 0.06087709, 0.03162758])
复制代码 4.计算预期组合年化收益、组合方差和组合标准差
In [106]:- np.sum(returns.mean()*weights)*252
复制代码 Out[106]:In [107]:- np.dot(weights.T, np.dot(returns.cov()*252,weights))
复制代码 Out[107]:In [108]:- np.sqrt(np.dot(weights.T, np.dot(returns.cov()* 252,weights)))
复制代码 Out[108]:5.用蒙特卡洛模拟产生大量随机组合进行到此,我们最想知道的是给定的一个股票池(证券组合)如何找到风险和收益平衡的位置。
下面通过一次蒙特卡洛模拟,产生大量随机的权重向量,并记录随机组合的预期收益和方差。
In [111]:- port_returns = []port_variance = []for p in range(4000): weights = np.random.random(noa) weights /=np.sum(weights) port_returns.append(np.sum(returns.mean()*252*weights)) port_variance.append(np.sqrt(np.dot(weights.T, np.dot(returns.cov()*252, weights))))port_returns = np.array(port_returns)port_variance = np.array(port_variance)#无风险利率设定为4%risk_free = 0.04plt.figure(figsize = (8,4))plt.scatter(port_variance, port_returns, c=(port_returns-risk_free)/port_variance, marker = 'o')plt.grid(True)plt.xlabel('excepted volatility')plt.ylabel('expected return')plt.colorbar(label = 'Sharpe ratio')
复制代码 Out[111]:- [/code][img]https://beijingoptbbs.oss-cn-beijing.aliyuncs.com/zh/521637-b19bfb6c47f86b9d0133ffd9abaa2021.jpg[/img]
- [b]6.投资组合优化1——sharpe最大[/b]建立statistics函数来记录重要的投资组合统计数据(收益,方差和夏普比)
- 通过对约束最优问题的求解,得到最优解。其中约束是权重总和为1。
- In [115]:
- [code]def statistics(weights): weights = np.array(weights) port_returns = np.sum(returns.mean()*weights)*252 port_variance = np.sqrt(np.dot(weights.T, np.dot(returns.cov()*252,weights))) return np.array([port_returns, port_variance, port_returns/port_variance])#最优化投资组合的推导是一个约束最优化问题import scipy.optimize as sco#最小化夏普指数的负值def min_sharpe(weights): return -statistics(weights)[2]#约束是所有参数(权重)的总和为1。这可以用minimize函数的约定表达如下cons = ({'type':'eq', 'fun':lambda x: np.sum(x)-1})#我们还将参数值(权重)限制在0和1之间。这些值以多个元组组成的一个元组形式提供给最小化函数bnds = tuple((0,1) for x in range(noa))#优化函数调用中忽略的唯一输入是起始参数列表(对权重的初始猜测)。我们简单的使用平均分布。opts = sco.minimize(min_sharpe, noa*[1./noa,], method = 'SLSQP', bounds = bnds, constraints = cons)opts
复制代码 Out[115]:- status: 0 success: True njev: 4 nfev: 28 fun: -1.1623048291871221 x: array([ -3.60840218e-16, 2.24626781e-16, 1.63619563e-01, -2.27085639e-16, 8.36380437e-01]) message: 'Optimization terminated successfully.' jac: array([ 1.81575805e-01, 5.40387481e-01, 8.18073750e-05, 1.03137662e+00, -1.60038471e-05, 0.00000000e+00]) nit: 4
复制代码 得到的最优组合权重向量为:
In [116]:- opts['x'].round(3)
复制代码 Out[116]:- array([-0. , 0. , 0.164, -0. , 0.836])
复制代码 sharpe最大的组合3个统计数据分别为:
In [117]:- #预期收益率、预期波动率、最优夏普指数statistics(opts['x']).round(3)
复制代码 Out[117]:- array([ 0.508, 0.437, 1.162])
复制代码 7.投资组合优化2——方差最小接下来,我们通过方差最小来选出最优投资组合。
In [118]:- #但是我们定义一个函数对 方差进行最小化def min_variance(weights): return statistics(weights)[1]optv = sco.minimize(min_variance, noa*[1./noa,],method = 'SLSQP', bounds = bnds, constraints = cons)optv
复制代码 Out[118]:- status: 0 success: True njev: 7 nfev: 50 fun: 0.38542969450547221 x: array([ 1.14787640e-01, 3.28089742e-17, 2.09584008e-01, 3.53487044e-01, 3.22141307e-01]) message: 'Optimization terminated successfully.' jac: array([ 0.3851725 , 0.43591119, 0.3861807 , 0.3849672 , 0.38553924, 0. ]) nit: 7
复制代码 方差最小的最优组合权重向量及组合的统计数据分别为:
In [119]:- optv['x'].round(3)
复制代码 Out[119]:- array([ 0.115, 0. , 0.21 , 0.353, 0.322])
复制代码 In [120]:- #得到的预期收益率、波动率和夏普指数statistics(optv['x']).round(3)
复制代码 Out[120]:- array([ 0.226, 0.385, 0.587])
复制代码
8.组合的有效前沿有效前沿有既定的目标收益率下方差最小的投资组合构成。
在最优化时采用两个约束,1.给定目标收益率,2.投资组合权重和为1。
In [138]:- def min_variance(weights): return statistics(weights)[1]#在不同目标收益率水平(target_returns)循环时,最小化的一个约束条件会变化。target_returns = np.linspace(0.0,0.5,50)target_variance = []for tar in target_returns: cons = ({'type':'eq','fun':lambda x:statistics(x)[0]-tar},{'type':'eq','fun':lambda x:np.sum(x)-1}) res = sco.minimize(min_variance, noa*[1./noa,],method = 'SLSQP', bounds = bnds, constraints = cons) target_variance.append(res['fun'])target_variance = np.array(target_variance)
复制代码 下面是最优化结果的展示。
叉号:构成的曲线是有效前沿(目标收益率下最优的投资组合)
红星:sharpe最大的投资组合
黄星:方差最小的投资组合
In [139]:- plt.figure(figsize = (8,4))#圆圈:蒙特卡洛随机产生的组合分布plt.scatter(port_variance, port_returns, c = port_returns/port_variance,marker = 'o')#叉号:有效前沿plt.scatter(target_variance,target_returns, c = target_returns/target_variance, marker = 'x')#红星:标记最高sharpe组合plt.plot(statistics(opts['x'])[1], statistics(opts['x'])[0], 'r*', markersize = 15.0)#黄星:标记最小方差组合plt.plot(statistics(optv['x'])[1], statistics(optv['x'])[0], 'y*', markersize = 15.0)plt.grid(True)plt.xlabel('expected volatility')plt.ylabel('expected return')plt.colorbar(label = 'Sharpe ratio')
复制代码 Out[139]:
[code][/code]![]()
|