交易中的神经网络:具有层化记忆的智代
概述
日益增长的金融数据要求交易者不仅要快速处理,还要深度分析,以便准确及时地制定决策。然而,人类记忆力、注意力、以及处理大量信息的能力有限,可能导致关键事件被遗漏、或得出错误结论。这就需要能够整合异构数据的自主交易智代 — 快速、且高精度。其中一个解决方案出现在论文《FinMem:具有层化记忆和特征设计的性能强化 LLM 交易智代》之中。
所提议 FinMem 框架是一个创新的大语言模型(LLM)智代,引入了独特的多级记忆系统。该方式能够高效处理不同类型和时态含义的数据。FinMem 记忆模块分为工作记忆,设计用于短期数据处理;和分层的长期记忆,其中信息根据相关性和重要性进行分类。举例,每日新闻和短期市场波动只分析表层,而具有长期影响的报告和研究则存储在更深层的记忆。这种结构允许智代为信息排定优先级,专注在最相关的数据。
FinMem 中的剖析模块允许智代适配专业背景和市场条件。考虑到个人偏好和用户的风险备案,智代量身定制其策略,从而最大化效能。决策模块把当前市场数据,与存储的记忆整合,生成合理的策略。这样就可参考短期趋势、和长期形态两者。这种认知启发式设计令 FinMem 能够记住、并利用关键市场事件,从而提升决策的准确性和适应性。
来自原始研究中的多次实验结果表明,FinMem 在效率上优于其它自主交易模型。即便训练仅依据有限数据,智代在信息处理和投资决策方面均展现了杰出绩效。得益于其独特的认知负载监管能力,FinMem 能够处理大量事件,而不牺牲分析品质。例如,它能够并发分析数十个独立的市场信号,按重要性将它们结构化,并在时间制约下制定依据充分的决策。
FinMem 的另一个显耀优势是其依据实时新数据的学习和适应能力。这令智代不仅能管理当前任务,还能持续优调交易策略,从而应对不断变化的市场条件。这种认知灵活性与技术成熟度的结合,令 FinMem 成为自主交易领域的一大进步。FinMem 代表了一种将认知原理,与先进技术相结合的前沿解决方案,可在复杂且动态的金融市场中取得成功绩效。
FinMem 架构
FinMem 框架由三个主要模块组成:
- 剖析
- 记忆
- 决策制定
该剖析模块令 FinMem 能够开发一个动态的智代特征,设计用于高效地驾驭复杂的金融市场动态。FinMem 的动态特征包括两个关键成分:一个是基本的专业知识库,类似于交易专家,以及一个配备三种不同风险倾向的智代。
第一个成分内含两种信息类别:一个是 FinMem 即将交易的股票,其相关公司所涉的主要交易板块,及其涵盖整个训练区间的历史财务绩效的简要概览。在交易新公司股票之前,FinMem 会访问服务器端数据库,并更新这些行业和历史财务数据。这种专业知识配置将记忆范围缩窄到与特定交易任务相关的事件。
FinMem 设计的第二个成分包括三种不同的风险偏好备案:
- 风险索求,
- 风险规避,
- 自适应风险性格。
在风险索求模式,FinMem 采取激进、高回报的策略,而在风险规避模式下,则转向保守、低风险方式。FinMem 的独特之处在于能够回应当前市场条件,在这些风险之间动态切换。具体而言,当短期累计回报跌破零时,它会调整风险偏好。这种灵活的设计起到了保障作用,疏解了动荡市场中的长期回撤。
在初始训练阶段,FinMem 会根据所选的风险偏好进行配置,每个都伴以 LLM 提示形式的详细文本指导。这些指南判定 FinMem 如何处理收入的消息,并根据所赋予的风险备案定义其后续动作。系统在其待办事项列表中维护所有风险备案、及其详解的目录,允许按需在这些备案间切换,轻松适配不同股票。
FinMem 剖析模块内的动态特征配置既提供主观见解,也提供专业知识,以及灵活的风险行为选择。它提供了本质上下文,可过滤和提取与交易相关的信息、并记忆相关事件,从而强化推断的精确度、以及对市场条件变化的适应性。
FinMem 记忆模块模拟交易者的认知系统,高效处理层次化金融信息,并优先处理关键消息,得以实现高品质投资决策。它能够动态调整记忆能力,令智代能在覆盖更长时间段内处理更广泛的事件。FinMem 中的记忆模块包含工作记忆和长期记忆,两者都具备层化处理能力,并通过特定的投资查询激活。
工作记忆对应于人类认知功能,负责临时存储和心理活动。该框架的作者将这一概念融入了 FinMem 记忆设计,创建了一个中央工作空间,以便制定明智决策。不同于人类工作记忆能容纳约 7 ± 2 个事件,FinMem 的工作记忆可基于具体需求进行扩展。FinMem 的工作记忆设计用来将金融数据转化为交易动作,执行三个关键操作:汇总、观察、和反思。
FinMem 利用外部市场数据,推导出关键投资洞察和情绪,为特定股票量身订制交易查询。该系统将原产文本压缩成紧凑、且富含信息量的段落,提升了 FinMem 的处理效率。它提取并汇总了投资决策制定所需的相关数据和情绪。然后,FinMem 将这些输出导入长期记忆中的相应层,根据信息的时态敏感度选择。
在启动相同查询时,FinMem 会执行一个观察操作,以便收集市场事实。在 FinMem 训练和测试之间,可获得的信息有所不同。训练期间,它可访问指定区间内的综合股价数据。当收到的交易查询指定了股票代码和日期,FinMem 会专注每日调整后的收盘价差异,将次日价格与当天进行比较。这些价格差异会被当作市场基准。价格下降是“卖出”的信号,上涨或无变化表示“买入”。
测试期间,FinMem 失去了对未来价格数据的访问。取而代之,它更专注于分析历史价格走势,并评估所分析区间的累计回报。该阶段的特征是缺乏预测性市场数据,此为 FinMem 在股票价格趋势与多元化金融信息来源,如新闻、报告、和指标之间建立逻辑连结能力的关键考验。这对于评估 FinMem 自主分析和解读历史数据,演进交易策略的能力至关重要。
有两种类型的响应:立即和延伸。当收到针对特定股票代码的每日交易查询时,立即响应。运用 大语言模型 和预定义的提示词,智代结合了市场指标和,及来自每个长期记忆层排名前 K 位的记忆事件。市场指标衍生自观察操作结果,且在训练和测试阶段有所不同。测试期间,这会产生三个输出:交易方向(“买入”、“卖出”、或“持有”)、决策理由、以及最具影响力的记忆事件与其标识符。在训练阶段,无需指示交易方向,因为 FinMem 已经知道股票走势的未来方向。排名前 K 位的记忆事件封装了关键投资相关消息派生出的关键洞察和情绪,所有这些均由 FinMem 以先进能力汇总。
延伸响应重新评估覆盖所定义跟踪间隔间内智代的即刻结果。它包括股价趋势、交易绩效、以及基于若干个即刻反思的动作理由。而即刻响应支持直接交易和反馈记录,延伸响应则泛化市场趋势,并重新评估近期累计投资绩效。这些延伸响应最终被存储在深层长期记忆之中,强调了它们的关键重要性。
FinMem 的长期记忆会按层次组织分析性金融数据。FinMem 所用的层化结构,能考虑到不同金融数据类型固有的时间敏感性。该结构根据时效性和衰减率(遗忘速度)对汇总结果进行分类。输出是通过工作记忆泛化操作生成。趋向更深层的事件衰减率较慢 = 保留时间更长,而浅层数据衰减更快,且保留时间较短。每个记忆事件仅属于一层。
在收到投资查询后,FinMem 会从每层提取排名前 K 位的关键记忆事件,并将其导向工作记忆反射组件。事件基于三个量值排名:新颖性、相关性、和重要性。在聚集之前,分数超过 1.0 会被归一化至 [0,1] 范围。
对于投喂到技术层的交易请求,智代使用一个大语言模型查询来评估其新颖性,其与查询和事件时间戳之间的时差呈反比,反映出遗忘曲线。稳定性可在不同层部分控制衰减率:稳定性越高,代表记忆持续时间越长久。在交易环境中,公司年报被认为比每日财经新闻更为重要。因此,它们被赋予更高的稳定性数值,并存储在更深的处理层中,反映了它们对金融决策的广泛相关性和影响。
相关性的量化,则是计算从记忆事件上下文本推导出的嵌入矢量之间的余弦相似度。大语言模型查询协同原始交易请求数据,以及智代的特征配置。
FinMem 的决策模块有效整合了剖析和记忆模块的运作输出,支持有充分依据的投资决策。在每日交易决策中,FinMem 会针对给定股票选择三种可能动作之一:买入、卖出、或持有 — 经由文本验证。FinMem 决策模块所需的输入数据和输出,在训练和测试阶段之间存在差异。
在训练期间,FinMem 访问涵盖整个训练区间的多个来源的广泛数据。当它接收包含股票代码、日期、和交易特征描述的交易查询时,会同时在工作记忆中启动观察和汇总操作。FinMem 监控市场标签,包括每日调整的价格差值,其指示“买入”或“卖出”操作。利用这些价格变化信号,FinMem 识别并优先排名前 K 位记忆,排名是基于提取自每个长期记忆层的评分。这一过程令 FinMem 能够生成综合性分析,据其审辩并解读市场标签与所提取记忆之间的相关性。经由重复交易操作,有影响力的反应和记忆事件会迁移到更深层的记忆层加以保留,支持测试期间的未来投资决策。
在测试期间,当 FinMem 不再访问未来价格数据时,它依赖覆盖分析区间的累计回报来预测未来市场趋势。为了弥补预测数据的缺失,FinMem 使用派生自即刻反射得出的延申响应作为补充标签。当面对特定交易查询时,FinMem 整合来自多源的信息,包括历史累计回报、延申反思、及提取的前 K 位记忆。这种综合性方式令 FinMem 能够制定依据充分的交易决策。
应当注意的是,FinMem 仅在测试的即刻反应阶段生成可执行动作。由于交易方向基于实际价格趋势,训练期间没有投资动作。取而代之,该阶段专注于比较市场动态与来自多源的金融信息,以此积累交易经验。在该过程期间,FinMem 依据一个庞大的知识库来丰富其记忆模块,因此强化其在未来交易场景下的自主决策制定能力。
下面提供了 FinMem 框架的原始可视化。

