首先选取沪深股票市场,本人比较关注的12只股票:
000002 万科A,600566 济川药业,300051 三五互联,002039 黔源电力,600872 中炬高新,300324 旋极信息,600885 宏发股份,600382 广东明珠,000732 泰和集团,002174 游族网络,000915 山大华特,002415 海康威视
备注: 如果是基金经理,则会有研究部门推荐的股票选择池
程序运行的得到结论如下:
1. 当投资组合的sharpe值最大时,投资组合为:
41.2%的万科A,10.5%的广东明珠,38.2%的山大华特,10.1%的海康威视
该组合的未来预期年化收益为:21.4%
该组合的预期年化波动率为:29.5%
该组合的sharpe指数为0.725
2. 当投资组合的波动最小时,投资组合为:
34.5%的万科A,17.9%的济川药业,24.6%的黔源电力,2%的旋极信息,1%的宏发股份,9.4%的泰和集团,0.8%的游族网络,9.8%的海康威视
该组合的未来预期年化收益为:3.7%
该组合的预期年化波动率为:22.6%
该组合的sharpe指数为0.163
相关输出图表如下:
图1:关注的12只股票从2016-01-01到2016-12-01的归一化股价走势
图2:10万次蒙特卡洛模拟计算,得到各种投资组合以及相应收益率和波动率
图3:有效前沿、最优投资组合的图
#叉号:构成的曲线是有效前沿(efficient frontier,目标收益率下最优的投资组合)
#红星:夏普值最大的投资组合
#黄星:方差最小的投资组合

程序源代码以及详细注释说明如下:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import pandas.io.data as web
symbols = ['000002.sz','600566.ss','300051.sz','002039.sz','600872.ss','300324.sz',
'600885.ss','600382.ss','000732.sz','002174.sz','000915.sz','002415.sz']
noa = len(symbols)
data = pd.DataFrame()
for sym in symbols:
data[sym] = web.DataReader(sym, data_source='yahoo',start='2016-01-01',
end='2016-12-01')['Adj Close']
data.columns = symbols
data.head(5)
(data / data.ix[0] * 100).plot(figsize=(16, 10), grid=True)
returns = np.log(data / data.shift(1))
returns.mean()*252
returns.cov()*252
weights = np.random.random(noa)
weights /= np.sum(weights)
weights
np.sum(returns.mean()*weights)*252
np.dot(weights.T, np.dot(returns.cov()*252,weights))
np.sqrt(np.dot(weights.T, np.dot(returns.cov()* 252,weights)))
port_returns = []
port_variance = []
for p in range(100000):
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)
risk_free = 0.03
plt.figure(figsize = (16,8))
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')
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]
cons = ({'type':'eq', 'fun':lambda x: np.sum(x)-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
opts['x'].round(3)
statistics(opts['x']).round(3)
def min_variance(weights):
return statistics(weights)[1]
optv = sco.minimize(min_variance, noa*[1./noa,],method = 'SLSQP', bounds = bnds, constraints = cons)
optv
optv['x'].round(3)
statistics(optv['x']).round(3)
def min_variance(weights):
return statistics(weights)[1]
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)
len(target_variance)
plt.figure(figsize = (16,8))
plt.scatter(port_variance, port_returns, c = port_returns/port_variance,marker = 'o')
len(target_variance),len(target_returns)
plt.scatter(target_variance,target_returns, c = target_returns/target_variance, marker = 'x')
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')
·END·