2. 多目标优化基础:Pareto最优解、支配关系、Pareto前沿面、多目标与单目标的区别

做量化投资这些年,我越来越觉得——投资本质上就是个多目标优化问题

你想想看,我们既要收益高,又要回撤小,还得考虑流动性、换手率、持仓集中度……这些目标往往互相打架。你提高收益,波动就上来了;你控制回撤,收益可能就下去了。

这时候,传统的单目标优化就不够用了。我们需要一套新的理论框架——多目标优化

2.1 单目标优化 vs 多目标优化:本质区别在哪?

先说说单目标优化。说白了,就是找一个最优解。比如你只追求夏普比率最大化,那算法就拼命往那个方向跑,找到一个全局最优就完事了。

但多目标优化不一样。它要同时优化多个互相冲突的目标。比如:

  • 目标A:最大化年化收益率
  • 目标B:最小化最大回撤
  • 目标C:最小化换手率(降低交易成本)

这三个目标不可能同时达到最优。你收益率做到30%,回撤可能就20%了;你回撤控制在5%以内,收益率可能只有8%。

核心区别一句话总结:

单目标优化找的是一个最优解,多目标优化找的是一组非劣解(也叫Pareto最优解集)。

我在项目中遇到过不少新手,上来就想用加权求和法把多目标变成单目标。比如给收益赋权0.7,给回撤赋权0.3,然后优化这个加权值。嗯,这样做确实简单,但问题很大——权重的选择太主观了。你凭什么说收益比回撤重要?市场环境一变,这个权重可能就完全不合理了。

2.2 支配关系:判断谁更优的规则

多目标优化里,我们怎么比较两个解的优劣?这就引出了支配关系

定义很简单:

  • 解A 支配 解B,当且仅当:
    • 在所有目标上,A都不比B差
    • 至少在一个目标上,A严格优于B

举个例子。假设我们有两个目标:收益(越大越好)和回撤(越小越好)。

策略 年化收益 最大回撤
策略A 15% 8%
策略B 12% 6%
策略C 15% 10%

分析一下:

  • A vs B:A收益更高(15% > 12%),但回撤也更大(8% > 6%)。互有优劣,互不支配
  • A vs C:A收益相同(15% = 15%),但回撤更小(8% < 10%)。所以A支配C
  • B vs C:B收益更低(12% < 15%),但回撤更小(6% < 10%)。互有优劣,互不支配

避坑指南:我曾经在实盘策略筛选时,直接用夏普比率排序选前10个。结果发现这些策略的持仓高度重合,一遇到市场风格切换,集体回撤。后来我才意识到——夏普比率是个单目标指标,它把收益和波动揉在一起,掩盖了策略之间的本质差异。改用Pareto支配关系后,我才能选出真正多样化的策略组合。

2.3 Pareto最优解与Pareto前沿面

理解了支配关系,Pareto最优解就很好懂了。

Pareto最优解:在整个解空间中,不被任何其他解支配的解。

这些Pareto最优解构成的集合,就是Pareto最优解集。它们在目标空间中的映射,就是Pareto前沿面

我习惯把Pareto前沿面想象成一条「边界线」。在这条线上,你无法在不牺牲一个目标的前提下,改善另一个目标。比如你想让收益更高,就必须接受更大的回撤;你想让回撤更小,就必须接受更低的收益。

Pareto前沿面的三个关键特征:

  1. 非支配性:前沿面上的解互不支配
  2. 完整性:所有非支配解都在前沿面上
  3. 凸性(通常):前沿面通常是凸的,但也不绝对

下面我用一张SVG图来展示Pareto前沿面的概念。这张图我画了很多遍,每次给团队新人讲多目标优化时都会用到。

收益 → 回撤 → (越小越好) Pareto前沿面 被支配解 Pareto最优解 Pareto最优解 被支配解 Pareto前沿面

这张图里,红色曲线就是Pareto前沿面。曲线上的每个点都是一个Pareto最优解——你没法在不增加回撤的前提下提高收益,也没法在不降低收益的前提下减少回撤。灰色点是那些被支配的解,它们要么收益更低,要么回撤更大,或者两者都差。

注意:Pareto前沿面不一定总是凸的。当目标函数非凸时,前沿面可能出现凹陷。这时候用加权求和法会漏掉凹陷部分的解——这也是我为什么不太推荐加权求和法的原因之一。

2.4 多目标优化的实际应用:从理论到实战

理论讲完了,说说实战中怎么用。

在量化投资里,我通常把多目标优化用在以下几个场景:

  1. 策略参数优化:同时优化夏普比率、最大回撤、胜率
  2. 投资组合构建:同时优化收益、风险、换手率、持仓数量
  3. 因子筛选:同时考虑因子的收益预测能力、稳定性、容量
  4. 交易执行优化:同时优化滑点、冲击成本、完成时间

举个例子。我之前做CTA策略参数优化时,目标函数是这样的:

# 多目标优化目标函数示例
def objectives(params):
    # 参数:移动平均周期、止损比例、仓位比例
    ma_period, stop_loss, position_ratio = params
    
    # 回测得到三个目标值
    sharpe = backtest_sharpe(ma_period, stop_loss, position_ratio)
    max_dd = backtest_max_drawdown(ma_period, stop_loss, position_ratio)
    win_rate = backtest_win_rate(ma_period, stop_loss, position_ratio)
    
    # 返回目标向量(注意:回撤要取负,因为我们要最小化它)
    return [-sharpe, max_dd, -win_rate]

然后我用NSGA-II算法跑一遍,得到一组Pareto最优解。最后我从中选了一个「回撤适中、收益不错、胜率尚可」的参数组合——而不是那个夏普比率最高的。

我的经验:拿到Pareto前沿面后,别急着选一个解。我习惯先看看前沿面的形状——如果某个区域特别密集,说明算法在那个区域找到了很多不错的解;如果某个区域很稀疏,说明那个区域的解很难找到,或者根本不存在。

另外,我通常会保留3-5个Pareto最优解,分别对应「激进型」「稳健型」「保守型」的策略风格。这样市场环境变化时,我可以快速切换,而不是重新跑一遍优化。

2.5 多目标优化的常见误区

最后说说我踩过的坑,希望能帮你少走弯路。

误区 问题 正确做法
把所有目标加权求和 权重主观,且会漏掉非凸前沿面上的解 用Pareto方法,保留完整前沿面
目标数量太多 维度灾难,Pareto前沿面几乎全是解 控制在2-4个目标,或者用降维方法
忽略目标之间的相关性 高度相关的目标等于浪费一个维度 先做相关性分析,合并高度相关的目标
只关注前沿面,不看具体解 前沿面上的解可能在实际中不可行 加入约束条件,过滤掉不可行解

嗯,说到目标数量太多这个问题,我记得有一次帮一个团队做多因子选股优化,他们一口气列了8个目标——收益、波动、换手率、持仓数量、行业集中度、市值暴露、动量因子暴露、价值因子暴露。结果跑出来的Pareto前沿面几乎覆盖了整个目标空间,根本没法选。后来我建议他们先做因子分析,把高度相关的目标合并,最终压缩到3个核心目标,问题才变得可解。

多目标优化的核心思想,说白了就是承认现实中的权衡取舍。你不可能什么都想要,但你可以找到那个「不后悔」的边界——这就是Pareto前沿面的价值。


公众号:蓝海资料掘金营,微信deep3321