权限

出于安全原因,MetaTrader 5 提供了用于限制 MQL 程序执行某些操作的功能。某些限制是两个层级的,即为别针对整个终端以及为特定程序设置。终端设置优先,或者作为任何 MQL 程序设置的默认值。例如,交易员可以通过选中 MetaTrader 5 设置对话框中的对应选框来禁用所有自动交易。在此情况下,早前在相关对话框中为特定机器人设置的私有交易权限变为无效。

在 MQL5 API 中,这种限制(或者反面,权限)适用于通过 TerminalInfoIntegerMQLInfoInteger 函数进行的读取。由于它们对 MQL 程序的效果相同,因此程序对于总体和特定禁止项均需仔细检查(以避免尝试执行非法操作时出错)。因此,本节提供了不同层级所有选项的列表。

所有权限均为布尔标志,即它们存储 truefalse 值。

标识符

说明

TERMINAL_DLLS_ALLOWED

使用 DLL 的权限

TERMINAL_TRADE_ALLOWED

在线自动交易的权限

TERMINAL_EMAIL_ENABLED

发送电子邮件的权限(必须在终端设置中指定 SMTP 服务器和登录信息)

TERMINAL_FTP_ENABLED

通过 FTP 向指定服务器发送文件的权限(包括为在终端设置中指定的交易账户提供的报告)

TERMINAL_NOTIFICATIONS_ENABLED

向智能手机发送推送通知的权限

MQL_DLLS_ALLOWED

将 DLL 用于该程序的权限

MQL_TRADE_ALLOWED

自动交易程序的权限

MQL_SIGNALS_ALLOWED

信号处理程序的权限

在终端层级使用 DLL 的权限表示当运行一个包含指向某些动态库的链接的 MQL 程序时,“依赖项”选项卡上的“启用 DLL 导入”标志将在其属性对话框中默认启用。如果该标志在终端设置中被清除,则在 MQL 程序的属性中的选项将默认禁用。在任何情况下,用户必须允许单个程序的导入(对于脚本有一个例外,将在下文讨论)。否则,程序将不会运行。

换言之,TERMINAL_DLLS_ALLOWED 和 MQL_DLLS_ALLOWED 标志既可由绑定到 DLL 的程序检查,也可以由绑定到 DLL 的程序检查,但对于后者,MQL_DLLS_ALLOWED 必须明确设置为 true(因为已经启动)。因此,作为需要 DLL 的软件系统的一部分,可能需要提供一个独立实用工具,用于监测标志状态并在标志突然被关闭时向用户显示诊断信息。例如,一个 EA 交易可能需要一个使用 DLL 的指标。然后,在尝试加载指标并获得其句柄之前,EA 可能检查 TERMINAL_DLLS_ALLOWED 标志并生成一个警告(如果标志被重置)。

对于脚本,该行为可能稍有不同,因为仅当源代码中存在 #property script_show_inputs 指令时,脚本设置对话框才会打开。如果不存在,则当 TERMINAL_DLLS_ALLOWED 标志在终端设置中被重置时(并且用户必须启用该标志以让脚本运行),该对话框才会出现。当普通标志 TERMINAL_DLLS_ALLOWED 被启用后,该脚本无需用户确认即运行,即假定 MQL_DLLS_ALLOWED 值为 true(根据 TERMINAL_DLLS_ALLOWED)。

在测试程序中运行时,TERMINAL_TRADE_ALLOWED 和 MQL_TRADE_ALLOWED 标志始终等于 true。然而,在 指标中,无论这些标志如何设置,均禁止对所有交易函数的访问。测试程序不允许测试具有 DLL 依赖项的 MQL 程序。

TERMINAL_EMAIL_ENABLED、TERMINAL_FTP_ENABLED 以及 TERMINAL_NOTIFICATIONS_ENABLED 标志对于 send mailSendFTPsend notification 函数很关键,这些函数在 网络函数 一节中介绍。MQL_SIGNALS_ALLOWED 标志会影响一组管理 mql5.com 交易信号订阅(不在本书讨论范围内)的函数的可用性。其状态对应于 MQL 程序特性的 Common 选项卡中的 Allow changing signal settings 选项。

