第九章:期权组合优化目标——夏普比率、索提诺比率、最大回撤约束
做期权组合优化,说白了就是回答一个问题:什么样的组合才算「好」?
我早年刚接触量化时,觉得收益高就是好。后来被市场狠狠教育了几次,才明白——收益必须和风险放在一起看。今天我们就来聊聊三个最核心的优化目标:夏普比率、索提诺比率,以及最大回撤约束。
9.1 夏普比率:最经典的「收益/风险」标尺
夏普比率是业界最通用的指标。它的公式很简单:
Sharpe Ratio = (Rp - Rf) / σp
其中 Rp 是组合预期收益,Rf 是无风险利率,σp 是组合收益的波动率。
核心思想:每承担一单位总风险,能换来多少超额收益。
我在项目中遇到过一件事:有个同事拿了一个夏普比率高达 2.5 的策略给我看,我一看回测曲线——确实漂亮。但仔细检查发现,他用了日频数据,而且没有考虑交易成本。换成周频数据后,夏普直接掉到 0.8。嗯,这里要注意:数据频率和计算方式对夏普比率影响极大。
- 年化夏普比率通常用日收益率计算,再乘以 sqrt(252)
- 无风险利率建议用 10 年期国债收益率,别用短期利率
- 期权组合的收益分布往往偏斜,夏普比率会低估尾部风险
9.2 索提诺比率:只惩罚「坏」波动
夏普比率有个天然缺陷:它把上行波动和下行波动一视同仁。但作为期权交易者,你想想看——上涨的波动我们巴不得多来点,真正怕的是下跌。
索提诺比率就是来解决这个问题的:
Sortino Ratio = (Rp - Rf) / σd
σd 是下行标准差,只计算收益率低于目标值(通常设为 0 或无风险利率)的部分。
我个人习惯在期权组合优化中优先使用索提诺比率。为什么?因为期权策略天然具有非对称收益特征。比如卖出宽跨式,夏普可能很好看,但一旦遇到黑天鹅,下行风险极大。索提诺比率能更真实地反映这种风险。
9.3 最大回撤约束:守住底线
夏普和索提诺都是「比率型」指标,它们能告诉你每单位风险换多少收益,但它们不会告诉你组合可能亏多少钱。
最大回撤(Max Drawdown)就是用来补这个短板的。它衡量的是:从历史高点跌到最低点,最大亏损幅度是多少。
在期权组合优化中,我通常这样设置约束:
约束条件:
- 最大回撤 ≤ 15%
- 回撤恢复期 ≤ 60 个交易日
- 单日最大亏损 ≤ 5%
为什么要有恢复期约束?因为期权组合如果回撤太大,gamma 和 vega 暴露会急剧变化,恢复起来比股票组合难得多。我曾经见过一个组合回撤 20%,虽然最终涨回来了,但中间因为保证金不足被迫平仓——这就是回撤约束没设好的代价。
目标函数 = 索提诺比率 - λ × (当前回撤 / 最大允许回撤)
这样组合会自动避开那些「高收益但回撤深」的方案。
9.4 三者如何协同优化?
在实际项目中,我不会只用单一指标。我的做法是:
- 第一层筛选:用夏普比率过滤掉明显不行的组合(比如夏普 < 0.5)
- 第二层优化:以索提诺比率为目标函数,最大化每单位下行风险的收益
- 第三层约束:加入最大回撤和恢复期约束,确保组合不会「暴毙」
下面这张图展示了三者的关系:
9.5 代码实现示例
下面是一个简单的 Python 实现,展示如何在优化中同时考虑这三个目标:
import numpy as np
from scipy.optimize import minimize
def sharpe_ratio(returns, rf=0.03):
excess = returns.mean() * 252 - rf
vol = returns.std() * np.sqrt(252)
return excess / vol if vol > 0 else 0
def sortino_ratio(returns, rf=0.03, target=0):
excess = returns.mean() * 252 - rf
downside = returns[returns < target].std() * np.sqrt(252)
return excess / downside if downside > 0 else 0
def max_drawdown(equity_curve):
peak = np.maximum.accumulate(equity_curve)
drawdown = (equity_curve - peak) / peak
return drawdown.min()
def objective(weights, returns):
# 组合收益
port_returns = returns @ weights
# 索提诺比率(最大化)
sr = sortino_ratio(port_returns)
# 回撤惩罚
equity = (1 + port_returns).cumprod()
dd = max_drawdown(equity)
penalty = 0 if dd > -0.15 else 1000 # 回撤超过15%则重罚
return -sr + penalty
# 假设 returns 是历史收益率矩阵(n_days × n_assets)
# weights 是资产权重向量
result = minimize(objective,
x0=np.ones(5)/5,
args=(returns,),
constraints=[{'type': 'eq', 'fun': lambda w: np.sum(w) - 1}],
bounds=[(0, 0.3)]*5)
9.6 实际应用中的取舍
最后说点实在的。这三个目标不可能同时达到最优——这是优化问题的本质。
我做过一个实盘案例:一个跨式期权组合,夏普比率 1.2,索提诺 0.9,最大回撤 12%。我试图把索提诺优化到 1.2 以上,结果回撤飙到了 18%。后来我妥协了,把索提诺目标设在 1.0,回撤控制在 14% 以内——这个方案最终实盘表现反而最好。
所以我的建议是:先定回撤底线,再优化索提诺,最后用夏普做验证。这个顺序我用了很多年,没出过大问题。
公众号:蓝海资料掘金营,微信deep3321