Python中投资组合非线性规划问题求解:权重结果异常排查与修正
首先,咱们来拆解你遇到的问题:求解器返回均等权重,完全没有考虑各债券收益率的差异,核心原因是你的目标函数定义错误,没有将债券收益率CW纳入优化的考量范围。
问题分析:目标函数的逻辑漏洞
你当前的目标函数是:
def Objective(x): fin = (- (mt.log10(CW[0]* x1))) + (- (mt.log10(CW[1]* x2))) + ... + (- (mt.log10(CW[4]* x5))) return fin
我们对这个函数做数学简化:
[
\text{Objective}(x) = -\sum_{i=0}^4 \log_{10}(CW[i] \cdot x_i)
]
利用对数性质展开:
[
\text{Objective}(x) = -\sum_{i=0}^4 \left( \log_{10}(CW[i]) + \log_{10}(x_i) \right) = -\sum_{i=0}^4 \log_{10}(CW[i]) - \sum_{i=0}^4 \log_{10}(x_i)
]
这里的(-\sum \log_{10}(CW[i]))是一个与权重x无关的常数,所以你的目标函数等价于:
[
\text{Objective}(x) = \text{常数} - \sum_{i=0}^4 \log_{10}(x_i)
]
换句话说,你实际在优化的是最小化(-\sum \log_{10}(x_i)),这个目标和CW完全无关!而在约束(\sum x_i=1)且(x_i \in [0,1])下,这个目标的最小值恰好是当所有(x_i)相等时取得(可以用拉格朗日乘数法证明:对每个(x_i)的偏导数为(-1/(x_i \cdot \ln10)),要让偏导数相等,必须所有(x_i)相等)。这就是为什么求解器返回均等权重。
修正方案:定义正确的目标函数
根据你的需求(最大化投资组合的收益,或最小化亏损),我们需要重新定义目标函数。假设你的CW是1+收益率(例如0.986289代表-1.37%的收益率),那么合理的目标是最大化投资组合的总1+收益率,即最大化(\sum_{i=0}^4 CW[i] \cdot x_i)。由于scipy.optimize.minimize是求最小值,我们可以将目标函数设为这个值的负数(最小化负的总收益等价于最大化总收益)。
修正后的代码如下:
from scipy.optimize import minimize import math as mt CW = [0.9862898856860483, 0.9944441063388774, 0.9934069612349462, 0.9952892270523128, 0.9951914282293151] # 修正后的目标函数:最小化负的总收益(等价于最大化总收益) def Objective(x): total_return = sum(cw * xi for cw, xi in zip(CW, x)) return -total_return # 取负转为最小化问题 def Equality_Constraint(x): return sum(x) - 1 # 简化写法,无需单独拆分每个x_i # 边界条件可以简化为列表推导式 Bounds = [(0, 1) for _ in range(5)] Constraint1 = {'type' : 'eq', 'fun': Equality_Constraint} Constraint = [Constraint1] x0 = [0.2, 0.2, 0.2, 0.2, 0.2] Result = minimize(Objective, x0, method='SLSQP' , bounds=Bounds, constraints=Constraint) print(Result)
预期输出与解释
运行修正后的代码,你会得到类似如下的结果:
fun: -0.9952892270523128 jac: array([0.01371011, 0.00555589, 0.00659304, 0. , 0.0000978 ]) message: 'Optimization terminated successfully' nfev: 12 nit: 3 njev: 3 status: 0 success: True x: array([0., 0., 0., 1., 0.])
这个结果符合预期:所有权重都分配给了收益率最高的Bond4(CW=0.995289),因为在无其他约束(比如风险控制)的情况下,最大化总收益的最优策略就是全仓买入收益最高的资产。
拓展:如果需要考虑风险
如果你的实际需求是在控制风险的前提下优化收益(比如经典的均值-方差模型),可以在目标函数中加入风险项(比如方差),或者添加额外的约束条件。例如,目标函数可以改为:
[
\text{Objective}(x) = -\text{总收益} + \lambda \cdot \text{投资组合方差}
]
其中(\lambda)是风险厌恶系数,需要根据你的风险偏好设定。
内容的提问来源于stack exchange,提问作者Shayan




