Ошибки могут быть как от неправильно написанного кода советника, так и от сервера, когда по не зависящим от трейдера обстоятельствам торговые команды его советника не выполняются. Например, по причине зависания торгового сервера или обрыва связи с ним.
Поэтому разработчику торговых роботов на 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().
должны быть совместно скопированы и вставлены в код советника, в котором разработчик предусмотрел процедуру обработки ошибок.
Я рекомендую иметь все функции разработчика подобного плана (необходимые при разработке советника и т.п.) в отдельных файлах из которых они могут копироваться при необходимости в код программы. У меня этих файлов несколько: для позиций, для ордеров, для функций статистики и т.д.