强化学习基础(二):Q-Learning与SARSA算法原理
好,咱们接着聊。上一章我们把强化学习的核心概念捋了一遍,状态、动作、奖励、策略这些基本盘算是稳了。这一章,我们直接上硬菜——两种最经典的时序差分(TD)算法:Q-Learning 和 SARSA。
说实话,这两个算法是入门强化学习的“必过坎”。我当年刚接触时,也绕了不少弯路。今天我就用最直白的方式,把它们的原理、区别,以及在实际量化交易中怎么用,给你讲透。
一、从“猜数字”游戏理解TD思想
先别急着看公式。我们想一个问题:你玩一个猜数字游戏,每次猜完,系统只告诉你“高了”或“低了”。你怎么快速逼近正确答案?
你不会等猜完100次再总结,而是每猜一次,就根据反馈调整下一次的猜测。这就是时序差分(TD)的核心思想——用当前步的即时奖励 + 下一步的估计值,来更新当前步的估计值。
用公式表达就是:
新估计值 = 旧估计值 + 学习率 × (即时奖励 + 折扣因子 × 下一步估计值 - 旧估计值)
这个括号里的差值,我们叫它TD误差。说白了,就是“我猜的”和“实际发生的”之间的差距。差距越大,调整幅度越大。
核心要点:TD算法不需要等到回合结束才更新,它可以在每一步都学习。这在交易场景中特别重要——你不可能等一年后再优化策略,对吧?
二、Q-Learning:离线学习的“激进派”
Q-Learning 是 Watkins 在1989年提出的。它的核心思想很直接:学习一个最优动作价值函数 Q(s,a),告诉你“在状态s下做动作a,未来能拿到多少累计奖励”。
更新公式长这样:
Q(s,a) ← Q(s,a) + α [ r + γ * max_a' Q(s',a') - Q(s,a) ]
注意看那个 max_a' Q(s',a')——它取的是下一个状态中所有动作里最大的那个Q值。这意味着什么?
意味着Q-Learning在更新时,假设自己下一步一定会选最优动作。它不管当前策略是什么,只管“理论上最好的结果”。
我举个例子。你在交易中,当前持仓是空仓(状态s),你有三个动作:买入、卖出、持有。Q-Learning在更新时,会直接看“如果我现在买入,未来最好的情况能赚多少”,而不是看“按我现在的策略,买入后下一步会怎么操作”。
我的经验:在量化回测中,Q-Learning往往收敛更快,因为它“胆子大”,直接朝着最优方向学。但风险是——如果市场环境突变,它可能会过度乐观。我曾经在2015年股灾回测中吃过这个亏,模型在暴跌前还拼命买入,因为历史数据里“买入”一直是好动作。
三、SARSA:在线学习的“稳健派”
SARSA 的名字来源于它的更新需要5个元素:State, Action, Reward, State', Action'。也就是当前状态、当前动作、奖励、下一个状态、下一个动作。
更新公式:
Q(s,a) ← Q(s,a) + α [ r + γ * Q(s',a') - Q(s,a) ]
和Q-Learning唯一的区别在于:它用的是 Q(s',a'),而不是 max_a' Q(s',a')。这里的 a' 是实际要执行的下一个动作,而不是理论上的最优动作。
这意味着什么?SARSA 在更新时,会考虑当前策略的“实际行为”。如果当前策略是ε-greedy(后面会讲),那它就会把“探索”带来的次优动作也考虑进去。
关键区别一句话总结:
- Q-Learning:学的是“如果我一直选最优,结果会怎样”
- SARSA:学的是“按我现在的策略走,结果会怎样”
四、探索与利用的权衡:ε-greedy策略
好,现在问题来了。无论是Q-Learning还是SARSA,都需要一个策略来生成动作。这个策略不能一直选已知的最优动作(利用),否则会错过更好的选择(探索)。
ε-greedy 是最简单也最常用的解决方案:
- 以概率 ε 随机选择一个动作(探索)
- 以概率 1-ε 选择当前Q值最大的动作(利用)
代码实现就几行:
import numpy as np
def epsilon_greedy(Q, state, epsilon, n_actions):
if np.random.random() < epsilon:
# 探索:随机选一个动作
return np.random.randint(n_actions)
else:
# 利用:选Q值最大的动作
return np.argmax(Q[state])
避坑指南:我曾经在实盘模拟中把ε设成固定值0.1,结果模型永远在探索,永远学不好。正确的做法是让ε随时间衰减——初期多探索,后期多利用。比如从0.9线性衰减到0.01。
五、在离散动作空间中的应用:以仓位管理为例
在量化交易中,离散动作空间最常见的场景就是仓位管理。假设我们只允许三种仓位:
- 动作0:空仓(0%仓位)
- 动作1:半仓(50%仓位)
- 动作2:满仓(100%仓位)
状态可以定义为:过去N天的收益率、波动率、成交量变化等。奖励函数可以设为:每步的收益率 - 惩罚项(比如最大回撤惩罚)。
下面是一个完整的Q-Learning训练循环框架:
import numpy as np
# 初始化Q表
n_states = 100 # 离散化后的状态数
n_actions = 3 # 空仓、半仓、满仓
Q = np.zeros((n_states, n_actions))
# 超参数
alpha = 0.1 # 学习率
gamma = 0.9 # 折扣因子
epsilon = 0.9 # 初始探索率
epsilon_min = 0.01
epsilon_decay = 0.995
# 训练循环
for episode in range(1000):
state = env.reset() # 获取初始状态
done = False
while not done:
# 用ε-greedy选动作
action = epsilon_greedy(Q, state, epsilon, n_actions)
# 执行动作,获取下一个状态和奖励
next_state, reward, done = env.step(action)
# Q-Learning更新
best_next_action = np.argmax(Q[next_state])
td_target = reward + gamma * Q[next_state][best_next_action]
td_error = td_target - Q[state][action]
Q[state][action] += alpha * td_error
state = next_state
# 衰减探索率
if epsilon > epsilon_min:
epsilon *= epsilon_decay
我的习惯:在实际项目中,我不会直接用原始收益率作为奖励。我会用夏普比率或者卡玛比率的增量作为奖励,这样模型会更关注风险调整后的收益。你想想看,一个策略如果收益高但回撤大,你敢用吗?
六、Q-Learning vs SARSA:到底选哪个?
这个问题我经常被问到。直接给结论:
| 对比维度 | Q-Learning | SARSA |
|---|---|---|
| 学习方式 | 离线学习(Off-policy) | 在线学习(On-policy) |
| 更新依据 | 理论最优动作 | 实际执行动作 |
| 收敛速度 | 通常更快 | 通常更慢 |
| 风险偏好 | 激进,可能高估 | 稳健,更贴近实际 |
| 适用场景 | 环境稳定,追求最优 | 环境波动大,求稳 |
我个人在量化交易中的经验是:先用Q-Learning快速找到大致方向,再用SARSA做精细调优。这样既保证了效率,又兼顾了稳健性。
七、本章知识体系图
下面这张图把本章的核心逻辑串起来了,建议你多看几遍:
本章核心记忆点:
- Q-Learning 用 max 更新,胆子大,学得快
- SARSA 用实际动作更新,步子稳,更安全
- ε-greedy 是探索和利用的“调节旋钮”
- 离散动作空间最适合做仓位管理、买卖信号等
好了,这一章的内容就到这。下一章我们会把这些算法真正跑起来,用Python实现一个完整的交易智能体。到时候你会发现,这些理论其实离实战并不远。
公众号:蓝海数据掘金营,微信deep3321