由于检查某些特性需要额外工作,因此最好将标志封装在一个类中,该类通过方法隐藏对各种系统函数的多次调用。这是十分必要的,因为某些权限不仅限于上述选项。例如,交易权限不仅可以在终端或 MQL 程序层级设置(或移除),而且可以为单个金融工具设置,比如根据你的经纪人和交易所时段为其指定的规范来设置。因此,在这一步,我们将提供“权限”类的草案,其中仅包含我们熟知的元素,今后我们将针对特定应用程序 API 进行改善。

有了作为程序层的类,编程人员无需记住哪些权限是为 TerminalInfo 函数定义的,哪些是为 MqlInfo 函数定义。

源代码在 EnvPermissions.mq5 文件中。

class Permissions
{
public:
   static bool isTradeEnabled(const string symbol = NULLconst datetime session = 0)
   {
      // TODO: will be supplemented by applied checks of the symbol and sessions
      return PRTF(TerminalInfoInteger(TERMINAL_TRADE_ALLOWED))
          && PRTF(MQLInfoInteger(MQL_TRADE_ALLOWED));
   }
   static bool isDllsEnabledByDefault()
   {
      return (bool)PRTF(TerminalInfoInteger(TERMINAL_DLLS_ALLOWED));
   }
   static bool isDllsEnabled()
   {
      return (bool)PRTF(MQLInfoInteger(MQL_DLLS_ALLOWED));
   }
   
   static bool isEmailEnabled()
   {
      return (bool)PRTF(TerminalInfoInteger(TERMINAL_EMAIL_ENABLED));
   }
   
   static bool isFtpEnabled()
   {
      return (bool)PRTF(TerminalInfoInteger(TERMINAL_FTP_ENABLED));
   }
   
   static bool isPushEnabled()
   {
      return (bool)PRTF(TerminalInfoInteger(TERMINAL_NOTIFICATIONS_ENABLED));
   }
   
   static bool isSignalsEnabled()
   {
      return (bool)PRTF(MQLInfoInteger(MQL_SIGNALS_ALLOWED));
   }
};

所有类方法均为静态的,在 OnStart 中调用。

void OnStart()
{
   Permissions::isTradeEnabled();
   Permissions::isDllsEnabledByDefault();
   Permissions::isDllsEnabled();
   Permissions::isEmailEnabled();
   Permissions::isPushEnabled();
   Permissions::isSignalsEnabled();
}

生成的日志示例如下所示。

TerminalInfoInteger(TERMINAL_TRADE_ALLOWED)=1 / ok
MQLInfoInteger(MQL_TRADE_ALLOWED)=1 / ok
TerminalInfoInteger(TERMINAL_DLLS_ALLOWED)=0 / ok
MQLInfoInteger(MQL_DLLS_ALLOWED)=0 / ok
TerminalInfoInteger(TERMINAL_EMAIL_ENABLED)=0 / ok
TerminalInfoInteger(TERMINAL_NOTIFICATIONS_ENABLED)=0 / ok
MQLInfoInteger(MQL_SIGNALS_ALLOWED)=0 / ok

为方便自学,该脚本内置(但注释掉)了以下功能:连接系统 DLL 以读取 Windows 剪贴板内容。我们将在本书第七章探讨库的创建和使用,尤其是 #import 指令,具体在 章节中。

我们假定全局 DLL 导入选项在终端中被禁用(出于安全考虑,这是建议设置)。然后,如果 DLL 连接到脚本,则可以仅通过在其单个设置对话框中允许导入来运行脚本,此时 MQLInfoInteger(MQL_DLLS_ALLOWED) 将返回 1 (true)。如果给定了 DLL 的全局权限,则我们得到 TerminalInfoInteger(TERMINAL_DLLS_ALLOWED)=1,并且 MQL_DLLS_ALLOWED 继承此值。