您应当知道的 MQL5 向导技术(第 58 部分):配以移动平均和随机振荡器形态的强化学习(DDPG)
概述
自我们上一篇文章,我们测试了来自两个指标(移动平均线和随机振荡器)的 10 种信号形态。其中七个能基于一年的测试窗口通过前向漫游测试。然而,在这些当中,仅有两个做到了做多和做空。这主要是因为我们的测试窗口很短,这就是为何建议读者在将来采用它之前,在更长历史数据上进行测试。
我们在此遵循的是一个论点,其中三种主要机器学习模式能一并采用,每个都有其自己的“阶段”。回忆一下,这些模式分别是监督学习(SL)、强化学习(RL)、和推理学习(IL)。我们在上一篇文章中详讨了监督学习,其中移动平均线和随机振荡器的组合形态被归一化为特征的二元向量。随后,这些数据被投喂到一个简单的神经网络,我们依据 EURUSD 货币对的2023 年数据进行了训练,随后在 2024年数据上执行了前向测试。
由于我们的方式基于“强化学习可边学习边训练模型”的论点,我们打算在本文中通过来自早期监督学习的结果、以及网络来演示这一点。我们假设,强化学习是当部署时的反向传播形式,它能精细优调买卖决策,如此它们就不再仅仅基于价格变化预测,而是如同监督学习模型中的情况。
正如我们在过去的强化学习文章中所见,这种“优调”嫁接了探索和利用。故此,这般行事,我们的政策网络就能在实时市场环境中训练,并据其判定哪些状态应得出买入或卖出动作。有些情况下,看涨状态不一定意味着买入机会,反之亦然。这意味着我们的强化学习模型充当监督学习模型决策制定的额外过滤器。来自我们的监督学习模型中状态,使用了单维度连续值,这与我们将要用到的动作空间非常相似。
DDPG
我们已研究了数种不同的强化学习算法,至于本文,我们将考察深度判定性政策梯度(DDPG)。这个特定算法,有点像我们在之前文章中提到的 DQN,作用是在连续动作空间中进行预测。回想一下,我们最近研究的算法大都是分类器,考据输出下一步行动的概率分布,例如是买入、卖出、亦或持有。
这个不是分类器,而是回归器。我们定义一个动作空间,数据类型是浮点值,范围从 0.0 到 1.0。该方式能用来校准更多的选项,远不止简单几个:
- 买入(超过 0.5);
- 卖出(低于 0.5);
- 或持有(接近 0.5);
这可通过引入挂单类型,甚或仓位大小来达成。这些量值留给读者自行探索,在于我们将坚持最基本的骨架实现,而 0.5 作为关键阈值。
原则上,DDPG 利用神经网络近似 Q-值(来自动作的奖励),并直接优化政策(当环境状态呈现时,选择下一个最佳动作的网络),取代只估算 Q-值。不像 DQN 能用于离散/分类动作,如左或右,DDPG 纯粹针对连续动作空间。(比方说训练机器人时的转向角度、或电机扭矩)。它是如何运作的?
主要用到两种神经网络。
- 其一是参与者网络,其角色是决定对应给定环境状态的最佳动作。
- 另一个是评论者网络,其目的是估算运营该动作能获得的潜在回报,据其评估参与者所选动作的优劣。
该估算值也称为 Q-值。还有,DDPG 内的重点是经验回放缓冲区。它将以往的经验(表示状态、动作、奖励、和下一状态的统合)存储在缓冲区之中。从该缓冲区的随机抽样用于训练网络,并降低更新之间的相关性。
除了上述两个网络之外,它们的等价副本也被称为“目标”。这些参与者和评论者网络的分离副本,更新权重的配速较慢,据说这可提供一致的目标,有助于稳定训练进程。最后,探索作为强化学习的关键特性,在 DDPG 中更进一步,以算法为动作引入噪声成分,最常见的是奥恩斯坦-乌伦贝克(Ornstein-Uhlenbeck)噪声。
训练 DDPG 基本上涵盖三件事。首先,它涉及改进参与者网络,其中评论者网络指导参与者网络定义哪些行为是好或坏,如此令参与者网络更好地调整权重,选择最大化奖励的动作。其次,改进评论者网络,其中它能更好地利用 Bellman 更新估算奖励/Q-值,具体如下方程所示:

