English Русский Español Português
preview
交易中的神经网络:配备概念强化的多智代系统(FinCon)

交易中的神经网络:配备概念强化的多智代系统(FinCon)

MetaTrader 5交易系统 |
84 0
Dmitriy Gizlyk
Dmitriy Gizlyk

概述

金融市场具有高波动性和复杂性,为制定最优投资决策造成了重大挑战。交易者和投资组合经理必须考虑各种多模态数据,如宏观经济指标、技术信号、以及市场参与者的行为因素。这些努力的主要目标是最大化回报的同时风险最小化。

在传统金融机构中,数据处理和决策制定涉及多位专家:分析师进行市场调研,风险管理者评估潜在威胁,高管制定策略决策。然而,尽管存在层次化结构,人为因素和有限的资源往往阻碍了快速适应市场瞬时变化的能力。如是结果,自动化系统的运用变得日益显要:系统不仅加速分析过程,还能降低人为错误的可能性。

人工智能和金融技术的前沿研究专注于开发自适应软件解决方案。这样的系统能够从历史数据中学习,识别市场形态,并制定更明智的决策。近年来最有前景的方向之一是自然语言处理(NLP)方法的整合,能够分析财经新闻、专家预测、及其它基于文本的数据,从而提升预测准确性和风险评估。

此类系统的有效性主要取决于两个关键层面:系统组件之间的相互作用,以及它们自我持续学习的能力。研究表明,在专家团队协作上系统建模展示出卓越性能,随着新方式的采用,这些模型对于变化中的市场条件变得越来越适应。

现有解决方案,如 FinMemFinAgent,在自动化金融运作中取得了可观进展。然而,这些系统也有局限性:它们偏于注重短期市场动态,而往往缺乏全面的长期风险管理机制。甚至,计算资源的约束,和有限的算法灵活性,也能降低它们的推荐品质。

这些挑战在论文《FinCon:一款配备概念性词汇强化的综合 LLM 多智代系统,强化金融决策》中得以解决。作者提出了 FinCon,这是一款专门设计用于整合股票交易和投资组合管理流程的多智代系统。

FinCon 框架模拟专业投资团队的工作流程。分析智代从各种来源收集和分析数据,包括市场指标、新闻推送、和历史数据,而管理智代则综合这些见解,并制定最终决策。该方式最大限度地降低参与者之间的冗余沟通,并优化计算资源的占用。

作者设计的 FinCon 的运作,即能搭配独立金融资产、亦或多元化投资组合。这令该系统极具多样性。

FinCon 利用分析模型和机器学习算法执行实时风险评估。每次交易局次之后,系统都会献上操作后分析,辨别错误,并基于新获得的数据更新模型。

实证结果明示,FinCon 显著改进了风险管理,并强化了整体投资组合的绩效。


FinCon 架构

FinCon 架构拥有两级层次化结构,由两个主要组件组成:管控-分析智代组,和风险控制子系统。该结构确保了高效的信息处理,降低了出错概率,最小化决策制定成本,且能深度分析市场。

FinCon 框架好似一个组织良好的投资公司,所有资源都为最大效率而加以优化。其主要意向是提升信息感知和分析能力,同时最大限度减少沟通和数据处理开销。

分析智代在 FinCon 中扮演关键角色,从海量市场数据中提取主要投资灵感。每个智代都具备狭窄的专业性,防止数据重复和认知过载。在参考实现中,框架用到了七个分析智代。文本智代分析新闻报道、新闻稿、和财务报告,来辨别潜在风险和机会。音频智代解读来自公司高管的财报录音,检测情感细微差别、及关键讨论点。数据分析和股票选择智代计算量化量值,令管理者能够高精度预测市场趋势。

分析智代将输出提供给管控智代,由后者制定入场决策。至于交易决策,管控执行四项关键职能:整合分析结果、实时监控风险、持续回顾过往决策、以及完善投资信念。

FinCon 实现了两层风险控制机制。局内风险评估能够实现实时纠正动作,将短期损失最小化。局外风险评估比较跨局次结果,识别错误,并改进策略。这种双层方式确保系统对外部变化的韧性,并促进其持续改进。

