sc.minimize优化未满足持仓数量与敞口约束的问题求助
sc.minimize优化未满足持仓数量与敞口约束的问题求助
我最近在做投资组合优化时遇到了瓶颈,想请大家帮忙排查问题。我的需求是:让每个标的的仓位x只能取-1(做空)、0(不持仓)、1(做多),初始数组x0的元素都是-1或1,目标是最大化A @ x,但目前代码跑出来的结果始终无法同时满足持仓数量约束和敞口约束。以下是我的完整代码和问题细节:
代码实现细节
导入依赖
import numpy as np from scipy.optimize import minimize, NonlinearConstraint
目标函数(最大化A@x,转换为最小化问题)
def objective(x, A): return -np.dot(A, x) # 最大化等价于最小化负的结果
仓位取值约束(强制x只能是-1/0/1)
def constraint_func(x): # 当且仅当x的每个元素是-1/0/1时,x*(|x|-1)=0,求和后为0 return np.sum(x * (np.abs(x) - 1))
持仓数量统计函数
def amount_long(x): return np.where(x > 0, 1, 0).sum() # 统计做多标的数量 def amount_short(x): return np.where(x < 0, 1, 0).sum() # 统计做空标的数量
组合净敞口计算
def exposure(x, S): # 计算行业维度的多空敞口绝对值之和的最大值 if x[x > 0].sum() == 0: long_exposure = 0 else: long_exposure = np.dot(S.T, np.where(x > 0, 1, 0)) / x[x > 0].sum() if x[x < 0].sum() == 0: short_exposure = 0 else: short_exposure = np.dot(S.T, np.where(x < 0, 1, 0)) / x[x < 0].sum() return np.abs(long_exposure + short_exposure).max() def exposure_constraint(x, S): return exposure(x, S)
优化执行逻辑
# 定义约束条件 const = [ NonlinearConstraint(amount_long, 200, 30), # 这里我怀疑上下限写反了? NonlinearConstraint(amount_short, 200, 300), NonlinearConstraint(constraint_func, 0, 0), # 强制x取-1/0/1 NonlinearConstraint(lambda x: exposure_constraint(x, S), -0.1, 0.1) ] # 初始化x0:从历史数据提取的仅含±1的数组 ls = (long-short).loc[dt].replace(0, np.nan).dropna() x0 = (ls.values) A = profitability.loc[dt, ls.index].values S = sectors.loc[ls.index].values # 设置仓位边界:原x0为正的只能取0或1,原x0为负的只能取0或-1 b = [(0, 1) if i > 0 else (-1, 0) for i in x0] # 执行优化 result = minimize(objective, x0, args=(A,), bounds=b, constraints=const, method='SLSQP')
我初步怀疑的问题点
目前优化结果始终不满足约束,我自己排查了几个可能的问题:
- 约束上下限逻辑错误:比如
amount_long的约束设置为200, 30,这要求做多标的数量同时≥200且≤30,这显然是不可能满足的,是不是应该写反成30, 200? - 连续优化方法的局限性:SLSQP是针对连续变量的优化算法,而我的
x是离散的-1/0/1,虽然加了constraint_func强制等式约束,但连续优化很难严格满足离散变量的要求,容易得到近似解(比如0.6这种中间值)。 - 敞口约束的合理性:
exposure计算的是绝对值的最大值,本身是非负数,但约束设为-0.1到0.1,其实等价于0到0.1,会不会约束的定义方式有误? - 边界设置的限制:当前边界
b限制了原做多的标的不能改成做空,原做空的不能改成做多,如果业务上允许反转方向,是不是应该把边界改成(-1,1)? - 除零风险:原代码中
exposure计算时没有处理做多/做空数量为0的情况,可能在优化过程中触发除零错误,导致优化中断或结果异常。
希望大家提供的帮助
- 针对离散变量-1/0/1的优化场景,除了SLSQP,有没有更合适的工具或方法?比如整数规划相关的库(如
cvxpy的整数规划模块、pulp)? - 我的约束定义还有其他不合理的地方吗?比如持仓数量的约束应该用线性约束而非非线性约束?
- 敞口的计算逻辑是否正确?有没有更合理的方式定义组合的净敞口约束?
备注:内容来源于stack exchange,提问作者Pedro Andion
相关产品推荐
相关产品推荐

