Процедура обработки ошибок

Программирование прибыли: от азов к секретам мастерства. Читайте, спрашивайте, делитесь опытом.
Бонус за сообщение 0.5$
Ответственный Модератор - Haos

Процедура обработки ошибок

Сообщение Haos » 26 мар 2021, 05:30

В ходе работы советника, когда он запущен на выполнение на торговом сервере или на персональном вычислителе трейдера, могут возникать всевозможные ошибки. С одной стороны, это неприятное событие, а с другой стороны редко когда только что созданная программа не имеет ошибок. Поэтому их нужно как-то отслеживать и заранее знать какие действия следует запрограммировать в случае возникновения той или иной ошибки.

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

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

Основная функция, которая ставится в код советника имеет имя f__ProcessError():
Код: выделить все
bool f__ProcessError(int err)
{
/*
   Описание : Обработка ошибок
   Используется функция: f__PrintError()
   Параметры:                                                               
   err - номер ошибки           
*/
   int iteration;

   if(err > 1) f__PrintError(err);
   switch(err)
   {
   // Некритические ошибки
   case 0:     // ERR_NO_ERROR
   case 135:   // ERR_PRICE_CHANGED
   case 138:   // ERR_REQUOTE
      return(true);
   // Некритические ошибки, требующие таймаута
   case 4:     // ERR_SERVER_BUSY
   case 128:   // ERR_TRADE_TIMEOUT
      Sleep(1000 * 60);
      return(true);   
   case 129:   // ERR_INVALID_PRICE
   case 130:   // ERR_INVALID_STOPS
      //if (WorkMode==ModeManual && ShowConfirm) MessageBox("Неправильные стопы", VISITCARD, MB_OK);
      return(false);
   case 136:   // ERR_OFF_QUOTES
      Sleep(1000 * 5);
      return(true);   
   case 137:   // ERR_BROKER_BUSY
   case 145:   // ERR_TRADE_MODIFY_DENIED
      Sleep(1000 * 15);
      return(true);   
   // Нет связи с сервером. Пытаемся восстановить связь
   case 6:     // ERR_NO_CONNECTION
   {
      bool connect = false;
      iteration = 0;
      while((!connect) || (iteration < 60)) // в течение 5 минут пытаемся подконнектиться к серверу
      {
         Sleep(1000 * 5);
         connect = IsConnected();
         if(connect)
         {
            Print("Связь восстановлена");
            return(true);
         }
         iteration++;
         Print("Связь не восстановлена, прошло ", iteration * 5, " секунд.");
      }
      Print("Соединение в течение ", iteration * 5, " секунд восстановить не удалось.");
      return(false);
   }
   // Подсистема торговли занята. Ждем, пока освободится
   case 146:   // ERR_TRADE_CONTEXT_BUSY
   {
      bool tradecontextbusy = true;
      iteration = 0;
      while((tradecontextbusy) || (iteration < 60)) // в течение 5 минут ждем освобождения подсистемы торговли
      {
         Sleep(1000 * 5);
         tradecontextbusy = IsTradeContextBusy();
         if(!tradecontextbusy)
         {
            Print("Подсистема торговли освободилась.");
            return(true);
         }
         iteration++;
         Print("Подсистема торговли все еще занята, прошло ", iteration * 5, " секунд.");
      }
      Print("Подсистема торговли в течение ", iteration * 5, " секунд не освободилась.");
      return(false);
   }
   // Критические ошибки. Прекращаем попытки открытия ордера
   case 1:     // ERR_NO_RESULT
   case 2:     // ERR_COMMON_ERROR
   case 3:     // ERR_INVALID_TRADE_PARAMETERS
   case 5:     // ERR_OLD_VERSION
   case 7:     // ERR_NOT_ENOUGH_RIGHTS
   case 8:     // ERR_TOO_FREQUENT_REQUESTS
   case 9:     // ERR_MALFUNCTIONAL_TRADE
   case 64:    // ERR_ACCOUNT_DISABLED
   case 65:    // ERR_INVALID_ACCOUNT
   case 131:   // ERR_INVALID_TRADE_VOLUME
   case 132:   // ERR_MARKET_CLOSED
   case 133:   // ERR_TRADE_DISABLED
   case 134:   // ERR_NOT_ENOUGH_MONEY
   case 139:   // ERR_ORDER_LOCKED
   case 140:   // ERR_LONG_POSITIONS_ONLY_ALLOWED
   case 141:   // ERR_TOO_MANY_REQUESTS
   case 142:
   case 143:
   case 144:
   case 147:   // ERR_TRADE_EXPIRATION_DENIED
   case 148:   // ERR_TRADE_TOO_MANY_ORDERS
   case 4110:  // ERR_LONGS_NOT_ALLOWED
   case 4111:  // ERR_SHORTS_NOT_ALLOWED
      return(false);
   case 4109:  // ERR_TRADE_NOT_ALLOWED
      //MessageBox("Для совершения операций необходимо поставить галочку \"Разрешить советнику торговать\" в настройках терминала", VISITCARD, MB_OK);
      return(false);
   }
   return(false);
}

