- 设计各种类型的 MQL 程序
- 线程
- 事件处理函数概述
- 各类启动和停止程序的特征
- 指标和 EA 交易的参考事件:OnInit 和 OnDeinit
- 脚本和服务的主要功能:OnStart
- 以编程方式移除 EA 交易和脚本:ExpertRemove
指标和 EA 交易的参考事件:OnInit 和 OnDeinit
在交互式 MQL 程序(指标和 EA 交易)中,环境会生成两个事件,用于准备启动 (OnInit) 和停止 (OnDeinit)。脚本和服务中不存在这些事件,因为它们不接受异步事件:当控制权交给其唯一的事件处理程序 OnStart 后,直到工作结束前,脚本/服务线程的执行上下文将始终处于该 MQL 程序代码中。相比之下,对于指标和 EA 交易,正常工作流程假定,环境会反复调用其特定的事件处理函数(我们将在指标和 EA 交易相关章节中讨论这些函数),并且每次完成必要操作后,程序会将控制权返回给终端,进入空闲状态等待新事件。
int OnInit()
OnInit函数是同名事件的处理程序,该事件在加载 EA 交易或指标后生成。该函数仅在需要时定义。
该函数必须返回 ENUM_INIT_RETCODE 枚举值之一。
标识符 |
说明 |
---|---|
INIT_SUCCEEDED |
初始化成功,可继续执行程序;对应值 0 |
INIT_FAILED |
初始化失败,由于致命错误(如无法创建文件或辅助指标)无法继续执行;值为 1 |
INIT_PARAMETERS_INCORRECT |
输入参数组错误,无法执行程序 |
INIT_AGENT_NOT_SUITABLE |
在 测试程序中工作的特定代码:由于某些原因,当前代理不适合测试(例如 RAM 不足、不支持 OpenCL 等) |
如果 OnInit返回任何非零返回码,则表示初始化失败,随后会生成 Deinit 事件,其反初始化原因代码为 REASON_INITFAILED(见下文)。
OnInit函数可以声明为返回类型 void:在这种情况下,初始化始终被视为成功。
在OnInit处理程序中,重要的是确保所有必要的环境信息已就绪,如果不可用,则将延迟下一个分时报价或计时器到达事件的准备操作。关键在于,当终端启动时,OnInit事件通常在与服务器建立连接之前触发,因此许多金融工具和交易账户的特性仍然未知。特别是,特定交易品种的点值可能返回为零。
void OnDeinit(const int reason)
当 EA 交易或指标被反初始化时,将调用OnDeinit函数(如果已定义)。该函数为可选函数。
reason参数包含反初始化原因代码。可能的值如下表所示。
常量 |
值 |
说明 |
---|---|---|
REASON_PROGRAM |
0 |
EA 交易通过调用 ExpertRemove 函数停止运行 |
REASON_REMOVE |
1 |
程序从图表中移除 |
REASON_RECOMPILE |
2 |
程序被重新编译 |
REASON_CHARTCHANGE |
3 |
图表交易品种或周期发生变更 |
REASON_CHARTCLOSE |
4 |
图表关闭 |
REASON_PARAMETERS |
5 |
输入参数发生变更 |
REASON_ACCOUNT |
6 |
激活了另一个账户,或由于账户设置变更导致重新连接到交易服务器 |
REASON_TEMPLATE |
7 |
应用了不同的图表模板 |
REASON_INITFAILED |
8 |
OnInit 处理程序返回非零值 |
REASON_CLOSE |
9 |
终端关闭 |
在 MQL 程序中,如果设置了停止标志 _StopFlag,可以在程序的任何位置使用 UninitializeReason 函数获取相同的代码。
AllInOne.mqh文件有 Finalizer 类,允许通过UninitializeReason 调用在析构函数中“挂钩”反初始化代码。我们必须在 OnDeinit处理程序中获取相同的值。
class Finalizer
|
为了便于使用 EnumToString将代码转换为字符串表示形式(原因名称),Uninit.mqh 文件中定义了包含上述表格常量的 ENUM_DEINIT_REASON 枚举。日志将显示类似以下的条目:
OnDeinit DEINIT_REASON_REMOVE
|
当更改指标所在图表的交易品种或时间范围时,指标会被卸载并重新加载。在这种情况下,旧副本中触发 OnDeinit事件顺序与新副本中触发OnInit 事件的顺序没有明确定义。这是由于终端处理异步事件的特性所致。换言之,新副本可能会在旧副本完全卸载之前就被加载并初始化,这可能不太符合逻辑。如果指标在 OnInit中执行了某些图表调整操作(例如创建 图形对象),而没有采取特殊措施,则被卸载的副本可能会立即“清理”图表(删除该对象,误认为是自己创建的)。对于图形对象这一特定情况,有一个特殊的解决方案:可以为对象命名时包含交易品种和时间范围前缀(以及输入变量值的校验和),但该方案不适用于一般情况。要实现这一问题的通用解决方案,应实现某种同步机制,例如基于 全局变量 或 资源。
在测试程序中测试指标时,MetaTrader 5 开发者决定不生成OnDeinit事件。他们的初衷是,指标会创建一些图形对象,这些对象通常会OnDeinit处理程序中被移除,但用户可能希望在测试结束后仍能查看这些对象。实际上,如果有需要,MQL 程序开发者可通过主动检查MQLInfoInteger(MQL_TESTER)模式来实现类似行为和保留对象。这一设计存在矛盾之处,因为在 EA 交易测试后,会调用 OnDeinit处理程序,而 EA 交易同样可以在OnDeinit 中删除对象。目前,仅针对指标,测试程序中无法保证OnDeinit处理程序的正常执行。此外,其他终止操作同样不会执行,例如不会调用全局对象的析构函数。
因此,如需在测试运行结束后执行统计计算、文件保存或其他原本计划在指标的 OnDeinit中完成的操作,则必须将指标算法迁移至 EA 交易。