4、奖励函数工程:夏普比率作为奖励信号,回撤惩罚项的设计,多目标奖励的加权与归一化
奖励函数,说白了就是交易智能体的「指挥棒」。你给它什么信号,它就往哪个方向跑。我见过太多人把强化学习当成黑盒子,随便写个收益率当奖励就往上怼,结果模型要么疯狂赌博,要么直接躺平。嗯,这里面的坑,我踩过不少。
今天咱们就聊聊怎么设计一套靠谱的奖励函数。核心就三件事:用夏普比率当主信号,把回撤惩罚加进去,最后搞定多目标加权和归一化。
核心观点:奖励函数不是越复杂越好,而是越「对齐目标」越好。你的交易目标是稳健盈利,那奖励函数就得同时反映收益和风险。
4.1 夏普比率作为奖励信号
为什么选夏普比率?因为它同时考虑了收益和波动。我个人习惯把夏普比率作为奖励函数的主干,而不是直接用收益率。
简单来说,夏普比率 = (收益率 - 无风险利率) / 波动率。但在强化学习里,我们通常用简化版本:
# 简化版夏普比率计算
def sharpe_ratio(rewards):
# rewards: 一段时间内的收益率序列
mean_reward = np.mean(rewards)
std_reward = np.std(rewards)
if std_reward == 0:
return 0
return mean_reward / std_reward * np.sqrt(252) # 年化
我在项目中遇到过一个问题:直接用整个回测期的夏普比率做奖励,模型训练特别慢。为什么?因为每个step都要等整个episode结束才能算奖励,这延迟太大了。
后来我改用「滚动夏普比率」——用过去N步的收益率窗口来计算。这样每个step都能拿到一个实时的奖励信号:
def rolling_sharpe(reward_history, window=20):
if len(reward_history) < window:
return 0
window_rewards = reward_history[-window:]
return np.mean(window_rewards) / (np.std(window_rewards) + 1e-8)
小技巧:窗口大小选20-60步比较合适。太短了噪声大,太长了反应慢。我一般用30步,相当于1.5个交易日的分钟级数据。
4.2 回撤惩罚项的设计
光有夏普比率还不够。你想想看,一个策略可能夏普比率很高,但中间回撤了50%,你受得了吗?反正我受不了。
回撤惩罚,就是让智能体学会「别把净值曲线搞得太难看」。我常用的方法有两种:
- 最大回撤惩罚:当回撤超过阈值时,给一个大的负奖励
- 连续回撤惩罚:每次回撤都扣分,回撤越深扣得越狠
def drawdown_penalty(equity_curve, threshold=0.1):
# equity_curve: 净值曲线
peak = np.maximum.accumulate(equity_curve)
drawdown = (peak - equity_curve) / peak
# 超过阈值的部分加倍惩罚
penalty = np.where(drawdown > threshold,
drawdown * 2, # 超阈值加倍
drawdown * 0.5) # 正常惩罚
return -np.mean(penalty) # 返回负值作为惩罚
避坑指南:我曾经把回撤惩罚设得太重,结果模型变得极度保守,几乎不交易。后来我把惩罚系数调到了0.1-0.3之间,才找到平衡点。记住,惩罚的目的是「约束」,不是「禁止」。
4.3 多目标奖励的加权与归一化
实际交易中,我们往往有多个目标:既要收益高,又要回撤小,还要交易次数合理。这就涉及到多目标奖励的加权组合。
我常用的奖励函数结构是这样的:
def composite_reward(returns, equity_curve, trade_count):
# 1. 夏普比率信号
sharpe = rolling_sharpe(returns, window=30)
# 2. 回撤惩罚
dd_penalty = drawdown_penalty(equity_curve, threshold=0.1)
# 3. 交易频率惩罚(防止过度交易)
freq_penalty = -0.01 * trade_count if trade_count > 10 else 0
# 4. 加权组合
reward = (0.6 * sharpe +
0.3 * dd_penalty +
0.1 * freq_penalty)
return reward
这里有个关键问题:不同目标的量纲不一样。夏普比率可能是0.5-2.0,回撤惩罚可能是-0.1到0,交易频率惩罚可能是-0.5到0。直接加权的话,量纲大的会主导训练。
所以归一化很重要。我一般用两种方法:
| 方法 | 公式 | 适用场景 |
|---|---|---|
| Min-Max归一化 | (x - min) / (max - min) | 已知上下界的目标 |
| Z-score归一化 | (x - mean) / std | 分布稳定的目标 |
我的习惯:先用Z-score把各个奖励分量归一化到均值为0、标准差为1的分布,然后再加权。这样权重才能真正反映「重要性」,而不是被量纲绑架。
4.4 整体框架图
下面这张图展示了奖励函数工程的核心流程。从原始交易数据到最终的复合奖励,每一步都有讲究:
4.5 实战中的注意事项
最后分享几个实战经验:
- 奖励不要设计得太「密」:每个step都给奖励,模型容易过拟合短期噪声。我习惯每5-10步给一次奖励,或者用累积收益来算。
- 权重需要调参:0.6/0.3/0.1不是金科玉律。我一般先跑一组实验,看各个分量的量级,再调整权重让它们贡献相当。
- 记得加一个「生存奖励」:如果模型一直不交易,给它一个小的负奖励,鼓励它至少尝试一下。不然模型可能学会「躺平」。
总结一下:奖励函数工程,本质上是在告诉智能体「什么是对的」。夏普比率告诉它要稳健,回撤惩罚告诉它别玩火,多目标加权告诉它怎么平衡。这三板斧用好了,你的交易智能体至少不会跑偏。