投资优化 续 发表于 2018-04-07 | 分类于 py-finance | 阅读次数 12345678910111213141516蒙特卡洛模拟 S0 =100. r =0.05 sigma =0.2 T =1.0 M= 50 1 =250000 生成 25 万条路 径,每条有 50个时间步 def gen_monte(): dt = T / M S = np.zeros((M + 1, I), np.float64) S[0] = S0 for t in range(1, M + 1): rand = np.random.standard_normal(I) rand = (rand-rand.mean())/rand.std() S[t] = S[t - 1] * np.exp((r - 0.5 * sigma ** 2) * dt + sigma * np.sqrt(dt) * rand) $\textstyle\sum_{}w_i\;=1$, $\textstyle w_i\geq\;0$ 1234def rand_w(split=5): w = np.random.random(split) w /= np.sum(w) return w 预期收益 252年化 1np.sum(rets.mean() * weight * 252) 预期投资方差 12var = np.dot(weights.T, np.dot(rets.cov() * 252, weights)) std = np.sqrt(var) 123456789101112131415161718192021222324252627282930313233343536373839404142优化组合 夏普指数(即预期投资组合超额收益) 投资收益率超过无风险利率 rf 的部分除以预期投资组合标准差。为了简单起见,我们假定 rf=0。 rf =0 def statistics(weights): """ Return portfolio statistics :param weights: weights for different securities in portfolio :return: pret:float expected portfolio return pvol:float expected portfolio volatility pret/pvol:float Sharpe ratio for rf=0 """ weights = np.array(weights) pret = np.sum(rets.mean() * weights) * 252 pvol = np.sqrt(np.dot(weights.T, np.dot(rets.cov() * 252, weights))) return np.array([pret, pvol, pret-rf / pvol]) import scipy.optimize as sco def min_func_sharpe(weights): return -statistics(weights)[2] # 约束是所有参数(权重)的总和为1。 这可以用minimize函数的约定表达如下 cons = ({'type': 'eq', 'fun': lambda x: np.sum(x) - 1}) # 我们还将参数值(权重)限制在0和l之间。 这些值以多个元组组成的一个元组形式提供给最小化函数: bnds = tuple((0, 1) for x in range(noa)) # 优化函数调用中忽略的唯一输入是起始参数列表(对权重的初始猜测)。我们简单地使用平均分布: noa * [1. / noa, ] # [0.2, 0.2, 0.2, 0.2, 0.2] opts = sco.minimize(min_func_sharpe, noa * [1. / noa, ], method='SLSQP', bounds=bnds, constraints=cons) statistics(opts['x'].round(3)) # array([ 0.22201418, 0.28871174, 0.76898216]) # 预期收益率约为22.2%. 预期被动率约为28.9%, 得到的最优夏普指数为0.77 有效边界 1234567891011目标收益率水平下波动率最小 预期收益tret trets = np.linspace(0.0, 0.25, 50) tvols = [] bnds = tuple((0, 1) for x in weights) for tret in trets: cons = ({'type': 'eq', 'fun': lambda x: statistics(x)[0] - tret}, {'type': 'eq', 'fun': lambda x: np.sum(x) - 1}) res = sco.minimize(min_func_port, noa * [1. / noa, ], method='SLSQP', bounds=bnds, constraints=cons) tvols.append(res['fun']) tvols = np.array(tvols) 资本市场线 12345678910111213141516171819202122232425262728293031323334353637import scipy.interpolate as sci ind = np.argmin(tvols) evols = tvols[ind:] erets = trets[ind:] tck = sci.splrep(evols, erets) # 通过这条数值化路径,最终可以为有效边界定义一个连续可微函数 # 和对应的一阶导数函数df(x): def f(x): """ 有效边界 插值逼近 """ return sci.splev(x, tck, der=0) def df(x): """ 有效边界函数的一阶导数。 """ return sci.splev(x, tck, der=1) #我们所寻求的是函数 t(x)=α+b.x,描述穿过风险-收益空间中无风险资产、与有效边界 相切的一条值线 # 定义一个函数,返回给定参数集p=(a,b,x) def equations(p, rf=0.01): eq1 = rf - p[0] eq2 = rf + p[1] * p[2] - f(p[2]) eq3 = p[1]-df(p[2]) return eq1,eq2,eq3 # 数值优化得到如下的值 #无风险利率为a = 1%时的资本市场线和相切的投资组合 opt=sco.fsolve(equations,[0.01,0.5,0.15]) 123456cons = ({'type': 'eq', 'fun': lambda x: statistics(x)[0] - f(opt[2])}, {'type': 'eq', 'fun': lambda x: np.sum(x) - 1}) res = sco.minimize(min_func_port, noa * [1. / noa, ], method='SLSQP', bounds=bnds, constraints=cons) res['x'].round(3) # array([ 0. , 0. , 0. , 0.703, 0.297]) 本文作者: wyx 本文链接: https://github.com/blog/2018/04/07/%E6%8A%95%E8%B5%84%E4%BC%98%E5%8C%96-%E7%BB%AD 版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 3.0 许可协议。转载请注明出处!