实现 MQL5 版本
在论证了 FinMem 框架的理论层面之后,我们现在转到实现所提议方式的 MQL5 版本。应当立即注意的是,与之前所有工作相比,我们的实现与作者的原始方案很可能有显著差异。这主要是因为原始框架依赖预训练的大语言模型作为其核心。在我们情况中,我们的实现将基于作者提出的信息处理方式,但以不同的视角加以利用。
记忆模块
我们从构建记忆模块开始。在原版 FinMem 框架中,得益于大语言模型的运用,智代的记忆中充满了自不同来源的事件汇总,及其嵌入文本描述。然而在我们的实现中,我们不会使用大语言模型。相应地,我们仅会依赖直接从交易终端获得的数值信息。
接下来,我们需要研究构建多层记忆,每层衰减率都不同。这立即引发了一个问题:如何优先处理所分析事件。仅分析当前环境状态,由价格走势数据和各种技术指标的表述,难以判定两个后续状态的优先级。
在评估了各种选项之后,我们决定使用重复模块来规划记忆层。为了模拟不同的遗忘率,我们为不同的记忆层采用了区别化重复模块架构,因其架构设计,每层处理不同的衰减特性。我们选择不去人为设定优先环境状态。取而代之,所有记忆层均等处理原产数据,且我们提议允许模型学习优先级。
我们通过交叉注意力模块实现了跨记忆层的数据匹配。
上述算法封装在 CNeuronMemory 对象之中,其结构如下所述。
class CNeuronMemory : public CNeuronRelativeCrossAttention { protected: CNeuronLSTMOCL cLSTM; CNeuronMambaOCL cMamba; //--- 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: CNeuronMemory(void){}; ~CNeuronMemory(void){}; //--- virtual bool Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl, uint window, uint window_key, uint units_count, uint heads, ENUM_OPTIMIZATION optimization_type, uint batch) override; //--- virtual int Type(void) override const { return defNeuronMemory; } //--- 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; };
在我们的函数库中,我们已实现了两个重复模块:LSTM 和 Mamba,我们用其规划记忆层。为了调和这些模块的输出,我们将用到一个相对交叉注意力模块。为了降低我们的注意力模块内部对象数量,我们将用交叉注意力对象作为父类。
内部记忆层对象声明为静态,允许我们保持类构造和析构函数为空。所有声明和继承的对象初始化,如常在 Init 方法中执行。
bool CNeuronMemory::Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl, uint window, uint window_key, uint units_count, uint heads, ENUM_OPTIMIZATION optimization_type, uint batch) { if(!CNeuronRelativeCrossAttention::Init(numOutputs, myIndex, open_cl, window, window_key, units_count, heads, window, units_count, optimization_type, batch)) return false;
该方法的参数包含父类方法中熟悉的常量。然而,在这种情况下,我们排除了第二个数据源参数,在于我们的新对象仅据单一数据流上操作。在调用父类方法时,我们复制主数据流数值当作第二个源参数。
父类方法操作成功执行之后,我们按相应数据源参数初始化记忆层的重复对象。
if(!cLSTM.Init(0, 0, OpenCL, iWindow, iUnits, optimization, iBatch)) return false; if(!cMamba.Init(0, 1, OpenCL, iWindow, 2 * iWindow, iUnits, optimization, iBatch)) return false; //--- return true; }
最后,方法返回一个表示操作成功的布尔结果至调用程序。
下一步是构建 feedForward 算法。此处的一切都十分简单。该方法接收一个指向源数据对象的指针,然后传递给内部记忆层对应的方法。
bool CNeuronMemory::feedForward(CNeuronBaseOCL *NeuronOCL) { if(!cLSTM.FeedForward(NeuronOCL)) return false; if(!cMamba.FeedForward(NeuronOCL)) return false;
然后我们用父类交叉注意力比较这些重复对象的结果,并返回一个布尔结果至调用程序。
return CNeuronRelativeCrossAttention::feedForward(cMamba.AsObject(), cLSTM.getOutput());
}
传播误差梯度的 calcInputGradients 算法看起来稍微复杂一些。于此,我们需要将误差梯度从两个信息流传播到源数据对象,其指针已作为方法参数提供。
bool CNeuronMemory::calcInputGradients(CNeuronBaseOCL *NeuronOCL) { if(!NeuronOCL) return false;
在该方法内,我们首先检查源数据对象指针的有效性,否则梯度传播是不可能的。
验证成功后,我们利用父对象将误差梯度分派到内部记忆层。
if(!CNeuronRelativeCrossAttention::calcInputGradients(cMamba.AsObject(), cLSTM.getOutput(), cLSTM.getGradient(), (ENUM_ACTIVATION)cLSTM.Activation())) return false;
接下来,我们将梯度从一个记忆层传播到源数据层。
if(!NeuronOCL.calcHiddenGradients(cMamba.AsObject())) return false;
然后,我们将指向源数据梯度缓冲区的指针替换到一个自由缓冲区,并传播第二个信息流。
CBufferFloat *temp = NeuronOCL.getGradient(); if(!NeuronOCL.SetGradient(cMamba.getPrevOutput(), false)) return false; if(!NeuronOCL.calcHiddenGradients(cLSTM.AsObject())) return false; if(!NeuronOCL.SetGradient(temp, false) || !SumAndNormilize(temp, cMamba.getPrevOutput(), temp, iWindow, false, 0, 0, 0, 1)) return false; //--- return true; }
最后,我们合计两条流的梯度,并将缓冲区指针恢复到原始状态。所有操作完成后,方法会把执行状态通知调用程序,并终止。
更新模型参数的 updateInputWeights 方法算法不包含任何复杂元素。我鼓励您独立审阅它们。记忆模块及其所有方法的完整代码均包含在附加文件之中。我们现在进入下一阶段。
构建 FinMem 框架
我们工作的下一阶段涉及实现综合性的 FinMem 框架算法,我们将在 CNeuronFinMem 对象构建它。新类结构如下所示。
class CNeuronFinMem : public CNeuronRelativeCrossAttention { protected: CNeuronTransposeOCL cTransposeState; CNeuronMemory cMemory[2]; CNeuronRelativeCrossAttention cCrossMemory; CNeuronRelativeCrossAttention cMemoryToAccount; CNeuronRelativeCrossAttention cActionToAccount; //--- 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: CNeuronFinMem(void) {}; ~CNeuronFinMem(void) {}; //--- virtual bool Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl, uint window, uint window_key, uint units_count, uint heads, uint accoiunt_descr, uint nactions, ENUM_OPTIMIZATION optimization_type, uint batch); //--- virtual int Type(void) override const { return defNeuronFinMem; } //--- 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 方法中处理。
重点要注意,在这种情况下,我们正在创建一个智代对象。它分析输入数据,并返回一个特定的动作向量,其反映在对象的初始化参数之中。因此,除了描述环境状态张量的标准常量外,初始化方法还包括账户状态描述符(account_descr),和动作空间(nactions)的参数。
进而,为了模拟 FinMem 框架作者提议的延申反应模块的行为,我们计划反复重使用智代在向新环境状态转变之前所用的动作信息。出于此原因,交叉注意力模块被选作父类。
bool CNeuronFinMem::Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl, uint window, uint window_key, uint units_count, uint heads, uint account_descr, uint nactions, ENUM_OPTIMIZATION optimization_type, uint batch) { if(!CNeuronRelativeCrossAttention::Init(numOutputs, myIndex, open_cl, nactions / 2, window_key, 2, heads, window, units_count, optimization_type, batch)) return false;
在对象初始化方法的主体内,我们遵循既定的惯例:首先,调用父类方法。如早前所述,它是交叉注意力对象。主要信息流接收智代之前动作的向量,我们将其切分为两等份(大概代表买入和卖出操作)。次级信息流接收描述环境当前状态的经处理数据。
父类操作执行成功后,我们继续初始化新声明的对象。第一个是环境状态描述符的数据置换对象。
index++; if(!cMemory[0].Init(0, index, OpenCL, window, window_key, units_count, heads, optimization, iBatch)) return false;
回忆模型输入由环境状态描述组成,以单根柱线向量表示。转置该张量就能跨独立单变量序列进行分析。
基于这一特性,我们用两个记忆模块,从不同角度分析输入数据。
index++; if(!cMemory[0].Init(0, index, OpenCL, window, window_key, units_count, heads, optimization, iBatch)) return false; index++; if(!cMemory[1].Init(0, index, OpenCL, units_count, window_key, window, heads, optimization, iBatch)) return false;
这些记忆模块产生的结果随后在交叉注意力模块中聚合。
index++; if(!cCrossMemory.Init(0, index, OpenCL, window, window_key, units_count, heads, units_count, window, optimization, iBatch)) return false;
下一个交叉注意力模块据提取自账户状态向量的累计盈亏信息来丰富环境状态描述,其还包含所分析状态的时间戳。
index++; if(!cMemoryToAccount.Init(0, index, OpenCL, window, window_key, units_count, heads, account_descr, 1, optimization, iBatch)) return false;
最后,我们初始化一个交叉注意力模块,智代最近的动作与当前账户状态中反映的相应成果一致。
index++; if(!cActionToAccount.Init(0, index, OpenCL, nactions / 2, window_key, 2, heads, account_descr, 1, optimization, iBatch)) return false; //--- if(!Clear()) return false; //--- return true; }
这些步骤完成后,我们清除所有重复对象的内部状态,并返回一个表示操作成功的布尔结果至调用程序。
不知不觉中,我们已经到达了本文末尾,但我们的工作尚未完成。我们稍作休息。在下一篇文章中,我们将引领我们的实现至其逻辑完结,并用真实历史数据来评估已开发解决方案的有效性。
结束语
本文探讨了 FinMem 框架,它代表了自主交易系统演进的新阶段。它结合了认知原理,和基于大语言模型的先进算法。其多层记忆和实时适应性,令智代即使在波动的市场条件下也能做出精准、且依据充分的投资决策。
在实践章节,我们开始按自己对拟议方式的解读,开发 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/16804
注意: MetaQuotes Ltd.将保留所有关于这些材料的权利。全部或部分复制或者转载这些材料将被禁止。
本文由网站的一位用户撰写,反映了他们的个人观点。MetaQuotes Ltd 不对所提供信息的准确性负责,也不对因使用所述解决方案、策略或建议而产生的任何后果负责。
交易中的神经网络:具有层化记忆的智代(终篇)
解密开盘区间突破(ORB)日内交易策略
风险管理(第二部分):在图形界面中实现手数计算
创建动态多货币对EA(第二部分):投资组合多元化与优化
你好,这篇文章很有意思。不幸的是,我无法编译 Research.mq5 文件--其中 if((!CreateDescriptions(actor, critic, critic))) 一行的参数数量不正确。- 参数数量不正确。我无法继续(
下午好,请问 Research 文件是从哪个目录中加载的?参数确实很多。这项工作中只使用了一个模型。
下午好,请问研究文件是从哪个目录下载的?这里确实有很多参数。本文只使用了一个模型。
我已经翻阅了目录,但我已经搞不清楚是从哪里下载的了。((
您能告诉我这篇论文应该使用哪个目录吗?
在目录上偷懒,已经搞不清楚我在哪里拍的((
请指导我这篇文章该用什么目录?
与本文相关的所有文件都位于 FinMem 文件夹中。
我尝试了各种方法,但都没有得到您的结果。
很抱歉,您能否给出正确的说明,告诉我们该运行什么程序,按什么顺序运行什么文件。
谢谢。