forked from qkd8059/Capstone
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathmax_sharpe.py
42 lines (40 loc) · 1.75 KB
/
max_sharpe.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import numpy as np
import scipy.optimize as optimize
# Maximize Sharpe Ratio
def max_sharpe(mu,Q,card):
"""
:param mu: n*1 vector, expected returns of n assets
:param Q: n*n matrix, covariance matrix of n assets
:param card: a scalar, cardinality constraint
:return: norm_weight (the portfolio weight), ticker_index (the indices of selected stock)
"""
def get_ret_vol_sr(weights):
weights = np.array(weights)
ret = np.sum(mu * weights)
vol = np.sqrt(np.dot(weights.T,np.dot(Q,weights)))
sr = ret/vol
return np.array([ret,vol,sr])
# minimize negative Sharpe Ratio
def neg_sharpe(weights):
return get_ret_vol_sr(weights)[2] * -1
# check allocation sums to 1
def check_sum(weights):
return np.sum(weights) - 1
# create constraint variable
cons = ({'type':'eq','fun':check_sum})
num_assets = len(mu)
# create bounds for the weights 0<=x_i<=0.5
up = 0.5
bounds = tuple((0,up) for x in range(num_assets))
# equal weight initialization
init_guess = num_assets * [1./num_assets,]
# Use sequential least square quadratic programming in scipy to optimize
opt_results = optimize.minimize(neg_sharpe, init_guess, method='SLSQP', bounds=bounds, constraints=cons)
# opt_results = optimize.minimize(neg_sharpe, init_guess, method='CG', bounds=bounds, constraints=cons)
weight = opt_results.x
# Return the indices of the selected stocks
ticker_index = np.argsort(weight)[-card:]
# Return the weight based on the cardinality and normalize the weight to avoid extremely small weights (e.g. 10^-10)
weight_opt = weight[np.argsort(weight)[-card:]]
norm_weight = [float(i)/sum(weight_opt) for i in weight_opt]
return norm_weight, ticker_index