Разрешения

MetaTrader 5 позволяет ограничить выполнение некоторых действий MQL-программами, из соображений безопасности. Некоторые из этих ограничений являются двухуровневыми, то есть устанавливаются раздельно для терминала в целом, и для конкретной программы. Настройки терминала имеют приоритет или выступают значениями по умолчанию для настроек любой MQL-программы. Например, трейдер может запретить всю автоматическую торговлю, установив соответствующий флажок в диалоге настроек MetaTrader 5. При этом частные разрешения на торговлю, "выданные" ранее конкретным роботам в их диалогах, утрачивают силу.

В MQL5 API подобные ограничения (или наоборот, разрешения) доступны на чтение через функции TerminalInfoInteger и MQLInfoInteger. Поскольку они имеют одинаковый эффект на MQL-программу, та обязана проверять общие и частные запреты в равной степени тщательно (во избежание генерации ошибки при попытке выполнить недопустимое действие). Поэтому в данном разделе опции разных уровней объединены в единый список.

Все разрешения представляют собой логические флаги, то есть хранят значение true или false.

Идентификатор

Описание

TERMINAL_DLLS_ALLOWED

разрешение на использование DLL

TERMINAL_TRADE_ALLOWED

разрешение на автоматическую торговлю онлайн

TERMINAL_EMAIL_ENABLED

разрешение на отправку писем (SMTP-сервер и логин должны быть указаны в настройках терминала)

TERMINAL_FTP_ENABLED

разрешение на отправку файлов по FTP на указанный сервер (в том числе отчетов для указанного в настройках терминала торгового счета)

TERMINAL_NOTIFICATIONS_ENABLED

разрешение на отправку push-уведомлений на смартфон

MQL_DLLS_ALLOWED

разрешение на использование DLL для данной программы

MQL_TRADE_ALLOWED

разрешение на автоматическую торговлю для данной программы

MQL_SIGNALS_ALLOWED

разрешение на работу с сигналами для данной программы

Разрешение использовать DLL на уровне терминала означает, что при запуске MQL-программы, в которой есть ссылка на какую-либо динамическую библиотеку, в диалоге её свойств будет по умолчанию включен флаг Разрешить импорт DLL на закладке Зависимости. Если флаг в настройках терминала сброшен, то и опция в свойствах MQL-программы будет по умолчанию выключена. Пользователь в любом случае должен разрешить импорт для отдельной программы (есть одно исключение для скриптов, о котором сказано ниже). Если он этого не сделает, программа просто не запустится.

Иными словами, проверить флаги TERMINAL_DLLS_ALLOWED и MQL_DLLS_ALLOWED может либо программа без привязки к DLL, либо программа с привязкой, но для которой MQL_DLLS_ALLOWED однозначно равно true (в силу того, что она уже запустилась). Таким образом, в составе программных комплексов, требующих DLL, вероятно, имеет смысл предусмотреть независимую утилиту, которая отслеживала бы состояние флага и выводила диагностику для пользователя, если он его вдруг отключит. Например, эксперту может требоваться индикатор, использующий DLL. Тогда прежде чем пытаться загрузить индикатор и получить его дескриптор, эксперт может проверить флаг 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. Однако в индикаторах доступ ко всем торговым функциям запрещен вне зависимости от данных флагов. В тестере не допускается проверка MQL-программ с зависимостью от DLL.

От флагов TERMINAL_EMAIL_ENABLED, TERMINAL_FTP_ENABLED, TERMINAL_NOTIFICATIONS_ENABLED зависит работоспособность функций SendMail, SendFTP, SendNotification, которые описаны в разделе Сетевые функции. Флаг MQL_SIGNALS_ALLOWED влияет на доступность группы функций, управляющих подпиской на торговые сигналы mql5.com (не рассматриваются в данной книге). Его состояние соответствует опции Разрешить изменение настроек сигналов на закладке Общие в свойствах MQL-программы.

Поскольку проверка некоторых свойства требует дополнительных усилий, имеет смысл обернуть флаги в класс, скрывающий в своих методах множественные вызовы разных системных функций. Это тем более необходимо из-за того, что некоторые разрешения не ограничиваются только вышеприведенными опциями. Например, разрешение на торговлю может быть установлено (или снято) не только на уровне терминала или MQL-программы, но и для отдельного финансового инструмента — согласно его спецификации у вашего брокера и расписанию торговых сессий на бирже. В связи с этим мы пока представим заготовку класса Permissions, которая будет содержать лишь знакомые элементы, а затем усовершенствуем её с учетом прикладных API.

Благодаря программной прослойке в виде класса, программист избавлен от необходимости запоминать, какие разрешения определены для TerminalInfo-функций, а какие — для MqlInfo-функций.

Исходный код находится в файле EnvPermissions.mq5.

class Permissions
{
public:
   static bool isTradeEnabled(const string symbol = NULLconst datetime session = 0)
   {
      // TODO: будет дополнено прикладными проверками символа и сессий
      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 унаследует это значение.