更新投资信念在模型适应中扮演关键角色。它允许 FinCon 在数据提取期间调整分析智代的重点,并优调管控者的决策制定逻辑。参与者–评论者机制令 FinCon 能够基于给定的交易目标定期优化其交易策略。该方式结合了成功和失败动作的分析,可供持续完善其决策制定政策。

FinCon 的局次式反射由一种独特的机制驱动,称为概念性词汇强化(CVRF)。该部件通过比较分析师的洞察与管控者的决策,评估顺序交易局次的有效性。CVRF 把关键发现与特定的交易策略链接到一起。通过对比更高成功、或较低成功局次的概念洞见,模型生成信念调整的建议。这些洞察有助于智代专注于最相关的市场信息,从而提升整体投资组合绩效。

信念调整建议首先传达至管控者,然后选性分享至分析师。这最大限度地减少了冗余沟通,防止信息过载。该方法衡量连续学习轨迹之间重叠交易行为的比例,强化系统效率。在每个智代都有明确定义,且专业化角色的环境中尤为明显,促进了模型间的协同效应。

FinCon 提供了先进的记忆模块,划分为三个关键部分:工作记忆、程序记忆、和局次记忆。

工作记忆暂时存储持续操作所需的数据。这就能快速处理大批量信息,且不丢失上下文。

过程化记忆保留了之前局次中成功应用的算法和策略。该记忆能够快速适应重复任务,并重用经过验证的方法。

局次记忆记录关键事件、动作、和结果,这对于高级政策的细化尤为重要。这种记忆类型在模型的学习过程中扮演着关键角色,助其利用过去的成功和失败教训来提升未来表现。

FinCon 的层次结构令其成为一个高效、高适应性的系统。该框架的原始可视化提供如下。

作者对 FinCon 框架的可视化


实现 MQL5 版本

在探讨了 FinCon 框架的理论层面后,我们现在转入文章的实践章节,其中我们遵照所提议概念的解释实现 MQL5 版本。

重点要注意,原始的 FinCon 框架建立在预训练大语言模型(LLM)之上的。在我们的项目中,我们不使用语言模型。取而代之,我们仅用到 MQL5 环境中的可用工具来实现这些提议的理论。那么,我们先从改造记忆模块开始。

记忆模块改造方式


正如您或许的记忆,我们之前开发的记忆模块由两个不同架构设计的重现模块组成。这种设计能够创建一个信息衰减速率不同的两级记忆系统,令其在多元化任务中更具灵活性和适应性。该方式在需要同时考虑短期和长期依赖的状况下尤其实用。

注意,在我们的模型中,衰变率并未明确定义。取而代之,由于重现模块之间的架构差异,它自然而然地出现。其中一个模块专注于短期记忆,用于快速更新信息。另一个负责长期依赖性,覆盖较长区间保留重要数据。这些架构上的区分,可在处理速度与深度之间打造自然的平衡。

记忆模块内的信息存储在重现模块的隐藏状态之中。该方式显著降低记忆使用,但当必须提取和比较特定局次时,也带来了挑战。然而,这一能力对于实现概念验证机制至关重要,其需要比较当前、与之前存储局次的上下文。

进而,FinCon 框架的作者强调采用三级记忆系统对于更精确的分析和预测至关重要。由此,有必要通过引入额外的局次记忆层来升级现有的记忆模块。

优化记忆模块的过程包含若干重要步骤。首先,它最小化计算资源的使用。这可通过集成数据压缩算法来达成。这样的算法剔除冗余信息,降低每局次的记忆需求,同时保持数据的本质特性。

另一个重要任务是确保快速且准确地获取相关信息。为达成这一点,建议使用向量相似度算法。这些算法令系统能够快速定位与当前事件最相似的局次 — 这是实时应用中的关键功能。

如是结果,改造的记忆模块将成为提升该模型整体效率的基石。它不仅确保数据存储紧凑,还能快速访问相关信息,显著强化决策制定过程。

新记忆模块的实现


我们在一个名为 CNeuronMemoryDistil 的新对象中实现所提议方法。其结构呈现如下。

class CNeuronMemoryDistil  :  public CNeuronMemory
  {
protected:
   CNeuronBaseOCL       cConcatenated;
   CNeuronTransposeOCL  cTransposeConc;
   CNeuronConvOCL       cConvolution;
   CNeuronEmbeddingOCL  cDistilMemory;
   CNeuronRelativeCrossAttention cCrossAttention;
   //---
   virtual bool      feedForward(CNeuronBaseOCL *NeuronOCL) override;
   virtual bool      calcInputGradients(CNeuronBaseOCL *NeuronOCL) override;
   virtual bool      updateInputWeights(CNeuronBaseOCL *NeuronOCL) override;

public:
                     CNeuronMemoryDistil(void) {};
                    ~CNeuronMemoryDistil(void) {};
   //---
   virtual bool      Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl,
                          uint window, uint window_key, uint units_count,
                          uint heads, uint stack_size,
                          ENUM_OPTIMIZATION optimization_type, uint batch);
   //---
   virtual int       Type(void) override
 const   {  return defNeuronMemoryDistil; }
   //---
   virtual bool      Save(int const file_handle) override;
   virtual bool      Load(int const file_handle) override;
   //---
   virtual bool      WeightsUpdate(CNeuronBaseOCL *source, float tau) override;
   virtual void      SetOpenCL(COpenCLMy *obj) override;
   //---
   virtual bool      Clear(void) override;
  };

在我们的实现中,父类是之前开发的记忆对象,我们继承了所有核心接口,以及短期和长期记忆的两个重现模块。在新类内声明的内部对象,形成了局次记忆的基础。这允许存储和处理与特定局次相关的数据。每个对象在整体记忆结构中执行专门角色,令数据分析更加精准和全面。它们的功能将在记忆模块方法实现期间详述。

所有内部对象都声明为静态,允许我们将构造和析构函数留空。该方式优化了记忆使用,并在创建或销毁对象期间最小化出错风险,强化了系统稳定性。

继承对象和新声明对象两者的初始化均在 Init 方法中发生。方法参数包括一组定义对象架构的常量,其为模型配置特定任务提供必要的灵活性,同时保持完整性和功能性。

bool CNeuronMemoryDistil::Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl,
                               uint window, uint window_key, uint units_count,
                               uint heads, uint stack_size,
                               ENUM_OPTIMIZATION optimization_type, uint batch)
  {
   if(!CNeuronRelativeCrossAttention::Init(numOutputs, myIndex, open_cl, window,
                                         window_key, units_count, heads, window,
                                       2 * stack_size, optimization_type, batch))
      return false;

在方法主体内,我们按惯例调用父类 Init 方法来初始化继承的对象,传递相应的参数。然而,由于新对象的独有特性,无法直接调用基本记忆模块的初始化方法。取而代之,我们采用来自交叉注意力对象的类似方法,作为基本记忆模块的父节点。这确保了新架构各部分的一致性和正常功能。

展望未来,我们的记忆模块会按局次记忆的背景来分析当前状态,输出预期值。此处,交叉注意力模块扮演者着关键角色,执行两个主要功能。第一个是找到最相关的局次。为实现该任务,框架使用向量相似度算法,其基础是注意力机制的依赖系数。

交叉注意力模块的第二个功能是依据选定局次的上下文来丰化原始状态。这能打造更完整、更具信息量的表述,提升数据处理和决策准确性。

在初始化期间,我们将源数据参数传递给交叉注意力对象,上下文序列长度则设置为局次记忆缓冲区大小的两倍。这样就能容纳短期和长期记忆模块两者的结果。

交叉注意力对象成功初始化之后,我们调用继承的短期和长期重现模块的初始化方法。我们取用的该过程来自父类方法。

   uint index = 0;
   if(!cLSTM.Init(0, index, OpenCL, iWindow, iUnits, optimization, iBatch))
      return false;
   index++;
   if(!cMamba.Init(0, index, OpenCL, iWindow, 2 * iWindow, iUnits, optimization,
                                                                        iBatch))
      return false;

这些模块的输出被级联到一个缓冲区中,允许并发访问两种记忆类型。为此目的创建一个足够大的基准对象。

   index++;
   if(!cConcatenated.Init(0, index, OpenCL, 2 * iWindow * iUnits, optimization,
                                                                       iBatch))
      return false;
   cConcatenated.SetActivationFunction(None);

接着,将级联的信息压缩,并集成到局次记忆存储对象之中。

由于我们正与代表单一环境状态的多模态时间序列共事,因此在压缩过程中保持单位序列的关键特征非常重要。采用两阶段压缩方式。第一步是针对单个单元序列进行初步压缩,提取关键特征,并降低数据量,同时不损失完整性。

转置级联张量,按单变量序列表述数据。

   index++;
   if(!cTransposeConc.Init(0, index, OpenCL, iUnits, 2 * iWindow, optimization,
                                                                       iBatch))
      return false;

然后通过卷积层对数据进行压缩。

   index++;
   if(!cConvolution.Init(0, index, OpenCL, iUnits, iUnits, iWindowKey, iWindow,
                                                      1, optimization, iBatch))
      return false;
   cConvolution.SetActivationFunction(GELU);

为了存储局次记忆,我们应用了一个嵌入层,其中部分压缩状态投影为紧凑的潜在表示,并加入固定长度的先进先出FIFO)内存堆栈之中。

每个张量模块都通过可训练的投影矩阵投影到潜在空间当中。这些矩阵将多模态数据从原产格式转换为统一表示。该方式简化了进一步分析,并确保当整合来自不同来源信息时,数据的一致性。在此情况下,这些分别是短期和长期记忆模块。

   index++;
   uint windows[] = {iWindowKey * iWindow, iWindowKey * iWindow};
   if(!cDistilMemory.Init(0, index, OpenCL, iUnitsKV / 2, iWindow, windows))
      return false;

如早前所述,局次记忆背景下的原产数据分析是由交叉注意力基准对象执行。为了更全面的分析,引入了一个额外的交叉注意力对象,于短期和长期记忆的上下文内处理源数据。该方式有助于捕捉不同记忆类型的协同效应。

之前创建的级联对象简化了这种集成过程。如是结果,一个单交叉注意力对象可审计两个记忆模块,来丰化数据。这优化了计算资源,强化了分析精度。

   index++;
   if(!cCrossAttention.Init(0, index, OpenCL, iWindow, iWindowKey, iUnits, iHeads,
                                       iWindow, 2 * iUnits, optimization, iBatch))
      return false;
//---
   return true;
  }

所有内部对象初始化之后,方法会返回一个逻辑结果至调用程序。

接下来,我们转至 feedForward 方法,构造新模块的前馈通验。

bool CNeuronMemoryDistil::feedForward(CNeuronBaseOCL *NeuronOCL)
  {
   if(!cLSTM.FeedForward(NeuronOCL))
      return false;
   if(!cMamba.FeedForward(NeuronOCL))
      return false;

在方法参数中,接收指向源数据对象的指针,并立即传递给相应的短期和长期重现模块方法。它们的输出被级联到一个数据缓冲区中。

   if(!Concat(cLSTM.getOutput(), cMamba.getOutput(), cConcatenated.getOutput(),
                                                     iWindow, iWindow, iUnits))
      return false;
   if(!cTransposeConc.FeedForward(cConcatenated.AsObject()))
      return false;

注意,我们以单个时间步执行数据级联。这种逐步级联保留了所有单元序列的结构。

级联张量由卷积层移置和压缩。

   if(!cConvolution.FeedForward(cTransposeConc.AsObject()))
      return false;

压缩后的表示通过嵌入层投影到局次记忆。

   if(!cDistilMemory.FeedForward(cConvolution.AsObject()))
      return false;

在该阶段,我们已在记忆模块的三层中保存了所需的信息量。接下来,我们需要据关键事件的背景来丰化当前环境状态。首先,我们分析来自短期和长期记忆上下文中的源数据。

   if(!cCrossAttention.FeedForward(NeuronOCL, cConcatenated.getOutput()))
      return false;

然后我们利用局次记忆中的上下文来丰化数据。

   return CNeuronRelativeCrossAttention::feedForward(cCrossAttention.AsObject(),
                                                     cDistilMemory.getOutput());
  }

逻辑结果返回至调用程序。

实现前馈方法之后,我们继续反向传播算法。反向传播通验包含两个关键方法:

  • calcInputGradients — 传播误差梯度。
  • updateInputWeights — 更新模型参数。

误差梯度分派方法中的数据流以逆反顺序镜像前馈通验算法。

calcInputGradients 方法的参数中,我们收到指向与前馈通验相同的源数据对象指针。不过这次我们传播的是影响模型最终输出数据的误差梯度。

bool CNeuronMemoryDistil::calcInputGradients(CNeuronBaseOCL *NeuronOCL)
  {
   if(!NeuronOCL)
      return false;

方法伊始,我们立即验证接收指针的有效性,因其若无效,后续操作将变得毫无意义。

前馈通验调用父类交叉注意力方法结束。相应地,误差梯度分派过程从对应的同一对象的方法开始。在该阶段,梯度经由记忆层的信息流传播。

  if(!CNeuronRelativeCrossAttention::calcInputGradients(cCrossAttention.AsObject(),
                                                         cDistilMemory.getOutput(),
                                                       cDistilMemory.getGradient(),
                                      (ENUM_ACTIVATION)cDistilMemory.Activation()))
      return false;

局次记忆梯度会经由数据压缩层传递到短期和长期级联对象层。

   if(!cConvolution.calcHiddenGradients(cDistilMemory.AsObject()))
      return false;
   if(!cTransposeConc.calcHiddenGradients(cConvolution.AsObject()))
      return false;
   if(!cConcatenated.calcHiddenGradients(cTransposeConc.AsObject()))
      return false;

然而,该级联对象也用于分析两种记忆类型的输入数据。因此,误差梯度也必须通过第二条信息流传播。

   if(!NeuronOCL.calcHiddenGradients(cCrossAttention.AsObject(),
                                     cConcatenated.getOutput(),
                                     cConcatenated.getPrevOutput(),
                                     (ENUM_ACTIVATION)cConcatenated.Activation()))
      return false;

重点要注意,在这种情况下,我们使用级联对象的自由缓冲区,而非其专用缓冲区来获得误差梯度。该方式保留了先前计算的数据,避免覆盖有价值的信息。

接下来,我汇总来自两条信息流的数值,并在相应的记忆对象之间分派所得梯度。

   if(!SumAndNormilize(cConcatenated.getGradient(), cConcatenated.getPrevOutput(),
                       cConcatenated.getGradient(), iWindow, false, 0, 0, 0, 1) ||
      !DeConcat(cLSTM.getGradient(), cMamba.getGradient(), 
                cConcatenated.getGradient(), iWindow, iWindow, iUnits))
      return false;

于此必须强调,我们有意避免级联对象应用激活函数,以便防止数据失真。这是因为短期记忆和长期记忆模块或许用到不同的激活函数。然而,在将误差梯度分派到记忆模块之后,我们必须检查每个对象是否包含激活函数,如果包含,则利用这些激活函数的导数调整梯度值。

   if(cLSTM.Activation() != None)
      if(!DeActivation(cLSTM.getOutput(), cLSTM.getGradient(), 
                       cLSTM.getGradient(), cLSTM.Activation()))
         return false;
   if(cMamba.Activation() != None)
      if(!DeActivation(cMamba.getOutput(), cMamba.getGradient(), 
                       cMamba.getGradient(), cMamba.Activation()))
         return false;

此刻,我们将误差梯度经由短期和长期记忆管道向下传播至原始输入数据层。然而,请记住,该对象的梯度缓冲区已经包含上下文信息分析期间获得的数据。为了保留这些先前计算的值,我们必须在执行后续操作前暂时交换缓冲区指针。

   CBufferFloat *temp = NeuronOCL.getGradient();
   if(!NeuronOCL.SetGradient(cConcatenated.getPrevOutput(), false) ||
      !NeuronOCL.calcHiddenGradients(cLSTM.AsObject()) ||
      !SumAndNormilize(temp, NeuronOCL.getGradient(), temp, iWindow,
                                                  false, 0, 0, 0, 1))
      return false;

一旦替换完成,我们会依次将误差梯度进公园相应记忆模块的信息流传播,并将新值加入之前累积的数据当中。

   if(!NeuronOCL.calcHiddenGradients(cMamba.AsObject()) ||
      !SumAndNormilize(temp, NeuronOCL.getGradient(), temp, iWindow,
                                               false, 0, 0, 0, 1) ||
      !NeuronOCL.SetGradient(temp, false))
      return false;
//---
   return true;
  }

该步骤之后,我们把缓冲区指针恢复到原始状态。我们将操作的逻辑结果返回至调用程序,并完成方法的执行。

我们在改造的记忆模块 CNeuronMemoryDistil 中的实现方法至此完毕。附件中提供了该对象、及其所有方法的完整代码,供进一步研究。

我们工作的下一阶段是构造分析智代对象。不过,由于我们正接近文章篇幅的限制,我们将稍作休息,在下一部分继续这项工作。


结束语

本文探讨了 FinCon 框架,这是一款创新的多智代系统,旨在强化金融决策制定能力。该框架整合了层次化“管控-分析”互动结构与概念性言语强化机制,实现协调的智代协作和有效的风险管理。这些特性令模型能够成功处理各种财经任务,展现出在动态市场环境中的高适应性和性能。

在实践章节,我们开始实现所提议方法的 MQL5 版本。这项工作将在下一篇文章中继续,我们将依据真实历史市场数据,来评估已实现解决方案的性能和效率。


参考


文章中所用程序

# 名称 类型 说明
1 Research.mq5 智能系统 收集样本的智能系统
2 ResearchRealORL.mq5
智能系统
利用 Real-ORL 方法收集样本的智能系统
3 Study.mq5 智能系统 模型训练 EA
4 Test.mq5 智能系统 模型测试智能系统
5 Trajectory.mqh 类库 系统状态和模型架构描述结构
6 NeuroNet.mqh 类库 创建神经网络的类库
7 NeuroNet.cl 代码库 OpenCL 程序代码

本文由MetaQuotes Ltd译自俄文
原文地址: https://www.mql5.com/ru/articles/16916

附加的文件 |
MQL5.zip (2352.32 KB)
交易中的神经网络:配备概念强化的多智代系统(终篇) 交易中的神经网络:配备概念强化的多智代系统(终篇)
我们继续实现 FinCon 框架作者提议的方式。FinCon 是一款基于大语言模型(LLM)的多智代系统。今天,我们将实现必要的模块,并在真实历史数据上全面测试模型。
交易中的神经网络:针对金融市场的多模态、扩增工具型智代(终篇) 交易中的神经网络:针对金融市场的多模态、扩增工具型智代(终篇)
我们持续开发 FinAgent 算法,其是一款多模态金融交易智代,旨在分析多模态市场动态数据,以及历史交易形态。
交易中的神经网络:针对加密货币市场的记忆扩充上下文感知学习(MacroHFT) 交易中的神经网络:针对加密货币市场的记忆扩充上下文感知学习(MacroHFT)
我邀请您探索 MacroHFT 框架,该框架应用了上下文感知强化学习和记忆,利用宏观经济数据和自适应智代改进加密货币高频交易决策。
从基础到中级:结构(二) 从基础到中级:结构(二)
在本文中,我们将尝试理解为什么像 MQL5 这样的编程语言有结构,为什么在某些情况下,结构是在函数和过程之间传递值的理想方式,而在其他情况下,它们可能不是最好的方式。