我正在使用scipy.optimize.minimize来解决有效的投资组合。
使用默认设置时,我经常遇到“BaseException:linesearch的正方向导数”错误,当使用某些输入时。我注意到如果我将公差设置得足够高,问题会变得更少,但不会消失。有什么建议吗?
import numpy as np
import pandas as pd
import scipy.optimize
def fx(TOLERANCE):
#TOLERANCE = 1.5
def solve_weights(R, C, rf, b_):
def port_mean_var(W,R,C):
return sum(R*W), np.dot(np.dot(W, C), W)
def fitness(W, R, C, rf):
mean, var = port_mean_var(W, R, C) # calculate mean/variance of the portfolio
util = (mean - rf) / np.sqrt(var) # utility = Sharpe ratio
return 1/util # maximize the utility, minimize its inverse value
n = len(R)
W = np.ones([n])/n # start optimization with equal weights
#b_ = [(0.,1.) for i in range(n)] # weights for boundaries between 0%..100%. No leverage, no shorting
c_ = ({'type':'eq', 'fun': lambda W: sum(W)-1. }) # Sum of weights must be 100%
optimized = scipy.optimize.minimize(fitness, W, (R, C, rf),
method='SLSQP', constraints=c_,
bounds=b_, tol=TOLERANCE)
if not optimized.success:
raise BaseException(optimized.message)
return optimized.x
def mean_var_opt2(ret_df, upper_bounds=None):
R = (ret_df.mean(0)*252).values
C = (ret_df.cov()*252).values
rf = 0.0
if upper_bounds == None:
upper_bounds = pd.Series(1.0,index=ret_df.columns)
b_ = [(0.0,float(num)) for num in upper_bounds]
wgts = solve_weights(R, C, rf, b_)
return pd.Series(wgts, index=ret_df.columns)
np.random.seed(45)
rets = []
for i in range(10000):
rets.append(pd.DataFrame(np.random.randn(100,4)/100.0))
try:
for i in range(10000):
mean_var_opt2(rets[i])
except BaseException as e:
print e
finally: print "Tolerance: %s, iter: %s" % (TOLERANCE,i)
for k in [0.001, 0.01, 0.025, 0.05, 0.1, 0.5, 1.0, 5.0, 50.0, 500.0]:
fx(k)
Positive directional derivative for linesearch
Tolerance: 0.001, iter: 0
Positive directional derivative for linesearch
Tolerance: 0.01, iter: 30
Positive directional derivative for linesearch
Tolerance: 0.025, iter: 77
Inequality constraints incompatible
Tolerance: 0.05, iter: 212
Positive directional derivative for linesearch
Tolerance: 0.1, iter: 444
Positive directional derivative for linesearch
Tolerance: 0.5, iter: 444
Positive directional derivative for linesearch
Tolerance: 1.0, iter: 1026
Positive directional derivative for linesearch
Tolerance: 5.0, iter: 1026
Positive directional derivative for linesearch
Tolerance: 50.0, iter: 1026
Positive directional derivative for linesearch
Tolerance: 500.0, iter: 1026
答案 0 :(得分:1)
调整容差直到它不崩溃是一个非常弱的解决方案,对您的数据或功能进行小的更改,您一定会崩溃。请参阅here您的错误消息的含义。
我的猜测是约束不能很好地发挥作用。求解器在平滑函数上工作得最好,而你的约束可能会使问题变得非常困难。我可以想出两种解决方法:
W
的前N-1值,然后从中计算最后一个值。通过这种方法,您可能会发现自己处于负权重状态。(W.sum() - 1)**2
。这种行为在W
中是抛物线的,这就是解算器最好的效果。在最终结果中,权重可能不完全相加,但是当你在内部使用它们进行标准化时,它应该不是问题。 另一种方法是减少自由参数的数量。如果W[17]
具有与W[18]
类似的含义,则可以自然地期望它们的值相似。然后,您可以使用平滑函数计算它们,例如抛物线,或sin /余弦系列中的一些项。这允许您引入位置信息并减少问题的维数。
答案 1 :(得分:0)
SLSQP
要求成本函数必须是两次可导的,如果不满足该条件,则可能会失败。除非容差增加过大,否则您将始终获得初始解决方案,这对您没有任何帮助。
您可能想尝试使用COBYLA
来代替-但是请注意,这会要求您将边界转换为约束,因为COBYLA
不接受单独的bounds参数。
答案 2 :(得分:0)
我提供的答案很晚,因为似乎该示例的源代码仍在网络here上。
要像函数fitness()
中那样使Sharpe比率最大化,则不必使它的倒数最小。您可以简单地减少负面影响。
因此,如果我在该函数中将return 1/util
替换为return -util
并运行发问者的代码-我这样做了---我发现任何10,000迭代中的任何一个都没有错误TOLERANCE
。