使用DEoptim求解的最优投资组合绘图显示非最优,求原因解析
你在使用PortfolioAnalytics搭配DEoptim构建最优投资组合时,遇到了一个很典型的启发式优化困惑:明明图表里有回撤相同但收益率更高的组合,算法却没选到它。我来帮你拆解几个核心原因,以及对应的调试方向:
1. DEoptim的启发式搜索特性有局限性
DEoptim是差分进化算法,属于启发式优化范畴——它不像线性规划那样能100%找到全局最优解,而是通过迭代种群搜索来逼近最优。你设置的search_size=2000虽然不算小,但在有多个约束(组约束、全投资约束、long-only)的组合空间里,这个搜索规模可能还不足以覆盖到那个收益更高的可行组合。
调试建议:
增大搜索规模或者调整DEoptim的核心参数,比如:
# 增大搜索样本量,同时调整DEoptim种群规模和迭代次数 opt.obj.no1.1 <- optimize.portfolio(R=ret, portfolio=ret.obj.portf, optimize_method="DEoptim", search_size=5000, # 提升到5000甚至10000 trace=TRUE, DEoptim.control(NP=200, itermax=100))
2. 你把回撤设置成了目标而非硬约束
看你的代码,你是通过add.objective来设置maxDrawdown目标的:
ret.obj.portf <- add.objective(portfolio = ret.obj.portf, type = 'risk', name = 'maxDrawdown', arguments = list(inverse=TRUE), target = -0.1)
这里的问题是:add.objective里的risk目标带target,本质是把回撤作为惩罚项(而非严格约束)。也就是说,算法可能会接受稍微超过-0.1的回撤来换取更高收益,或者在搜索逻辑里,没有把“回撤≤-0.1”作为必须满足的前提。
正确的硬约束做法:
如果你想严格限定最大回撤不能超过10%,应该把回撤设置成约束,而非目标:
# 先移除原来的maxDrawdown目标,改用硬约束 ret.obj.portf <- add.constraint(portfolio=ret.obj.portf, type="risk", name="maxDrawdown", max=-0.1) # 强制要求回撤不能超过-0.1
这样算法会在所有满足回撤约束的可行组合里,专门寻找收益率最高的那个。
3. 组约束可能锁死了优化空间
你的代码里设置了非常严格的组约束:
group_list <- list(group1=c(3), group2=c(1, 2), group3=c(5, 7, 8)) init.portf <- add.constraint(portfolio= init.portf, type="group", groups=group_list, group_min=c(0.03, 0, 0), group_max=c(0.032, 0.2, 0.3))
尤其是group1(对应第3个资产)的权重被死死卡在0.03-0.032之间,这可能直接排除了那个收益更高的组合——它的权重分配可能违反了这个组约束,所以根本不在算法的可行搜索范围内。
验证方法:
查看chart.RiskReward里那个“更优”组合的权重,检查是否满足所有组约束条件。如果它的group1权重不在0.03-0.032之间,那它本来就不符合你的规则,算法当然不会选它。
4. 全投资约束的宽松设置可能有影响
你修改了全投资约束的范围:
ret.obj.portf$constraints[[1]]$min_sum <- 0.99 ret.obj.portf$constraints[[1]]$max_sum <- 1.01
虽然这个范围很小,但某些收益更高的组合可能权重和超出了0.99-1.01,或者算法在搜索时没有优先聚焦这个区间内的最优解。你可以尝试把这个范围改回严格的1(即min_sum=1, max_sum=1),再重新优化试试。
最后一步:验证可行域
你可以用extractStats(opt.obj.no1.1)导出优化后组合的详细统计,再手动计算那个“更优”组合的回撤、收益率和权重约束情况,确认它是否真的在你的可行域内。很多时候,看起来更优的组合其实是违反了某个隐藏的约束条件。
内容的提问来源于stack exchange,提问作者kobriukee