Это логическая функция (тип bool), параметром которой является код ошибки. Т.е. в коде советника она должна использоваться примерно таким способом:

Код: выделить все
if(!f__ProcessError(GetLastError())) return(false);

Так или иначе, в рассматриваемых в этом разделе форума функциях разработчика, мы часто видим использование процедуры обработки ошибок именно через рассматриваемые здесь функции, так что примеров достаточно много.

GetLastError() - встроенная в MQL4 функция, которая возвращает код последней ошибки, его то мы и передаем в качестве параметра в нашу функцию для обработки ошибок - f__ProcessError().

Как видно из кода функции по обработке ошибок f__ProcessError(), она использует в своей работе функцию f__PrintError(), которая журналирует код ошибки с описанием, в случае возникновения которую, разработчик может непосредственно обозреть на вкладке Журнал при работе советника. Код этой функции ниже:

Код: выделить все
int f__PrintError(int err)
{
   Print("ERROR ", err, ":  ", f__Err2str(err));
   return(0);
}


Эта вторая функция необходимая нам для работы первой также использует в своей работе еще одну функцию f__Err2str(int err), возвращающую описание ошибки по её номеру. Код этой функции ниже:

Код: выделить все
//+------------------------------------------------------------------+
//| Получение описания ошибки по ее номеру                           |
//+------------------------------------------------------------------+
string f__Err2str(int err)
{
   switch(err)
   {
   case 0:
      return("Нет ошибки");
   case 1:
      return("Функция модификации ордера пытается изменить уже установленные значения такими же значениями");
   case 2:
      return("Общая ошибка");
   case 3:
      return("В торговую функцию переданы неправильные параметры");
   case 4:
      return("Торговый сервер занят");
   case 5:
      return("Старая версия клиентского терминала");
   case 6:
      return("Нет связи с торговым сервером");
   case 7:
      return("Недостаточно прав");
   case 8:
      return("Слишком частые запросы");
   case 9:
      return("Недопустимая операция нарушающая функционирование сервера");
   case 64:
      return("Счет заблокирован");
   case 65:
      return("Неправильный номер счета");
   case 128:
      return("Истек срок ожидания совершения сделки");
   case 129:
      return("Неправильная цена");
   case 130:
      return("Неправильные стопы");
   case 131:
      return("Неправильный объем сделки");
   case 132:
      return("Рынок закрыт");
   case 133:
      return("Торговля запрещена");
   case 134:
      return("Недостаточно денег для совершения операции");
   case 135:
      return("Цена изменилась");
   case 136:
      return("Нет цен");
   case 137:
      return("Брокер занят");
   case 138:
      return("Реквот! Новые цены");
   case 139:
      return("Ордер заблокирован и уже обрабатывается");
   case 140:
      return("Разрешена только покупка");
   case 141:
      return("Слишком много запросов");
   case 142:
      return("Ордер поставлен в очередь");
   case 143:
      return("Ордер принят дилером к исполнению");
   case 144:
      return("Ордер аннулирован самим клиентом при ручном подтверждении сделки");
   case 145:
      return("Модификация запрещена, так как ордер слишком близок к рынку");
   case 146:
      return("Подсистема торговли занята");
   case 147:
      return("Использование даты истечения ордера запрещено брокером");
   case 148:
      return("Количество открытых и отложенных ордеров достигло предела, установленного брокером");
   case 4109:
      return("Торговля не разрешена. Необходимо включить опцию \"Разрешить советнику торговать\" в свойствах эксперта");
   case 4110:
      return("Длинные позиции не разрешены");
   case 4111:
      return("Короткие позиции не разрешены");
   }
   return("Описание ошибки не известно");
}


Вот эти три функции:

1. f__ProcessError();
2. f__PrintError();
3. f__Err2str().

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

Я рекомендую иметь все функции разработчика подобного плана (необходимые при разработке советника и т.п.) в отдельных файлах из которых они могут копироваться при необходимости в код программы. У меня этих файлов несколько: для позиций, для ордеров, для функций статистики и т.д.
Аватар пользователя
Haos
Специалист MQL
 
Сообщений: 24699
Зарегистрирован: 29 мар 2014, 16:07
Средств на руках: 193.70 Доллар
Группа: Главные модераторы
Благодарил (а): 3379 раз.
Поблагодарили: 8200 раз.

Вернуться в MQL – теория и практика

Кто сейчас на форуме?

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 67

Права доступа к форуму

Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения