交易中的神经网络:配备概念强化的多智代系统(终篇)
概述
在上一篇文章中,我们探讨了 FinCon 框架的理论层面,其是作为金融领域分析和自动化工具而开发的。其目标是利用大数据处理、自然语言处理(NLP)、以及投资组合管理技术,协助金融市场的决策。系统的核心理念在于采用多智代架构,每个模块执行特定任务,同时与其它模块互动,来达成共同目标。
该架构的一个关键组件是管控智代,它协调分析智代的工作。管控聚集分析师产生的成果,执行风险控制,并细化投资策略。FinCon 雇佣专门的分析智代,每一位负责不同层面的数据处理与分析、市场预测、及风险评估。这种分工降低了信息冗余,加速了数据处理。
该框架实现了两级风险管控架构:
- 第一级实时操作,最小化短期损失。
- 第二级则基于已完成的回合评估系统动作,识别错误,并改进策略。
FinCon 的一个关键特点是使用概念性言语强化反馈(CVRF)。该机制评估分析智代的表现,以及由管控所制定的交易决策。这样系统能够从自身经验中学习,专注于最具影响力的市场因素,优调行为政策。
该框架还包括三级记忆系统:
- 工作记忆暂时存储持续操作所需的数据。
- 过程记忆保留经过验证的方法和算法以供重用。
- 回合记忆记录关键事件及其结果,允许系统分析过往的经验,并把学识应用于未来的决策。
FinCon 框架的原始可视化如下。

在上一篇文章中,我们针对框架作者提议方式,开始实现的自我解释。在 CNeuronMemoryDistil 对象中,我们构建了三层记忆系统的算法。今天,我们继续这项工作。
分析智代对象
我们先开始构造分析智代模块。FinCon 作者设计了一个通用智代模块,能够跨多元领域运行,独立于具体任务。这种灵活性是经由一个围绕预训练大语言模型(LLM)构建的架构来达成,其功能基于问答(QA)原理。智代的行为取决于它收到的问题或任务。
尽管我们的模型未用到大语言模型(LLM),但我们仍然可以创建一个通用对象,适用于各种专业分析智代。该方式确保了系统的灵活性和模块化。
据作者之言,FinCon 智代集成了若干关键模块,共同支持其功能。
配置与剖析模块在定义智代任务类型方面扮演重要角色。它不仅设定交易目标,包括经济板块和绩效量值的详情,还将角色和责任分派给智代。该模块形成了一个基础文本框架,用于生成记忆数据库的功能性查询。
此外,配置与剖析模块令智代能够适应不同经济板块,识别当前任务中最相关的量值。由它生成的信息成为所有系统组件之间连贯交互的基础。
感知模块管理智代与其环境的交互。它通过过滤数据和识别有意义的形态来调控市场信息的感知。这令智代能够适应变化的条件,同时维护其预测的准确性和效率。
记忆模块是关键组件,确保决策制定所需的数据存储和处理。它由三个关键部分组成:工作记忆、过程记忆、和回合记忆。工作记忆令智代能够执行持续任务、监控市场变化、并调整其动作。过程记忆记录智代采取的所有步骤,包括结果和结论。回合记忆存储已完成任务的数据,为制定长期策略做出贡献。
在之前的工作中,我们已经开发了记忆模块,现在就能用现成的解决方案。值得注意的是,原版 FinCon 框架只允许管理器访问回合记忆。在我们的实现中,所有智代都利用三级记忆结构。每个智代都拥有自己的记忆模块,自然限制访问仅与其特定任务相关的数据。这种设计不仅允许每名智代参考近期的变化,还能考虑它们更广泛的时态背景。
配置和剖析模块的功能假设有专用外部对象存在,即根据每名智代的专业化、及可用输入数据来生成任务。在我们的实现中,我们假设输入数据是均匀的。这意味着固定智代角色,在每个步骤都会生成雷同的查询。然而,模型训练期间,这些查询可被调整,以便更好地符合智代当前的角色和技能。
这一原由引发在智代模块内创建一个可训练查询张量的思路。该方式剔除了对外部信息流的需求。该张量的初始值在对象创建期间会被随机初始化。这些参数形成了智代的“先天认知能力”。这为其未来学习奠定了独特的基础。
随着训练进度,智代逐渐发展出最适合其初始化时定义的固有能力的角色。这令智代能够有机地适应其任务,同时高效利用其“内在”特性,为进一步发展奠定坚实基础。可训练查询张量成为识别和强化最合适发展轨迹的关键工具。该设计确保了智代初始随机状态与目标角色之间的一致性,降低了训练成本,并提升整体模型效率。
感知模块的主要目标是识别方法,即能够从数据流中提取与智代任务最相关的形态。为了实现这一功能,我们用到交叉注意力机制。这样就能令模型“高亮”最相关的信息,确保有效的过滤和数据处理。
智代内部模块构造之后,下一重要步骤是分析其输出。一个中心问题在于结果的特殊性。一方面,这种特殊性依赖智代的任务,这看似与通用智代的概念相矛盾。另一方面,多元化的输出令结果处理变得复杂,故标准化必不可少。
在我们的实现中,每名智代生成一个张量,代表拟议的交易决策作为输出。最初的 FinCon 框架独家授权管控来生成交易决策。不过,智代提交自己的提案没有约束。该方式令我们能够创建一个统一的数据结构,来表示智代的输出,无论其具体角色如何。这种标准化简化了结果处理,提升了整体系统的效率。
上述所有概念均已在 CNeuronFinConAgent 对象中实现。其结构呈现如下。
class CNeuronFinConAgent : public CNeuronRelativeCrossAttention { protected: CNeuronMemoryDistil cStatesMemory; CNeuronMemoryDistil cActionsMemory; CNeuronBaseOCL caRole[2]; CNeuronRelativeCrossAttention cStateToRole; //--- virtual bool feedForward(CNeuronBaseOCL *NeuronOCL) override; virtual bool feedForward(CNeuronBaseOCL *NeuronOCL, CBufferFloat *SecondInput) override { return feedForward(NeuronOCL); } virtual bool calcInputGradients(CNeuronBaseOCL *NeuronOCL) override; virtual bool calcInputGradients(CNeuronBaseOCL *NeuronOCL, CBufferFloat *SecondInput, CBufferFloat *SecondGradient, ENUM_ACTIVATION SecondActivation = None) override { return calcInputGradients(NeuronOCL); } virtual bool updateInputWeights(CNeuronBaseOCL *NeuronOCL) override; virtual bool updateInputWeights(CNeuronBaseOCL *NeuronOCL, CBufferFloat *SecondInput) override { return updateInputWeights(NeuronOCL); } public: CNeuronFinConAgent(void) {}; ~CNeuronFinConAgent(void) {}; //--- virtual bool Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl, uint window, uint window_key, uint units_count, uint heads, uint stack_size, uint action_space, ENUM_OPTIMIZATION optimization_type, uint batch); //--- virtual int Type(void) override const { return defNeuronFinConAgent; } //--- 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 CNeuronFinConAgent::Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl, uint window, uint window_key, uint units_count, uint heads, uint stack_size, uint action_space, ENUM_OPTIMIZATION optimization_type, uint batch) { if(!CNeuronRelativeCrossAttention::Init(numOutputs, myIndex, open_cl, 3, window_key, action_space / 3, heads, window, units_count, optimization_type, batch)) return false;
在方法主体中,我们(如常)首先调用父类同名方法,其已规划了继承对象的初始化,以及与外部组件数据交换的接口。
如早前所述,交叉注意力对象被选作父类。该类对象设计用于处理两条数据流,在 FinCon 智代的背景下可能显得有些可疑,在于它们搭配特意针对它们所分配任务的单条信息流进行操作。然而,智代也会接收来自记忆模块的数据。这引入了第二条数据流。甚至,智代操作的一个关键层面是其顺序分析 — 即反射自身行为,并据变化的市场条件做出调整反应的能力。这一反射过程实际上创造了第三条信息流。
在我们的实现中,反射功能将通过继承自父类的机制进行组织。在演化中的市场条件背景下,交叉注意力方式预期能有效地调整先前结果的张量。因此,父对象的主要数据流将由结果张量参数组成,而第二条流则包含当前环境状态的信息。
回想一下,在智代输出处,我们期望得到一个推荐交易操作的张量。
接下来,我们初始化两个注意力模块。这些模块分别存储市场状况的动态,以及由智代拟议的交易决策序列。这种结构允许我们更好地评估当前市场动态背景下所应用行为政策的有效性。
int index = 0; if(!cStatesMemory.Init(0, index, OpenCL, window, iWindowKey, iUnitsKV, iHeads, stack_size, optimization, iBatch)) return false; index++; if(!cActionsMemory.Init(0, index, OpenCL, iWindow, iWindowKey, iUnits, iHeads, stack_size, optimization, iBatch)) return false;
剖析模块由两个顺序的全连接层构成。第一层包含一个固定值为 1 的元素,而第二层生成指定大小的张量。在我们的实现中,生成的向量长度是输入序列中单个元素描述的十倍。这可被理解为经由十个元素序列代表智代的角色。
index++; if(!caRole[0].Init(10 * iWindow, index, OpenCL, 1, optimization, iBatch)) return false; CBufferFloat *out = caRole[0].getOutput(); if(!out || !out.Fill(1)) return false; index++; if(!caRole[1].Init(0, index, OpenCL, 10 * iWindow, optimization, iBatch)) return false;
如前讨论,感知模块由一个内部交叉注意力对象表示。它在智代专精的背景下分析接收到的输入数据。
index++; if(!cStateToRole.Init(0, index, OpenCL, window, iWindowKey, iUnitsKV, iHeads, iWindow, 10, optimization, iBatch)) return false; //--- return true; }
所有内部和继承对象成功初始化之后,我们返回一个逻辑结果至调用程序,并结束方法的执行。
下一阶段的开发涉及在 feedForward 方法中实现前馈通验算法。于此,我们必须组织好之前初始化对象之间的信息流。
bool CNeuronFinConAgent::feedForward(CNeuronBaseOCL *NeuronOCL) { if(bTrain && !caRole[1].FeedForward(caRole[0].AsObject())) return false;
方法参数包括指向输入数据对象的指针,其中包含环境状态的描述。重点要记住,每个智代根据其具体角色分析输入信息。因此,我们首先生成描述指定任务的张量。
注意,智代角色张量仅在训练期间生成。在测试和生产模式下,智代的专精保持不变,且每次迭代无需重新生成该张量。
接下来,我们利用内部交叉注意力对象提取与解决智代所分配任务相关的形态。
if(!cStateToRole.FeedForward(NeuronOCL, caRole[1].getOutput())) return false; if(!cStatesMemory.FeedForward(cStateToRole.AsObject())) return false;
所获数值随后传递到环境状态记忆模块,据先前市场动态的信息来丰富当前状态。该方式提供了更深度的上下文理解。
类似地,我们将上一次前馈通验的结果添加到智代动作记忆模块之中。
if(!cActionsMemory.FeedForward(this.AsObject())) return false;
如是结果,两个记忆模块输出描述智代最近动作、及相应的环境变化的张量。这些数据会传递到父类同名方法,其鉴于当前市场动态调整推荐交易操作的张量。
在该步骤之前,需要交换数据缓冲区的指针,从而保留之前的结果张量。这确保了模型训练期间反向传播操作的正确执行。
if(!SwapBuffers(Output, PrevOutput)) return false; //--- return CNeuronRelativeCrossAttention::feedForward(cActionsMemory.AsObject(), cStatesMemory.getOutput()); }
这些操作的逻辑结果会返回给调用程序,并结束方法。
前馈算法完成后,我们继续组织反向传播通验的信息流。众所周知,在梯度传播期间,数据流与前馈相位的结构相似,但方向对立。好在前向和后向通验的路由雷同,模型能够高效地参考每个参数对最终结果的影响。
梯度分派运算在 calcInputGradients 方法里实现。该方法接收指向输入数据对象的指针,但这次我们必须传递反映输入数据对模型最终结果影响的误差梯度值。
bool CNeuronFinConAgent::calcInputGradients(CNeuronBaseOCL *NeuronOCL) { if(!NeuronOCL) return false;
在方法内,我们首先检查收到指针的有效性,因为若其无效,后续操作无意义。
真实梯度分派过程始于调用父类同名方法。它将误差梯度传递给注意力模块。
if(!CNeuronRelativeCrossAttention::calcInputGradients(cActionsMemory.AsObject(), cStatesMemory.getOutput(), cStatesMemory.getGradient(), (ENUM_ACTIVATION)cStatesMemory.Activation())) return false;
经由交易操作提案记忆模块,我们将误差梯度传递回当前对象。因为它之前的前馈结果被当作该记忆模块的输入。然而,结果缓冲区现在包含了来自最新前馈操作获得的不同值。甚至,我们打算保留梯度缓冲区当前值。为达成这一点,我们首先通过交换缓冲区指针来恢复上一次前馈通验的结果。接下来,我们将梯度缓冲指针替换为自由数据缓冲区。仅当完成这些准备工作后,我们才会继续分派误差梯度。
CBufferFloat *temp = Gradient; if(!SwapBuffers(Output, PrevOutput) || !SetGradient(cActionsMemory.getPrevOutput(), false)) return false; if(!calcHiddenGradients(cActionsMemory.AsObject())) return false; if(!SwapBuffers(Output, PrevOutput)) return false; Gradient = temp;
重点要注意,我们不会递归地将梯度传播到更早的通验。因此,来自这些操作获得的梯度不会被复用。无论如何,这些步骤对于确保记忆模块内部对象间梯度的正确分派是必要的。完成这些操作后,我们会恢复原始的缓冲指针。
然后我们将误差梯度分派到环境状态记忆模块的管道。于此,梯度首先传播到感知模块,如早前所述,感知模块由交叉注意力模块实现。
if(!cStateToRole.calcHiddenGradients(cStatesMemory.AsObject())) return false;
然后,我们根据它们对模型性能的影响,将获得的误差梯度分派到输入数据与负责生成智代角色张量的 MLP。
if(!NeuronOCL.calcHiddenGradients(cStateToRole.AsObject(), caRole[1].getOutput(), caRole[1].getGradient(), (ENUM_ACTIVATION)caRole[1].Activation())) return false; //--- return true; }
我们不会经由生成智代角色张量的 MLP 传播梯度,因为它的第一层包含固定值。
所有必要操作完成后,方法返回逻辑成功标志,并终止执行。
我们构造通用分析智代对象方法所用算法至此完毕。您能在附件中找到该类、及其所有方法的完整代码。
管控对象
我们的下一阶段工作是构造管控智代对象。此处,浮现些许概念上的不协调。一方面,我们曾讨论过构建一个通用智代功能,也能兼任管控。另一方面,管控者的角色是整合结果,并协调所有智代的动作。这意味着它必须接收来自多源的信息。
以下实现能够具有不同途径的视野。例如,作为之前构建的通用智代的适配,来执行管控功能。事实上,通用智代在此作为新对象的父类 — 其结构如下所示。
class CNeuronFinConManager : public CNeuronFinConAgent { protected: CNeuronTransposeOCL cTransposeState; CNeuronFinConAgent caAgents[3]; CNeuronFinConAgent caTrAgents[3]; CNeuronFinConAgent cRiskAgent; CNeuronBaseOCL cConcatenatedAgents; CNeuronBaseOCL cAccount; //--- virtual bool feedForward(CNeuronBaseOCL *NeuronOCL) override { return false; } virtual bool feedForward(CNeuronBaseOCL *NeuronOCL, CBufferFloat *SecondInput) override; virtual bool calcInputGradients(CNeuronBaseOCL *NeuronOCL) override {return false; } virtual bool calcInputGradients(CNeuronBaseOCL *NeuronOCL, CBufferFloat *SecondInput, CBufferFloat *SecondGradient, ENUM_ACTIVATION SecondActivation = None) override; virtual bool updateInputWeights(CNeuronBaseOCL *NeuronOCL) override {return false; } virtual bool updateInputWeights(CNeuronBaseOCL *NeuronOCL, CBufferFloat *SecondInput) override; public: CNeuronFinConManager(void) {}; ~CNeuronFinConManager(void) {}; //--- virtual bool Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl, uint window, uint window_key, uint units_count, uint heads, uint stack_size, uint account_descr, uint action_space, ENUM_OPTIMIZATION optimization_type, uint batch); //--- virtual int Type(void) override const { return defNeuronFinConManager; } //--- 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; virtual void TrainMode(bool flag); };
为了最小化外部数据流,我们将所有智代集成在管控对象内部。在这种配置中,管控可以被视为一个自包含的 FinCon 框架。不过,这更多是解读问题。我们来专注于开发这个新对象的功能。
在新对象结构中,我们再次见到一组熟悉的可覆写方法、及若干内部对象,我们将在设计类方法算法时探讨它们的作用。
所有内部对象都声明为静态,允许我们将类构造和析构函数留空。所有声明和继承对象的初始化,均在 Init 方法中执行。所有内部对象都声明为静态对象,允许类的构造和解构函数留空。
bool CNeuronFinConManager::Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl, uint window, uint window_key, uint units_count, uint heads, uint stack_size, uint account_descr, uint action_space, ENUM_OPTIMIZATION optimization_type, uint batch) { if(!CNeuronFinConAgent::Init(numOutputs, myIndex, open_cl, action_space, window_key, caAgents.Size() + caTrAgents.Size() + 1, heads, stack_size, action_space, optimization_type, batch)) return false;
在方法主体中,如常,我们调用父类的相关方法。但这次情况有细微差别。管控的初始数据是智代工作的成果。因此,管控的输入窗口对应于单一智代结果向量的维度,而序列长度等于包括风险评估智代在内的内部智代总数量。
应当注意,我们的管控会与两种类型的分析智代共事。它们各自从不同角度分析当前环境。为了获得输入数据的第二种投影,我们使用矩阵转置对象。
int index = 0; if(!cTransposeState.Init(0, index, OpenCL, units_count, window, optimization, iBatch)) return false;
接下来,我们为分析智代规划两个连续的初始化环路。
for(uint i = 0; i < caAgents.Size(); i++) { index++; if(!caAgents[i].Init(0, index, OpenCL, window, iWindowKey, units_count, iHeads, stack_size, action_space, optimization, iBatch)) return false; }
for(uint i = 0; i < caTrAgents.Size(); i++) { index++; if(!caTrAgents[i].Init(0, index, OpenCL, units_count, iWindowKey, window, iHeads, stack_size, action_space, optimization, iBatch)) return false; }
然后我们加上风险控制智代。其输入由描述当前账户状态的向量表示,且在初始化参数中明确指定。
index++; if(!cRiskAgent.Init(0, index, OpenCL, account_descr, iWindowKey, 1, iHeads, stack_size, action_space, optimization, iBatch)) return false;
此外,我们需要一个对象来级联所有内部智代的结果。这个合并输出将作为管控智代的输入,而功能则是我们继承自父类。
index++; if(!cConcatenatedAgents.Init(0, index, OpenCL, caAgents.Size()*caAgents[0].Neurons() + caTrAgents.Size()*caTrAgents[0].Neurons() + cRiskAgent.Neurons(), optimization, iBatch)) return false;
值得强调的是,账户状态信息是从一条辅助数据流获得的,由专用数据缓冲区表示。然而,为了正确运行初始化风险控制智代,需要一个包含这些输入数据的神经层对象。因此,我们创建一个内部对象,将第二条数据流中的信息传输到那里。
index++; if(!cAccount.Init(0, index, OpenCL, account_descr, optimization, iBatch)) return false; //--- return true; }
所有必要操作完成后,方法返回逻辑成功标志,并终止执行。
接下来我们将在 feedForward 方法内构造前馈算法。在这种情况下,我们是与两条输入数据流共事。主流提供描述所分析环境状态的张量,而次流则以账户状态向量的形式传递模型运行的财务结果。
bool CNeuronFinConManager::feedForward(CNeuronBaseOCL *NeuronOCL, CBufferFloat *SecondInput) { if(cAccount.getOutput() != SecondInput) { if(!cAccount.SetOutput(SecondInput, true)) return false; }
在方法内部,我们首先执行一个简短的预处理步骤,在此期间,次级输入数据对象(账户状态)的结果缓冲指针被相应数据流的缓冲区替换。我们还将主流输入数据的张量转置。
if(!cTransposeState.FeedForward(NeuronOCL)) return false;
这些准备步骤完成后,我们将所得数据传递至分析智代进行分析、并生成提案。
//--- Agents for(uint i = 0; i < caAgents.Size(); i++) if(!caAgents[i].FeedForward(NeuronOCL)) return false; for(uint i = 0; i < caTrAgents.Size(); i++) if(!caTrAgents[i].FeedForward(cTransposeState.AsObject())) return false; if(!cRiskAgent.FeedForward(cAccount.AsObject())) return false;
然后,智代的输出被级联到一个对象中。
//--- Concatenate if(!Concat(caAgents[0].getOutput(), caAgents[1].getOutput(), caAgents[2].getOutput(), cRiskAgent.getOutput(), cConcatenatedAgents.getPrevOutput(), Neurons(), Neurons(), Neurons(), Neurons(), 1) || !Concat(caTrAgents[0].getOutput(), caTrAgents[1].getOutput(), caTrAgents[2].getOutput(), cConcatenatedAgents.getPrevOutput(), cConcatenatedAgents.getOutput(), Neurons(), Neurons(), Neurons(), 4 * Neurons(), 1)) return false;
级联的结果随后传递给管控,由其负责基于所有智代的提案制定最终交易决策。
//--- Manager return CNeuronFinConAgent::feedForward(cConcatenatedAgents.AsObject()); }
逻辑结果返回至调用程序。
我们对构造管控方法所用算法的讨论至此结束。反向传播方法留待独立研究。该类及其所有方法的完整实现,可在随附的素材中找到。
模型架构
关于可训练模型的架构有几句话要说。在准备本文时,仅训练了一个模型,即交易决策智代。这不应与 FinCon 框架本身的智代混淆。
训练模型的架构相较之前关于 FinAgent 方法的研究成果几乎未有改变。仅更换了一个神经层,启用了 FinCon 框架中实现的方式整合。
//--- layer 2 if(!(descr = new CLayerDescription())) return false; descr.type = defNeuronFinConManager; //--- Windows { int temp[] = {BarDescr, 24, AccountDescr, 2 * NActions}; //Window, Stack Size, Account description, N Actions if(ArrayCopy(descr.windows, temp) < int(temp.Size())) return false; } descr.count = HistoryBars; descr.window_out = 32; descr.step = 4; // Heads descr.batch = 1e4; descr.activation = None; descr.optimization = ADAM; if(!actor.Add(descr)) { delete descr; return false; }
完整的模型架构代码包含在附件之中。它还包含用于训练和测试的程序。由于这些脚本是从早期工作中转移而来,未作修改,我们于此不作详细分析。
测试
最后两篇文章专门讨论了 FinCon 框架,其中我们深入探讨了其核心原则。我们按框架方法的解释实现了 MQL5 版本,现在是时候评估这些实现在真实历史数据上的有效性。
应当注意的是,此处展示的实现与原始版本有显著差异,而这肯定会影响结果。因此,我们仅能谈论所实现方式效率的评估,而非重现原始结果。
至于模型训练,我们用到 EURUSD 的 2024 年 H1 数据。分析指标的参数保持不变,专注于评估算法性能。
训练数据集由多个随机初始化参数模型的多次运行形成。此外,我们还纳入了利用 Real-ORL 方法从现有市场信号数据中推导出的成功运行。这丰富了数据集中积极的样本,并扩大了可能的市场场景覆盖范围。
在训练期间,我们采用了一个算法,为智代生成“近乎完美”的目标动作。如此无需持续更新数据集即可实现模型训练。不过,我们建议定期更新数据,通过扩大状态空间覆盖面,进一步提升学习成果。
最终测试基于 2025 年 1 月的可用数据进行,其它参数保持不变。结果如下所示。结果呈现如下。

测试结果对模型的有效性进行了混合评估。测试期间,该模型在 47 笔交易操作中实现了盈利,但其中只有 42% 的交易成功。甚至,大部分余额增长来自单笔盈利交易,而余下时间的余额曲线保持在狭窄区间。这表明模型还需进一步优化。
结束语
本文探讨了 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/16937
注意: MetaQuotes Ltd.将保留所有关于这些材料的权利。全部或部分复制或者转载这些材料将被禁止。
本文由网站的一位用户撰写,反映了他们的个人观点。MetaQuotes Ltd 不对所提供信息的准确性负责,也不对因使用所述解决方案、策略或建议而产生的任何后果负责。
交易中的神经网络:针对加密货币市场的记忆扩充上下文感知学习(MacroHFT)
交易中的神经网络:配备概念强化的多智代系统(FinCon)
交易中的神经网络:针对加密货币市场的记忆扩充上下文感知学习(终篇)