2 взгляда на обертки функций в MQL.
Одна из самых распространенных задач для разработчика, это разработка процедуры открытия / модификации ордера. С виду ничего сложного нет, есть функция OrderSend и другие, никаких трудностей не просматривается. Но только на первый взгляд. На самом деле, скрипт, или эксперт может и не открыть ордер. Как в этом случае поступить?
Для реагирования на ошибочные и не только на ошибочные ситуации, приводящие к отказу в открытии, закрытии, модификации ордеров и служат обертки функций.Обертка функции выполняет какие то определенные действия, потом вызывает оригинальную функцию и обрабатывает ответ. В нашем случае, перед вызовом той же OrderSend можно было бы проверить, открыт ли рынок, не занят ли терминал. После вызова, в случае ошибки, можно было бы проанализировать её и предусмотреть несколько вариантов действий – повторить попытку, прекратить выполнение. Отметим, что написание оберток для OrderSend, OrderModify и проч., вопрос спорный. Некоторые разработчики предпочитают максимально детализировать разбор возвращаемых значений. Представляется, что, как это часто бывает в программировании, однозначно правильного ответа нет.
Представим первый из вариантов обертки для OrderSend (не лучший) в MT4:
#define NUMBEROFTRY 5 //Число попыток совершить торговую операцию
#define SLIPPAGE 5 //Проскальзывание
#define TIMEOUT 2000 //Таймаут между попытками
int OrderSendP( string symbol, int cmd, double volume, double price, double stoploss, double takeprofit,
int slippage = SLIPPAGE, int magic=0, string comment="0", datetime expiration=0,
int NumberOfTry = NUMBEROFTRY, int iTimeOut = TIMEOUT, color arrow_color=CLR_NONE)
{
int ticket = -1;
for (int i = 0; i < NumberOfTry; i++) {
while (IsTradeContextBusy()) Sleep(iTimeOut);
RefreshRates();
ticket = OrderSend(symbol,cmd,volume,price,slippage,stoploss,takeprofit,comment,magic,expiration,arrow_color);
if (ticket != -1) return (ticket);
switch(GetLastError() ) {
case ERR_NO_ERROR:
case ERR_NO_RESULT:
return (ticket);
break;
default:
Sleep(iTimeOut);
break;
}//end switch
}//end for (i = 0; i < NumberOfTry; i++)
return (-1);
}
Вызов очень похож на вызов оригинальной торговой функции, введены значения некоторых параметров по умолчанию, добавлены несколько новых важных параметров:
- NumberOfTry. Число попыток повторить торговую операцию.
- iTimeOut. Таймаут между попытками.
Как видно, в данной обертке выбор сделан в пользу упрощения основного оператора switch. В случае возникновения ошибки функция делает NumberOfTry попыток установить ордер с таймаутом между попытками в iTimeOut.
Второй вариант, обертка функции удаления отложенных ордеров, более “продвинутое” решение для MT5:
bool DeletePendingOrder(int ticket= -1, int NumberOfTry = NUMBEROFTRY, int iTimeOut = TIMEOUT)
{
if (ticket != -1) {
if (OrderSelect(ticket) == false) {glob_err = GetLastError(); return (false);}
}
else ticket = (int)OrderGetInteger(ORDER_TICKET);
CTrade Trade;
bool b;
for (int i = 0; i < NumberOfTry; i++) {
b = Trade.OrderDelete(ticket);
glob_err = (int)Trade.ResultRetcode();
if (b == true && glob_err == TRADE_RETCODE_DONE) return (true);
switch(glob_err) {
case TRADE_RETCODE_DONE_PARTIAL:
case TRADE_RETCODE_ERROR:
case TRADE_RETCODE_INVALID_PRICE:
case TRADE_RETCODE_INVALID_STOPS:
case TRADE_RETCODE_PRICE_CHANGED:
case TRADE_RETCODE_PRICE_OFF:
case TRADE_RETCODE_TOO_MANY_REQUESTS:
case TRADE_RETCODE_CONNECTION:
case TRADE_RETCODE_REQUOTE:
Sleep(iTimeOut);
break;
case TRADE_RETCODE_DONE:
return (true);
default:
return (false);
}//end switch
}//for (int t=0; t<=NumberOfTry; t++)
return (false);
}
Можно видеть, как функция фильтрует ответ сервера и, в зависимости от него, фиксирует ошибку, делает паузу, или нормально завершает работу.
Что именно означает та, или иная ошибка в MT4 можно увидеть в файле stdlib.mq4 и stderror.mqh, входящих в поставку. Для MT5 подобной информации нет, но её можно обнаружить в архиве error_MQL5.zip, приложенным к настоящей статье.
Аналогичным образом можно создавать обертки и для других торговых функций – OrderModify, OrderDelete, OrderClose. Важно не забывать об этом, т.к. использование торговых функций в “чистом” виде может быть причиной очень серьезных последствий.