其中:
-
Q(s,a):在状态 s 下采取动作 a 的预测 Q-值(评论者的估测)。
-
r:在状态 s 下采取行动 a 后立即获得奖励。
-
γ:折扣因子(0≤γ<1),判定未来回报的多寡(接近 0 = 短期为主,接近 1 = 长期为主)。
-
s′:在状态 s 下采取动作 a 后观察到的下一个状态。
-
Qtarget(s′,⋅):目标 Q-网络针对下一个状态 s′估算的 Q-值(用于稳定训练)。
-
Actortarget(s′):目标参与者针对下一个状态 s′(判定性政策)推荐的动作。
最后,参与者目标和评论者目标模型遵循以下方程缓慢在线执行核心网络的更新:

其中:
- θtarget:目标网络(参与者或评论者)的参数(权重)。
- θ:主网络(在线)(参与者或评论者)的参数。
- τ:软性更新率(0≪τ≪1,例如 0.001)。控制更新目标网络的缓慢程度。
- 较小 τ = 目标网络变化非常缓慢(训练更稳定)。
- 较大 τ = 目标网络更新快速(稳定性较低,但或许适配更快)。
为何是 DDPG?它得以流行是因为它在高维连续动作空间中工作良好,且结合了 Q-学习的稳定性、及政策梯度的灵活性。如上文展示的机器人连续动作空间示例,它在机器人学、基于物理的控制、及其它类似复杂任务中十分流行。这并不意味着我们不能将其用于金融时间序列,这正是我们将要探讨的。
我们正在实现的代码大部分都用 Python 3.10,因为当训练很深的网络时,它能带来更高的效率。但在这个领域,时不时就会学到新东西。就我而言,Python 实际上能够在训练网络(PyTorch 和 TensorFlow)中完成如此快速的计算,这得益于 C/C++ 和 CUDA 中的锚代码和类。MQL5 与 C 语言非常相似,且实现 OpenCL 的支持已有一段时间。我觉得包含基本矩阵乘法的函数库(部分在 OpenCL 中)可能缺失,故在 MQL5 版本中能否获得类似性能?这或许值得我们去探讨一下。
回放缓冲区
回放缓冲区是 DDPG 及其它无政策强化学习算法中非常重要的成分。它主要用于打破连续样本之间的时态相关性,启用经验复用,如此令学习更有效率,为稳定的训练提供多样化的过渡,并存储以往的经验(状态、动作、奖励、下一个状态、已完成的元组),以备训练网络权重更新过程所用。
其核心实现主要从初始化函数开始:
def __init__(self, capacity): self.buffer = deque(maxlen=capacity)
我们正在调用 collections.deque,按固定最大容量,并当满负荷时遵照先进先出行为自动丢弃旧经验。它非常简单,且内存利用高效。接下来是推送操作,其中缓冲区存储完整的过渡元组,并处理成功和终端转换(通过完成标志)。当添加新经验时,它提供了极低开销。
def push(self, state, action, reward, next_state, done): self.buffer.append((state, action, reward, next_state, done))
所用的抽样机制是一种随机均匀抽样,这对于打破相关性非常重要。其高效之处在于通过 zip(*batch) 批量处理,其有助于分离环境分量。它返回 Q-学习更新所需的所有分量。
def sample(self, batch_size): batch = random.sample(self.buffer, batch_size) states, actions, rewards, next_states, dones = zip(*batch)
回放缓冲类的下一步是针对每个环境分量,进行张量转换和设备处理。如上所示,这些分别是状态、动作、奖励、下一状态、和完成。转换非常稳健。它能处理 NumPy 数组和 PyTorch 张量两者作为输入。这确保了张量(可取作含有梯度信息的数组)与计算图形分离。
我们把数据转移到 CPU,从而避免设备冲突。我们执行显式浮点张量(float-32)转换,这是神经网络的常见前提。这种数据类型比 MQL5 常用的双精度更小,计算效率明显更高。最后,得益于 PyTorch(不同于 TensorFlow),我们能够选择将数据移到特定的计算设备,譬如 GPU(若其可用的话)。
states = torch.FloatTensor( np.array([s.detach().cpu().numpy() if torch.is_tensor(s) else s for s in states]) ).to(device)
我们的回放缓冲类配合 DDPG 工作良好,它首先促进了无政策学习,因为 DDPG 需要一个回放缓冲区,以便从历史数据中学习。DDPG 的连续动作空间,可配合浮点张量转换得到良好处理。它经由随机抽样为 DDPG 提供了一些稳定性,有助于预防相关更新,从而令训练解除稳定性。它还增加了一定的灵活性,能搭配 NumPy 和 torch 输入两者工作,这在强化学习流水线中很常用。
潜在强化是改变了经验回放缓冲区优先级,以便处理重要过渡;采用多步返回、或 n 步学习;分离/分类不同类型的经验;并拥有更高效的张量转换,避免了 NumPy 中转。
整体上,我们的回放缓冲区类很稳健,因为我们用到 torch.is_tensor() 进行类型检查、设备处理以确保 CPU/GPU 兼容性,并且环境分量的干净剥离。性能也不受影响,因为 deque 提供 O(1) 的附加和删除操作;使用批处理令开销最小化;并实现了随机抽样,其对于中等规模的缓冲区来颇具效率。它还具备可维护性,给出的代码实现清晰简洁,能直截了当地扩展或修改;且在输出中提供了良好的类型一致性。
主要的限制和考虑因素可能来自内存用法。对于高过渡状态,存储完整的过渡可能非常庞大。此外,固定容量或许需要针对不同环境加以调校。另一个限制是抽样效率。统一抽样并不会优先考虑重要经验,因为全部都给出同等权重。抽样时也未处理局次边界。
解决部分问题的可能替代方案,包括基于磁盘存储非常大的缓冲区;基于图像状态来存储压缩的表示;以及额外支持,像是日志等,来存储附加信息。这些变化能为 DDPG 奠定坚实基础,令其能够基于特定应用需求进行扩展,同时维持其核心功能。
评论者与参与者网络
这两个网络都遵循相似的多层感知器结构,不过正如强化学习所预期,它们在 DDPG 中担负着不同目的。评论者网络(也称为 Q-函数)估算状态-动作对(Q-值、或奖励)的数值,而参与者网络(也称为政策网络)则判断给定状态的最优动作。
评论者网络的初始化和层结构形状如下:
def __init__(self, state_dim, action_dim, hidden_dim): super(Critic, self).__init__() self.fc1 = nn.Linear(state_dim + action_dim, hidden_dim) self.fc2 = nn.Linear(hidden_dim, hidden_dim) self.fc3 = nn.Linear(hidden_dim, 1)
此处的关键点是:它取状态和动作两者(正如我们在之前的强化学习算法中所见)作为输入,不同于其它方法中的数值函数;我们正实现的这个网络,采用三个全连接层,前两层隐藏了维度神经元;最终输出层仅输出一个 Q-值标量;该架构旨在估测连续动作空间的 Q(s,a)。
前向通验机制如下:
def forward(self, state, action): x = torch.cat([state, action], dim=1) x = self.relu(self.fc1(x)) x = self.relu(self.fc2(x)) q_value = self.fc3(x)
本实现内的“关键”组件是 torch.cat,其是 DDPG 动作值估算的根本。它在处理前结合了状态和动作输入向量。dim=1 尺寸确保批处理的正确级联。我们代码中另一个值得注意的部分是激活函数。针对隐藏层用到 ReLU,在于它有助于缓解梯度消失的问题。在最后一层上未执行激活,因为 Q-值能够是任意实数。
信息流从“状态-动作”对到隐藏层,再到 Q-值估算。它代表了 Q-学习函数的核心。参与者网络还有以下初始化和结构:
def __init__(self, state_dim, action_dim, hidden_dim): super(Actor, self).__init__() self.fc1 = nn.Linear(state_dim, hidden_dim) self.fc2 = nn.Linear(hidden_dim, hidden_dim) self.fc3 = nn.Linear(hidden_dim, action_dim) self.tanh = nn.Tanh()
此处值得注意的关键层面是:它只接受状态维度作为输入,因为政策依赖于状态。出于我们的目的,它遵循与上述评论者网络相似的三层结构,但输出的处理方式不同。最终层的尺寸与动作空间维度相匹配。针对输出层采用 Tanh 激活,对于界定动作非常重要。前向通验机制如下清单定义:
def forward(self, state):
x = self.relu(self.fc1(state))
x = self.relu(self.fc2(x))
action = self.tanh(self.fc3(x)) 这比评论者网络简单得多,后者只接收状态作为输入(不同于评论者),然后经由隐藏层构建状态表示。动作生成通过 Tanh 激活启用,其约束输出为 [-1, 1]。这对于 DDPG 的连续动作空间至关重要。这个固定范围能够重新调整到环境的行动范围,比如 [0,1],等等。此外,于此值得注意的是该政策固有确定性。输出的是具体动作,而非像随机政策方法常见的那样,输出的是跨离散动作集合的概率分布。
针对评论者网络选择的 DDPG 特殊设计,行事与其它强化学习算法持平,它们是:因状态和动作及连在一起,故输入需联动处理;得到一个在连续动作空间中工作良好的标量输出;且无预留的全范围估算 Q-值的激活。对于参与者网络,DDPG 设计选择通过 Tanh 界定输出,确保动作在可学习范围内;判定性质,因为追求的是更具体的动作权重,而非随机政策;以及动作-空间-匹配,最终层大小与环境的动作维度直接对齐。
我们的 DDPG 示例用到一维动作空间。状态空间也是一维空间,因为这是上一篇文章中所用的监督学习网络的输出。共享的架构特征是 ReLU 激活,其往往是深度强化学习中隐藏层的常用选择。我们经由同意维度维持了一致的隐藏尺寸,并具备适用于低维状态空间的 MLP 结构。
PyTorch 网络的实现优势并不突出,无论如何它们有这些:维度处理的稳健性,和输入/输出维度的清晰规格;激活管理,其中隐藏/输出激活之间适当分离;以及批处理支持,因为所有操作(在其张量中)都维持批量维度。此外,提升这些网络性能的一些考虑因素包括 ReLU 的效率,因该激活速度比其它激活类型更快,线性层的简单性(无卷积或递归),以及流水线前向通验中操作最小化。
关键网络的潜在强化包括:层归一化,这样能够i偶稳定学习;状态值的对立架构;以及像 TD3 中那样的多 Q-输出,可裁剪双 Q-学习。对于参与者网络,改进可能是噪声注入(尽管 DDPG 使用外部噪声);批量归一化以帮助处理不同的状态尺度;以及为了更稳定训练而进行的频谱归一化。
为了在 DDPG 境况中整合这两者:评论者网络在训练中的角色是为政策更新提供 Q-值估算,随后用于计算自身的时态差值目标。它需要精确评估输入、状态-动作值,以便量化调整政策(参与者网络权重 & 偏差)所需的程度。参与者在训练中的角色是提供计算环境功能、和 Q-值计算的动作,依据评论者 Q-值按升序更新梯度,并学习能够持续控制的平滑确定性政策。
结束语
在我们复审来自上一篇文章中 7 个形态的政策前向漫游测试报告之前,我们应当先查看 DDPG 智代类和环境数据类。不过,我们会在下一篇文章中涵盖这些内容,因为本文篇幅已经相当大了。此处涵盖的大部分内容是用 Python 编写的,目的是导出 ONNX 网络,集成到 MQL5 中作为资源。
Python 现在很重要,因为它在训练上比原产 MQL5 更高效,不过在将来的文章中也可能探讨利用 OpenCL 的变通方法。在向导中采用信号类汇编智能系统也将在下一篇文章中考察,故本文没有附件。
| 名称 | 描述 |
|---|---|
| wz_58_ddpg.py | 利用 Python 实现的强化学习 DDPG 脚本文件 |
本文由MetaQuotes Ltd译自英文
原文地址: https://www.mql5.com/en/articles/17668
注意: MetaQuotes Ltd.将保留所有关于这些材料的权利。全部或部分复制或者转载这些材料将被禁止。
本文由网站的一位用户撰写,反映了他们的个人观点。MetaQuotes Ltd 不对所提供信息的准确性负责,也不对因使用所述解决方案、策略或建议而产生的任何后果负责。
市场模拟(第九部分):套接字(三)
价格行为分析工具包开发(第 24 部分):价格行为量化分析工具
新手在交易中的10个基本错误
MQL5经济日历交易指南(第九部分):通过动态滚动条与界面优化提升新闻交互体验