Программное удаление советников и скриптов: ExpertRemove

При необходимости разработчик может организовать остановку и выгрузку MQL-программ двух типов: экспертов и скриптов. Это делается с помощью функции ExpertRemove.

void ExpertRemove()

Функция не имеет параметров и не возвращает значения. Она отправляет в среду исполнения MQL-программ запрос на удаление текущей программы. Фактически это приводит к взведению флага _StopFlag и прекращению приема (и обработки) всех последующих событий. После этого программе дается 3 секунды на то, чтобы правильно закончить свою работу: освободить ресурсы, прервать циклы в алгоритмах и т.д. Если программа этого не сделает, она будет выгружена принудительно, с потерей промежуточных данных.

В индикаторах и сервисах данная функция не работает (программа продолжает выполняться).

Каждое обращение к функции сигнализируется в журнале записью "Вызвана функция ExpertRemove()" ("ExpertRemove() function called").

Функция в первую очередь востребована в экспертах, которые невозможно прервать иным способом. В случае скриптов, как правило, более простым способом является прерывание цикла (если он есть) с помощью оператора break. Но если циклы вложены, или алгоритм использует множество вызовов функций одна из другой, проще на разных уровнях учитывать флаг остановки в условиях для продолжения расчетов, а в случае ошибочной ситуации взводить этот флаг с помощью ExpertRemove. Если не использовать данный встроенный флаг, в любом случае пришлось бы вводить аналогичную по назначению глобальную переменную.

В скрипте ScriptRemove.mq5 приведен пример использования ExpertRemove.

Потенциальную проблему в работе алгоритма, которая приводит к необходимости выгрузки скрипта, эмулирует класс ProblemSource. В его конструкторе случайным образом вызывается ExpertRemove.

class ProblemSource
{
public:
   ProblemSource()
   {
      // имитируем проблему во время создания объекта, например,
      // с захватом неких ресурсов, таких как файл и т.д.
      if(rand() > 20000)
      {
         ExpertRemove(); // установит _StopFlag в true
      }
   }
};

Далее объекты этого класса создаются на глобальном уровне и внутри вспомогательной функции.

ProblemSource global// объект может породить ошибку
   
void SubFunction()
{
   ProblemSource local// объект может породить ошибку
   // имитируем некую работу (надо проверить целостность объекта!)
   Sleep(1000);
}

Теперь используем SubFunction в работе OnStart внутри цикла с условием на IsStopped.

void OnStart()
{
   int count = 0;
   // цикл пока не остановит пользователь или сама программа
   while(!IsStopped())
   {
      SubFunction();
      Print(++count);
   }
}

Вот пример вывода в журнал (каждый запуск будет отличаться из-за случайности):

1
2
3
ExpertRemove() function called
4

Обратите внимание, что если ошибка произойдет при создании глобального объекта, цикл не выполнится ни разу.

Поскольку эксперты могут запускаться в тестере, там функция ExpertRemove также имеет эффект, причем он зависит от места вызова функции. Если это делается внутри обработчика OnInit, произойдет отмена тестирования, то есть одного прогона тестера на текущем наборе параметров эксперта. Такое завершение рассматривается как ошибка инициализации. При вызове ExpertRemove в любом другом месте алгоритма тестирование советника прервется досрочно, но будет обработано штатным образом, с вызовом OnDeinit и OnTester. В этом случае будет получена накопленная торговая статистика и значение критерия оптимизации, с учетом того, что эмулируемое серверное время TimeCurrent не достигнет конечной даты в настройках тестера.