Using SLSQP for finding the maximum sharpe ratio portfolio, getting nan as portfolio volatility

80 Views Asked by At

I don't really understand what SLSQP is doing when I run this, the denominator of the objective function is always nan (as seen in the callback). When I plug in x0 into the denominator, I get an actual number so I don't understand why its nan in the callback right off the bat?

from scipy.optimize import minimize
import numpy as np

n = 250
x0 = np.ones(n) / n
pred = np.random.normal(loc=0.07, scale=0.2, size=(n))
c = ((np.random.random(size = (n, n)))-0.5) *0.1

def objective(weights):
  if np.sum(weights) == 0:
    return 10
  else:
    return -np.dot(weights, pred)/(np.sqrt(np.dot(weights, np.dot(c, weights)))) # /

def custom_callback(xk):
    print(np.dot(xk, pred) , (np.sqrt(np.dot(xk, np.dot(c, xk)))))

constraints = (
  {'type': 'ineq', 'fun': lambda weights: np.abs(np.sum(weights)) - 0.03},  
  {'type': 'ineq', 'fun': lambda weights: 1.03 - np.sum(np.abs(weights))},  
  {'type': 'ineq', 'fun': lambda weights: np.sum(np.abs(weights))-0.97},
  )

bounds = tuple((-0.02, 0.02) for asset in range(len(x0)))
result = minimize(objective, x0, method='SLSQP', bounds=bounds, constraints=constraints, options={'disp': 2, 'maxiter' : 100}, callback=custom_callback)

denominator with x0 plugged in:

np.sqrt(np.dot(x0, np.dot(c, x0)))
1

There are 1 best solutions below

1
Erwin Kalvelagen On
  1. The callback is called after a complete iteration. So not with your x0.
  2. c is usually positive definite.
  3. abs is non-differentiable and violates the smoothness assumptions of SQLSQP.
  4. Sharpe Ratio models can be reformulated as convex QPs. That is more reliable.