0

I am trying to build an efficient frontier as in the Markowitz problem. I have written the code below, but I get the error "ValueError: Objective function must return a scalar". I have tested 'fun' with some values, for example, I input to the console:

W = np.ones([n])/n # start optimization with equal weights cov_matrix = returns.cov() fun = 0.5*np.dot(np.dot(W, cov_matrix), W) # variance of the portfolio fun 

The output is 0.00015337622774133828, which is a scalar. I don't know what might be wrong. Any help is appreciated.

Code:

from scipy.optimize import minimize import pandas as pd import numpy as np from openpyxl import load_workbook wb = load_workbook('path/Assets_3.xlsx') # in this workbook there is data for returns. # The next lines clean unnecessary first column and first row. ws = wb.active df = pd.DataFrame(ws.values) df1 = df.drop(0,axis=1) df1 = df1.drop(0) df1 = df1.astype(float) rf = 0.05 r_bar = 0.05 returns = df1.copy() def efficient_frontier(rf, r_bar, returns): n = len(returns.transpose()) W = np.ones([n])/n # start optimization with equal weights exp_ret = returns.mean() cov_matrix = returns.cov() fun = 0.5*np.dot(np.dot(W, cov_matrix), W) # variance of the portfolio cons = ({'type': 'eq', 'fun': lambda W: sum(W) - 1. }, {'type': 'ineq', 'fun': lambda W: np.dot(exp_ret,W) - r_bar }) bnds = [(0.,1.) for i in range(n)] # weights between 0..1. res = minimize(fun, W, (returns, cov_matrix, rf), method='SLSQP', bounds = bnds, constraints = cons) return res x= efficient_frontier(rf,r_bar,returns) x 

Some Data

 1 2 3 1 0.060206 0.005781 0.001117 2 0.006463 -0.007390 0.001133 3 -0.003211 -0.015730 0.001167 4 0.044227 -0.006250 0.001225 5 -0.040571 -0.006910 0.001292 6 -0.007900 -0.006160 0.001208 7 0.068702 0.013836 0.001300 8 0.039286 0.009854 0.001350 9 0.012457 -0.007950 0.001358 10 -0.013758 0.001021 0.001283 11 -0.002616 -0.013600 0.001300 12 0.059004 -0.006090 0.001442 13 0.015566 0.002818 0.001308 14 -0.036454 0.001395 0.001283 15 0.058899 0.011072 0.001325 16 -0.043086 0.017070 0.001308 17 0.023156 -0.003350 0.001392 18 0.063705 0.000301 0.001417 19 0.017628 -0.001960 0.001508 20 -0.014567 -0.006990 0.001525 21 -0.007191 -0.013000 0.001425 22 -0.000815 0.014773 0.001450 23 0.046493 -0.001540 0.001542 24 0.051832 -0.008580 0.001742 25 -0.007151 0.001177 0.001633 26 -0.018196 -0.008680 0.001642 27 -0.013513 -0.008810 0.001675 28 -0.026493 -0.010510 0.001825 29 -0.003249 -0.014750 0.001800 30 0.001222 0.022258 0.001758 
11
  • 1
    fun doesn't seem to be a function. Commented Oct 18, 2017 at 18:14
  • It's supposed to be a function of the weights W and the covariance matrix cov_matrix. Commented Oct 18, 2017 at 18:16
  • 1
    Are you sure you are not returning an np.array with shape (1), intead of a float? Commented Oct 18, 2017 at 18:17
  • @MatteoRagni If i put instead fun = float(0.5*np.dot(np.dot(W, cov_matrix), W)), I get the same error. Commented Oct 18, 2017 at 18:18
  • 1
    Uh ma fun is not a callable object! Probably that is the issue.... Commented Oct 18, 2017 at 18:20

1 Answer 1

3

This code is a mess and while i can show you something which runs, that does not mean anything.

You will see convergence to your starting-point, whatever that means in your task! It's a strong indicator that something is still very wrong (might be the underlying theory)!

Some additional remarks:

  • scipy's optimizers are build to work with numpy-arrays, not pandas Dataframes or Series objects!
    • the only things in your original question which hinted pandas-usage was a var-name df and returns.cov() which does not exist for numpy-arrays!
  • rf is never used anywhere!
  • there are multiple things in optimize's args, which are not used!
  • it does not feel like a problem one should use scipy's optimizers for! (but it's possible; here we are paying for numerical-differentiation for example)
    • cvxpy would probably a much much better approach (more clean, faster, more accurate) if interpret the problem correctly (did not analyze much)
    • but the same rules apply: some python-knowledge is needed!

Code:

from scipy.optimize import minimize import numpy as np import pandas as pd rf = 0.05 r_bar = 0.05 returns = pd.DataFrame(np.random.randn(30, 3), columns=list('ABC')) # PANDAS DF cov_matrix = returns.cov().as_matrix() # use PANDAS one last time # but result = np.array! returns = returns.as_matrix() # From now on: np-only! def fun(x, returns, cov_matrix, rf): return 0.5*np.dot(np.dot(x, cov_matrix), x) def efficient_frontier(rf, r_bar, returns): n = len(returns.transpose()) W = np.ones([n])/n # start optimization with equal weights exp_ret = returns.mean() cons = ({'type': 'eq', 'fun': lambda x: np.sum(x) - 1. }, # let's use numpy here {'type': 'ineq', 'fun': lambda x: np.dot(exp_ret, x) - r_bar }) bnds = [(0.,1.) for i in range(n)] # weights between 0..1. res = minimize(fun, W, (returns, cov_matrix, rf), method='SLSQP', bounds = bnds, constraints = cons) return res x= efficient_frontier(rf,r_bar,returns) print(x) 

Output:

A B C A 0.813375 -0.001370 0.173901 B -0.001370 1.482756 0.380514 C 0.173901 0.380514 1.285936 fun: 0.2604530793556774 jac: array([ 0.32863522, 0.62063321, 0.61345008]) message: 'Optimization terminated successfully.' nfev: 35 nit: 7 njev: 3 status: 0 success: True x: array([ 0.33333333, 0.33333333, 0.33333333]) 
Sign up to request clarification or add additional context in comments.

3 Comments

@MatteoRagni It's a question hard to work with. Especially until one recognizes that np_array.cov() does not exist.
Looking further into the results, I realized that in spite of outputting a result, the code does not optimize anything. Whatever W I choose to input as initial weights will be the final result of the weights and 'fun' is exactly the objective function when inputting these values.
That's what i told in the first place. The second sentence of my answer is important and without a clear problem-statement (theory of the problem) there is not much to help.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.