Некоторое время назад вышел топик
«Как переписать советник для реальной торговли», где рассматривалось создание эксперта на основе заимствованных функций. В этом же топике зададимся целью создать собственные функции и используем их для создания советника.
Чем же функция для тестера будет отличаться от версии онлайн?
1. Проверкой определенных параметров.
2. Заданным количеством попыток установить/закрыть/модифицировать/удалить ордер.
3. Обработкой ошибок по определенному алгоритму.
Для написания функций кроме приведенных в прошлом топике:
forum.mql4.com/ru/38949
www.opentraders.ru/downloads/1095/
www.opentraders.ru/downloads/1096/
я также использовал коды экспертов, созданных опытными разработчиками:
www.mql5.com/ru/code/15163
www.mql5.com/ru/code/14072
Для начала перепишем удаление отложек и закрытие ордеров. Начнем с удаления т.к. она самая простая и по ее примеру перепишем остальные.
//+------------------------------------------------------------------+
//| Удаление отложенных ордеров |
//+------------------------------------------------------------------+
void DelOrder()
{
bool del;
for(int i=OrdersTotal()-1;i>=0;i--)
{
if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
{
if(OrderSymbol()==Symbol() && OrderMagicNumber()==Magic)
{
if(OrderType()>1) del=OrderDelete(OrderTicket());
}
}
}
}
//+------------------------------------------------------------------+
//| Закрытие позиции по типу ордера |
//+------------------------------------------------------------------+
void CloseAll(int ot=-1)
{
bool cl;
for(int i=OrdersTotal()-1;i>=0;i--)
{
if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
{
if(OrderSymbol()==Symbol() && OrderMagicNumber()==Magic)
{
if(OrderType()==0 && (ot==0 || ot==-1))
{
RefreshRates();
cl=OrderClose(OrderTicket(),OrderLots(),NormalizeDouble(Bid,Digits),Slip,White);
}
if(OrderType()==1 && (ot==1 || ot==-1))
{
RefreshRates();
cl=OrderClose(OrderTicket(),OrderLots(),NormalizeDouble(Ask,Digits),Slip,White);
}
}
}
}
}
Начинаем с попыток:
for(int k=1;k<=MaxEntry;k++)
{
.....
}
Далее проверим состояние кнопок и галочек в терминале:
if(!IsTesting() && (!IsExpertEnabled() || IsStopped())) break;
while(!IsTradeAllowed()) Sleep(5000);
Также можно проверить тип и время закрытия ордера:
if(OrderCloseTime()>0)
{
Print("Ордер был закрыт или удален ");
.....
}
if(Type<2)
{
Print(" Ордер удалить нельзя, он уже исполнен ");
.....
}
Теперь займемся обработкой ошибок.
Для расшифровки кодов ошибок можно пользоваться функцией
ErrorDescription из библиотеки
stdlib.mq4, но лучше расположить ее в теле эксперта, это может пригодиться для маркета.
//+------------------------------------------------------------------+
// Пример использования Print("Ошибка : ",Error(GetLastError())); |
//+------------------------------------------------------------------+
string ErrorDescription(int error_code)
{
string error_string;
//----
switch(error_code)
{
//---- Коды ошибок, возвращаемые торговым сервером:
case 0: error_string="Нет ошибок"; break;
case 1: error_string="Нет ошибки, но результат неизвестен"; break;
case 2: error_string="Общая ошибка"; break;
case 3: error_string="Неправильные параметры"; break;
case 4: error_string="Торговый сервер занят"; break;
case 5: error_string="Старая версия клиентского терминала"; break;
case 6: error_string="Нет связи с торговым сервером"; break;
case 7: error_string="Недостаточно прав"; break;
case 8: error_string="Слишком частые запросы"; break;
case 9: error_string="Недопустимая операция нарушающая функционирование сервера"; break;
case 64: error_string="Счет заблокирован"; break;
case 65: error_string="Неправильный номер счета"; break;
case 128: error_string="Истек срок ожидания совершения сделки"; break;
case 129: error_string="Неправильная цена"; break;
case 130: error_string="Неправильные стопы"; break;
case 131: error_string="Неправильный объем"; break;
case 132: error_string="Рынок закрыт"; break;
case 133: error_string="Торговля запрещена"; break;
case 134: error_string="Недостаточно денег для совершения операции"; break;
case 135: error_string="Цена изменилась"; break;
case 136: error_string="Нет цен"; break;
case 137: error_string="Брокер занят"; break;
case 138: error_string="Новые цены"; break;
case 139: error_string="Ордер заблокирован и уже обрабатывается"; break;
case 140: error_string="Разрешена только покупка"; break;
case 141: error_string="Слишком много запросов"; break;
case 145: error_string="Модификация запрещена, так как ордер слишком близок к рынку"; break;
case 146: error_string="Подсистема торговли занята"; break;
case 147: error_string="Использование даты истечения ордера запрещено брокером"; break;
case 148: error_string="Количество открытых и отложенных ордеров достигло предела, установленного брокером.";break;
//---- Коды ошибок выполнения MQL4-программы:
case 4000: error_string="Нет ошибки"; break;
case 4001: error_string="Неправильный указатель функции"; break;
case 4002: error_string="Индекс массива - вне диапазона"; break;
case 4003: error_string="Нет памяти для стека функций"; break;
case 4004: error_string="Переполнение стека после рекурсивного вызова"; break;
case 4005: error_string="На стеке нет памяти для передачи параметров"; break;
case 4006: error_string="Нет памяти для строкового параметра"; break;
case 4007: error_string="Нет памяти для временной строки"; break;
case 4008: error_string="Неинициализированная строка"; break;
case 4009: error_string="Неинициализированная строка в массиве"; break;
case 4010: error_string="Нет памяти для строкового массива"; break;
case 4011: error_string="Слишком длинная строка"; break;
case 4012: error_string="Остаток от деления на ноль"; break;
case 4013: error_string="Деление на ноль"; break;
case 4014: error_string="Неизвестная команда"; break;
case 4015: error_string="Неправильный переход"; break;
case 4016: error_string="Неинициализированный массив"; break;
case 4017: error_string="Вызовы DLL не разрешены"; break;
case 4018: error_string="Невозможно загрузить библиотеку"; break;
case 4019: error_string="Невозможно вызвать функцию"; break;
case 4020: error_string="Вызовы внешних библиотечных функций не разрешены"; break;
case 4021: error_string="Недостаточно памяти для строки, возвращаемой из функции"; break;
case 4022: error_string="Система занята"; break;
case 4050: error_string="Неправильное количество параметров функции"; break;
case 4051: error_string="Недопустимое значение параметра функции"; break;
case 4052: error_string="Внутренняя ошибка строковой функции"; break;
case 4053: error_string="Ошибка массива"; break;
case 4054: error_string="Неправильное использование массива-таймсерии"; break;
case 4055: error_string="Ошибка пользовательского индикатора"; break;
case 4056: error_string="Массивы несовместимы"; break;
case 4057: error_string="Ошибка обработки глобальныех переменных"; break;
case 4058: error_string="Глобальная переменная не обнаружена"; break;
case 4059: error_string="Функция не разрешена в тестовом режиме"; break;
case 4060: error_string="Функция не разрешена"; break;
case 4061: error_string="Ошибка отправки почты"; break;
case 4062: error_string="Ожидается параметр типа string"; break;
case 4063: error_string="Ожидается параметр типа integer"; break;
case 4064: error_string="Ожидается параметр типа double"; break;
case 4065: error_string="В качестве параметра ожидается массив"; break;
case 4066: error_string="Запрошенные исторические данные в состоянии обновления"; break;
/*м*/ case 4067: error_string="Ошибка при выполнении торговой операции"; break;
case 4099: error_string="Конец файла"; break;
case 4100: error_string="Ошибка при работе с файлом"; break;
case 4101: error_string="Неправильное имя файла"; break;
case 4102: error_string="Слишком много открытых файлов"; break;
case 4103: error_string="Невозможно открыть файл"; break;
case 4104: error_string="Несовместимый режим доступа к файлу"; break;
case 4105: error_string="Ни один ордер не выбран"; break;
case 4106: error_string="Неизвестный символ"; break;
case 4107: error_string="Неправильный параметр цены для торговой функции"; break;
case 4108: error_string="Неверный номер тикета"; break;
case 4109: error_string="Торговля не разрешена. Необходимо включить опцию Разрешить советнику торговать в свойствах эксперта."; break;
case 4110: error_string="Длинные позиции не разрешены. Необходимо проверить свойства эксперта."; break;
case 4111: error_string="Короткие позиции не разрешены. Необходимо проверить свойства эксперта."; break;
case 4200: error_string="Объект уже существует"; break;
case 4201: error_string="Запрошено неизвестное свойство объекта"; break;
case 4202: error_string="Объект не существует"; break;
case 4203: error_string="Неизвестный тип объекта"; break;
case 4204: error_string="Нет имени объекта"; break;
case 4205: error_string="Ошибка координат объекта"; break;
case 4206: error_string="Не найдено указанное подокно"; break;
default: error_string="Ошибка при работе с объектом";
}
//----
return(error_string);
}
string ErrorDescription(int error_code)
{
string error_string;
//----
switch(error_code)
{
// ---- Error codes returned from trade server:
case 0: error_string="No error"; break;
case 1: error_string="No error, but the result is unknown"; break;
case 2: error_string="Common error"; break;
case 3: error_string="Wrong parameters"; break;
case 4: error_string="Trade server is busy"; break;
case 5: error_string="Old version of client terminal"; break;
case 6: error_string="No connection with trade server"; break;
case 7: error_string="not Enough rights"; break;
case 8: error_string="Too frequent requests"; break;
case 9: error_string="invalid operation in violation of the functioning of the server"; break;
case 64: error_string="Account is locked"; break;
case 65: error_string="Invalid account number"; break;
case 128: error_string="Expired expectations of the transaction"; break;
case 129: error_string="Invalid price"; break;
case 130: error_string="invalid stops"; break;
case 131: error_string="Wrong volume"; break;
case 132: error_string="Market is closed"; break;
case 133: error_string="Trade is disabled"; break;
case 134: error_string="not Enough money for the transaction"; break;
case 135: error_string="Price changed"; break;
case 136: error_string="off quotes"; break;
case 137: error_string="Broker is busy"; break;
case 138: error_string="New prices"; break;
case 139: error_string="Order is locked."; break;
case 140: error_string="long positions only Allowed."; break;
case 141: error_string="Too many requests"; break;
case 145: error_string="Modification denied because order too close to market"; break;
case 146: error_string="trade context is busy."; break;
case 147: error_string="Using the expiration date of the warrant is prohibited broker"; break;
case 148: error_string="Amount of open and pending orders has reached the limit set by the broker";break;
case 149: error_string="An attempt to open an order opposite to the existing one when hedging is disabled"; break;
case 150: error_string="An attempt to close an order contravening the FIFO rule";break;
// ---- Error codes run MQL4 programs:
case 4000: error_string="No error"; break;
case 4001: error_string="Wrong function pointer"; break;
case 4002: error_string="array Index is out of range"; break;
case 4003: error_string="No memory to stack functions"; break;
case 4004: error_string="stack Overflow after recursive call"; break;
case 4005: error_string="not enough stack for parameter passing"; break;
case 4006: error_string="No memory for parameter string"; break;
case 4007: error_string="No memory for temp string"; break;
case 4008: error_string="not initialized string"; break;
case 4009: error_string="not initialized string in array"; break;
case 4010: error_string="No memory for string array"; break;
case 4011: error_string="Too long string"; break;
case 4012: error_string="Remainder from division by zero"; break;
case 4013: error_string="zero Divide"; break;
case 4014: error_string="Unknown command"; break;
case 4015: error_string="Wrong jump"; break;
case 4016: error_string="not initialized array"; break;
case 4017: error_string="DLL Calls are not allowed"; break;
case 4018: error_string="Cannot load library"; break;
case 4019: error_string="Cannot call function"; break;
case 4020: error_string="Calls external library functions are not allowed"; break;
case 4021: error_string="not Enough memory for the string returned from function"; break;
case 4022: error_string="System is busy"; break;
case 4050: error_string="Wrong number of function parameters"; break;
case 4051: error_string="Invalid function parameter value."; break;
case 4052: error_string="Internal error string functions"; break;
case 4053: error_string="some array Error."; break;
case 4054: error_string="invalid use of array-timeseries"; break;
case 4055: error_string="custom indicator Error"; break;
case 4056: error_string="Arrays are incompatible"; break;
case 4057: error_string="Error processing globalnej variables"; break;
case 4058: error_string="global variable not found"; break;
case 4059: error_string="Function is not allowed in testing mode"; break;
case 4060: error_string="Function is not allowed"; break;
case 4061: error_string="Error sending mail"; break;
case 4062: error_string="Expected parameter type string"; break;
case 4063: error_string="Expected parameter type integer"; break;
case 4064: error_string="Expected parameter type double"; break;
case 4065: error_string="as expected array parameter"; break;
case 4066: error_string="Requested history data in update state"; break;
/*m*/ case 4067: error_string="Error executing trading operations"; break;
case 4099: error_string="End of file"; break;
case 4100: error_string="Error when working with file"; break;
case 4101: error_string="Wrong file name"; break;
case 4102: error_string="Too many open files"; break;
case 4103: error_string="Cannot open file"; break;
case 4104: error_string="Incompatible access to a file"; break;
case 4105: error_string="No warrant is not selected"; break;
case 4106: error_string="Unknown symbol"; break;
case 4107: error_string="Invalid price parameter for trade function"; break;
case 4108: error_string="Invalid ticket number"; break;
case 4109: error_string="Trade is not allowed. You must enable the option to Allow the EA to trade in the expert properties."; break;
case 4110: error_string="Long positions are not allowed. You need to check the expert properties."; break;
case 4111: error_string="shorts are not allowed.. You need to check the expert properties."; break;
case 4200: error_string="Object already exists"; break;
case 4201: error_string="Requested an unknown object property"; break;
case 4202: error_string="Object is not exist"; break;
case 4203: error_string="Unknown object type"; break;
case 4204: error_string="No object name"; break;
case 4205: error_string="Error coordinates object"; break;
case 4206: error_string="Not found specified subwindow"; break;
default: error_string="Error when working with object";
}
//----
return(error_string);
}
За действия эксперта после получения ошибки отвечает функция
ErrorsAction().
int ErrorsAction(int error_code)
{
int act=0;
//----
switch(error_code)
{
// ---- Error codes returned from trade server:
case 0: Print("No error"); break;
case 1: Print("No error, but the result is unknown"); return(0);
case 2: Print("Common error"); return(2);
case 3: Print("Wrong parameters"); return(0);
case 4: Print("Trade server is busy"); return(1);
case 5: Print("Old version of client terminal"); return(2);
case 6: Print("No connection with trade server"); return(0);
case 7: Print("not Enough rights"); return(2);
case 8: Print("Too frequent requests"); return(1);
case 9: Print("invalid operation in violation of the functioning of the server"); return(2);
case 64: Print("Account is locked"); return(2);
case 65: Print("Invalid account number"); return(2);
case 128: Print("Expired expectations of the transaction"); return(0);
case 129: Print("Invalid price"); return(1);
case 130: Print("invalid stops"); return(0);
case 131: Print("Wrong volume"); return(0);
case 132: Print("Market is closed"); return(0);
case 133: Print("Trade is disabled"); return(2);
case 134: Print("not Enough money for the transaction"); return(2);
case 135: Print("Price changed"); return(1);
case 136: Print("off quotes"); return(1);
case 137: Print("Broker is busy"); return(1);
case 138: Print("New prices"); return(1);
case 139: Print("Order is locked."); return(0);
case 140: Print("long positions only Allowed."); return(2);
case 141: Print("Too many requests"); return(1);
case 145: Print("Modification denied because order too close to market"); return(0);
case 146: Print("trade context is busy."); return(1);
case 147: Print("Using the expiration date of the warrant is prohibited broker"); return(2);
case 148: Print("Amount of open and pending orders has reached the limit set by the broker"); return(0);
case 149: Print("An attempt to open an order opposite to the existing one when hedging is disabled"); return(2);
case 150: Print("An attempt to close an order contravening the FIFO rule"); return(2);
// ---- Error codes run MQL4 programs:
case 4000: Print("No error"); return(1);
case 4001: Print("Wrong function pointer"); return(0);
case 4002: Print("array Index is out of range"); return(0);
case 4003: Print("No memory to stack functions"); return(0);
case 4004: Print("stack Overflow after recursive call"); return(0);
case 4005: Print("not enough stack for parameter passing"); return(0);
case 4006: Print("No memory for parameter string"); return(0);
case 4007: Print("No memory for temp string"); return(1);
case 4008: Print("not initialized string"); return(1);
case 4009: Print("not initialized string in array"); return(0);
case 4010: Print("No memory for string array"); return(0);
case 4011: Print("Too long string"); return(0);
case 4012: Print("Remainder from division by zero"); return(0);
case 4013: Print("zero Divide"); return(0);
case 4014: Print("Unknown command"); return(0);
case 4015: Print("Wrong jump"); return(0);
case 4016: Print("not initialized array"); return(0);
case 4017: Print("DLL Calls are not allowed"); return(0);
case 4018: Print("Cannot load library"); return(0);
case 4019: Print("Cannot call function"); return(0);
case 4020: Print("Calls external library functions are not allowed"); return(0);
case 4021: Print("not Enough memory for the string returned from function"); return(0);
case 4022: Print("System is busy"); return(0);
case 4050: Print("Wrong number of function parameters"); return(0);
case 4051: Print("Invalid function parameter value."); return(0);
case 4052: Print("Internal error string functions"); return(0);
case 4053: Print("some array Error."); return(0);
case 4054: Print("invalid use of array-timeseries"); return(0);
case 4055: Print("custom indicator Error"); return(0);
case 4056: Print("Arrays are incompatible"); return(0);
case 4057: Print("Error processing globalnej variables"); return(0);
case 4058: Print("global variable not found"); return(0);
case 4059: Print("Function is not allowed in testing mode"); return(0);
case 4060: Print("Function is not allowed"); return(0);
case 4061: Print("Error sending mail"); return(0);
case 4062: Print("Expected parameter type string"); return(0);
case 4063: Print("Expected parameter type integer"); return(0);
case 4064: Print("Expected parameter type double"); return(0);
case 4065: Print("as expected array parameter"); return(0);
case 4066: Print("Requested history data in update state"); return(0);
case 4067: Print("Error executing trading operations"); return(0);
case 4099: Print("End of file"); return(0);
case 4100: Print("Error when working with file"); return(0);
case 4101: Print("Wrong file name"); return(0);
case 4102: Print("Too many open files"); return(0);
case 4103: Print("Cannot open file"); return(0);
case 4104: Print("Incompatible access to a file"); return(0);
case 4105: Print("No warrant is not selected"); return(0);
case 4106: Print("Unknown symbol"); return(0);
case 4107: Print("Invalid price parameter for trade function"); return(0);
case 4108: Print("Invalid ticket number"); return(0);
case 4109: Print("Trade is not allowed. You must enable the option to Allow the EA to trade in the expert properties."); return(2);
case 4110: Print("Long positions are not allowed. You need to check the expert properties."); return(2);
case 4111: Print("shorts are not allowed.. You need to check the expert properties."); return(2);
case 4200: Print("Object already exists"); return(0);
case 4201: Print("Requested an unknown object property"); return(0);
case 4202: Print("Object is not exist"); return(0);
case 4203: Print("Unknown object type"); return(0);
case 4204: Print("No object name"); return(0);
case 4205: Print("Error coordinates object"); return(0);
case 4206: Print("Not found specified subwindow"); return(0);
default: Print("Error when working with object");
}
//----
return(0);
}
Результатом получения определенной ошибки будет небольшая или длительная пауза, а в исключительных случаях остановка работы эксперта.
if(del)
{
Print("Order: "+(string)OrderTicket()+" is removed successfully");
break;
}
if(!del)
{
err=GetLastError();
Print("Error(",err,") Order delete error: ",ErrorDescription(err));
// Блокировка работы советника
if(ErrorsAction(err)==2)
{
trade=false;
Print("Stop the Advisor!");
return;
}
// Длительная пауза
if(ErrorsAction(err)==1)
{
Sleep(1000*LongPause);
}
// Небольшая пауза
if(ErrorsAction(err)==0)
{
Sleep(1000*ShortPause);
}
}
Целиком функция удаления ордеров будет выглядеть так:
//+------------------------------------------------------------------+
//| Удаление отложенных ордеров |
//+------------------------------------------------------------------+
void DelOrderReal()
{
bool del=true;
int err=0;
for(int i=OrdersTotal()-1;i>=0;i--)
{
if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
{
if(OrderSymbol()==Symbol() && OrderMagicNumber()==Magic)
{
for(int k=1;k<=MaxEntry;k++)
{
if(!IsTesting() && (!IsExpertEnabled() || IsStopped())) break;
while(!IsTradeAllowed()) Sleep(5000);
if(OrderType()>1) del=OrderDelete(OrderTicket());
if(del)
{
Print("Order: "+(string)OrderTicket()+" is removed successfully");
break;
}
if(!del)
{
err=GetLastError();
Print("Error(",err,") Order delete error: ",ErrorDescription(err));
// Блокировка работы советника
if(ErrorsAction(err)==2)
{
trade=false;
Print("Stop the Advisor!");
return;
}
// Длительная пауза
if(ErrorsAction(err)==1)
{
Sleep(1000*LongPause);
}
// Небольшая пауза
if(ErrorsAction(err)==0)
{
Sleep(1000*ShortPause);
}
}
}
}
}
}
}
Точно таким же образом перепишем закрытие позиций: проверки, попытки, обработка ошибок:
//+------------------------------------------------------------------+
//| Закрытие позиции по типу ордера |
//+------------------------------------------------------------------+
void CloseAllReal(int ot=-1)
{
bool cl;
int err=0;
for(int i=OrdersTotal()-1;i>=0;i--)
{
if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
{
if(OrderSymbol()==Symbol() && OrderMagicNumber()==Magic)
{
if(OrderType()==0 && (ot==0 || ot==-1))
{
for(int k=1;k<=MaxEntry;k++)
{
if(!IsTesting() && (!IsExpertEnabled() || IsStopped())) break;
while(!IsTradeAllowed()) Sleep(5000);
RefreshRates();
cl=OrderClose(OrderTicket(),OrderLots(),NormalizeDouble(Bid,Digits),Slip,White);
if(cl)
{
Print("Order: "+(string)OrderTicket()+" has been closed successfully");
break;
}
if(!cl)
{
err=GetLastError();
Print("Error(",err,") Order close error: ",ErrorDescription(err));
// Блокировка работы советника
if(ErrorsAction(err)==2)
{
trade=false;
Print("Stop the Advisor!");
return;
}
// Длительная пауза
if(ErrorsAction(err)==1)
{
Sleep(1000*LongPause);
}
// Небольшая пауза
if(ErrorsAction(err)==0)
{
Sleep(1000*ShortPause);
}
}
}
}
if(OrderType()==1 && (ot==1 || ot==-1))
{
for(int k=1;k<=MaxEntry;k++)
{
if(!IsTesting() && (!IsExpertEnabled() || IsStopped())) break;
while(!IsTradeAllowed()) Sleep(5000);
RefreshRates();
cl=OrderClose(OrderTicket(),OrderLots(),NormalizeDouble(Ask,Digits),Slip,White);
if(cl)
{
Print("Order: "+(string)OrderTicket()+" has been closed successfully");
break;
}
if(!cl)
{
err=GetLastError();
Print("Error(",err,") Order close error: ",ErrorDescription(err));
// Блокировка работы советника
if(ErrorsAction(err)==2)
{
trade=false;
Print("Stop the Advisor!");
return;
}
// Длительная пауза
if(ErrorsAction(err)==1)
{
Sleep(1000*LongPause);
}
// Небольшая пауза
if(ErrorsAction(err)==0)
{
Sleep(1000*ShortPause);
}
}
}
}
}
}
}
}
В функции открытия ордера:
//+------------------------------------------------------------------+
//| Установка ордера |
//+------------------------------------------------------------------+
void PutOrder(int type,double price)
{
int r=0;
color clr=Green;
double sl=0,tp=0;
if(type==1 || type==3 || type==5)
{
clr=Red;
if(StopLoss>0) sl=NormalizeDouble(price+StopLoss*Point,Digits);
if(TakeProfit>0) tp=NormalizeDouble(price-TakeProfit*Point,Digits);
}
if(type==0 || type==2 || type==4)
{
clr=Blue;
if(StopLoss>0) sl=NormalizeDouble(price-StopLoss*Point,Digits);
if(TakeProfit>0) tp=NormalizeDouble(price+TakeProfit*Point,Digits);
}
r=OrderSend(NULL,type,Lots,NormalizeDouble(price,Digits),Slip,sl,tp,"",Magic,TimeCurrent()+Expiration*3600,clr);
return;
}
Добавим ко всему вышеперечисленному только проверку на наличие средств, а остальном все делается также:
if(AccountFreeMarginCheck(Symbol(),type,Lot(type))<=0)
{
Print("No enough money!");
trade=false;
return;
}
Если не хватает средств для открытия позиции, останавливаем работу советника.
//+------------------------------------------------------------------+
//| Установка ордера |
//+------------------------------------------------------------------+
void PutOrderReal(int type,double price)
{
int r=0,err=0;
color clr=Green;
double sl=0,tp=0;
if(type==1 || type==3 || type==5)
{
clr=Red;
if(StopLoss>0) sl=NormalizeDouble(price+StopLoss*Point,Digits);
if(TakeProfit>0) tp=NormalizeDouble(price-TakeProfit*Point,Digits);
}
if(type==0 || type==2 || type==4)
{
clr=Blue;
if(StopLoss>0) sl=NormalizeDouble(price-StopLoss*Point,Digits);
if(TakeProfit>0) tp=NormalizeDouble(price+TakeProfit*Point,Digits);
}
if(AccountFreeMarginCheck(Symbol(),type,Lot(type))<=0)
{
Print("No enough money!");
trade=false;
return;
}
for(int k=1;k<=MaxEntry;k++)
{
if(!IsTesting() && (!IsExpertEnabled() || IsStopped())) break;
while(!IsTradeAllowed()) Sleep(5000);
RefreshRates();
r=OrderSend(NULL,type,Lots,NormalizeDouble(price,Digits),Slip,sl,tp,"",Magic,0,clr);
if(r>0)
{
Print("Order is placed successfully: "+" OOP: ",price," SL: ",sl,+" TP: ",tp);
break;
}
else
{
err=GetLastError();
Print("Error(",err,") Order delete error: ",ErrorDescription(err));
// Блокировка работы советника
if(ErrorsAction(err)==2)
{
trade=false;
Print("Stop the Advisor!");
return;
}
// Длительная пауза
if(ErrorsAction(err)==1)
{
Sleep(1000*LongPause);
}
// Небольшая пауза
if(ErrorsAction(err)==0)
{
Sleep(1000*ShortPause);
}
}
}
return;
}
Проверку на стоплевел будем делать уже при установке ордера.
Модификация одного предварительно выбранного ордера будет написана по такому же алгоритму: проверяем входные параметры, кнопки, обновляем данные и т.д.:
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void ModifyReal(double oop,double sl=0,double tp=0)
{
bool mod;
double op=0,os=0,ot=0;
int err=0;
if(oop<=0) oop=OrderOpenPrice();
if(sl<0 ) sl=OrderStopLoss();
if(tp<0 ) tp=OrderTakeProfit();
oop=NormalizeDouble(oop,Digits);
sl=NormalizeDouble(sl,Digits);
tp=NormalizeDouble(tp,Digits);
op=NormalizeDouble(OrderOpenPrice() , Digits);
os=NormalizeDouble(OrderStopLoss() , Digits);
ot=NormalizeDouble(OrderTakeProfit(), Digits);
if(oop!=op || sl!=os || tp!=ot)
{
for(int i=1; i<=MaxEntry;i++)
{
if(!IsTesting() && (!IsExpertEnabled() || IsStopped())) break;
while(!IsTradeAllowed()) Sleep(5000);
RefreshRates();
mod=OrderModify(OrderTicket(),oop,sl,tp,0,Yellow);
if(mod)
{
Print("Modify Order: "," OOP: ",oop," SL: ",sl," TP: ",tp);
break;
}
if(!mod)
{
err=GetLastError();
Print("Error(",err,") modifying order: ",ErrorDescription(err));
Print("Modify Error: "," OOP: ",OrderOpenPrice()," SL: ",sl," TP: ",tp);
// Блокировка работы советника
if(ErrorsAction(err)==2)
{
trade=false;
Print("Stop the Advisor!");
return;
}
// Длительная пауза
if(ErrorsAction(err)==1)
{
Sleep(1000*300);
}
// Небольшая пауза
if(ErrorsAction(err)==0)
{
Sleep(1000*10);
}
}
}
}
}
И на последок когда самые наиболее часто употребляемые функции у нас готовы, напишем советник на двух МА где будут использованы все эти функции.
При пересечении машек будет установлен отложенник на расстоянии от цены и при смене сигнала позиция будет закрыта, а если ордер не сработал он удалится и установится новый. Сопровождение позиции будет осуществляться простым тралом.
Код советника для тестера у нас будет таким:
//+------------------------------------------------------------------+
//| 2MA.mq4 |
//| Copyright 2016, AM2 |
//| http://www.forexsystems.biz |
//+------------------------------------------------------------------+
#property copyright "Copyright 2016, AM2"
#property link "http://www.forexsystems.biz"
#property version "1.00"
#property strict
//--- Inputs
extern double Lots = 0.1; // лот
extern int StopLoss = 2000; // лось
extern int TakeProfit = 2000; // язь
extern int TrailingStop = 250; // трал
extern int MA1Period = 12; // период МА1
extern int MA2Period = 40; // период МА2
extern int Slip = 30; // реквот
extern int Shift = 1; // на каком баре сигнал индикатора
extern int Delta = 100; // расстояние от цены
extern int Magic = 123; // магик
datetime t=0;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//---
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
Comment("");
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void PutOrder(int type,double price)
{
int r=0;
color clr=Green;
double sl=0,tp=0;
if(type==1 || type==3 || type==5)
{
clr=Red;
if(StopLoss>0) sl=NormalizeDouble(price+StopLoss*Point,Digits);
if(TakeProfit>0) tp=NormalizeDouble(price-TakeProfit*Point,Digits);
}
if(type==0 || type==2 || type==4)
{
clr=Blue;
if(StopLoss>0) sl=NormalizeDouble(price-StopLoss*Point,Digits);
if(TakeProfit>0) tp=NormalizeDouble(price+TakeProfit*Point,Digits);
}
r=OrderSend(NULL,type,Lots,NormalizeDouble(price,Digits),Slip,sl,tp,"",Magic,0,clr);
return;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void OpenOrd()
{
double MA11=iMA(NULL,0,MA1Period,0,0,0,Shift);
double MA12=iMA(NULL,0,MA1Period,0,0,0,Shift+1);
double MA21=iMA(NULL,0,MA2Period,0,0,0,Shift);
double MA22=iMA(NULL,0,MA2Period,0,0,0,Shift+1);
if(MA11<MA21 && MA12>MA22)
{
DelOrder();
CloseAll();
PutOrder(5,Bid-Delta*Point);
}
if(MA11>MA21 && MA12<MA22)
{
DelOrder();
CloseAll();
PutOrder(4,Bid+Delta*Point);
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CloseOrd()
{
double MA11=iMA(NULL,0,MA1Period,0,0,0,Shift);
double MA12=iMA(NULL,0,MA1Period,0,0,0,Shift+1);
double MA21=iMA(NULL,0,MA2Period,0,0,0,Shift);
double MA22=iMA(NULL,0,MA2Period,0,0,0,Shift+1);
if(MA11<MA21 && MA12>MA22)
{
DelOrder();
CloseAll();
}
if(MA11>MA21 && MA12<MA22)
{
DelOrder();
CloseAll();
}
}
//+------------------------------------------------------------------+
//| Удаление отложенных ордеров |
//+------------------------------------------------------------------+
void DelOrder()
{
bool del;
for(int i=OrdersTotal()-1;i>=0;i--)
{
if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
{
if(OrderSymbol()==Symbol() && OrderMagicNumber()==Magic)
{
if(OrderType()>1) del=OrderDelete(OrderTicket());
}
}
}
}
//+------------------------------------------------------------------+
//| Закрытие позиции по типу ордера |
//+------------------------------------------------------------------+
void CloseAll(int ot=-1)
{
bool cl;
for(int i=OrdersTotal()-1;i>=0;i--)
{
if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
{
if(OrderSymbol()==Symbol() && OrderMagicNumber()==Magic)
{
if(OrderType()==0 && (ot==0 || ot==-1))
{
RefreshRates();
cl=OrderClose(OrderTicket(),OrderLots(),NormalizeDouble(Bid,Digits),Slip,White);
}
if(OrderType()==1 && (ot==1 || ot==-1))
{
RefreshRates();
cl=OrderClose(OrderTicket(),OrderLots(),NormalizeDouble(Ask,Digits),Slip,White);
}
}
}
}
}
//+------------------------------------------------------------------+
//| Простой трал |
//+------------------------------------------------------------------+
void Trailing()
{
bool mod;
for(int i=OrdersTotal()-1;i>=0;i--)
{
if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
{
if(OrderSymbol()==Symbol() || OrderMagicNumber()==Magic)
{
if(OrderType()==OP_BUY)
{
if(Bid-OrderOpenPrice()>TrailingStop*Point)
{
if(OrderStopLoss()<Bid-TrailingStop*Point)
{
mod=OrderModify(OrderTicket(),OrderOpenPrice(),Bid-TrailingStop*Point,OrderTakeProfit(),0,Yellow);
return;
}
}
}
if(OrderType()==OP_SELL)
{
if((OrderOpenPrice()-Ask)>TrailingStop*Point)
{
if((OrderStopLoss()>(Ask+TrailingStop*Point)) || (OrderStopLoss()==0))
{
mod=OrderModify(OrderTicket(),OrderOpenPrice(),Ask+TrailingStop*Point,OrderTakeProfit(),0,Yellow);
return;
}
}
}
}
}
}
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
if(t!=Time[0])
{
if(TrailingStop>0) Trailing();
if(OrdersTotal()>0)CloseOrd();
if(OrdersTotal()<1)OpenOrd();
t=Time[0];
}
}
//+------------------------------------------------------------------+
Он будет у нас работать по ценам открытия и после оптимизации показывает неплохую кривую доходности:
Начнем потихоньку делать реальную версию с проверок всего что только можно в онините. Здесь я предпочитаю не возвращать:
return(INIT_FAILED);
return(INIT_PARAMETERS_INCORRECT);
т.к. неопытный пользователь может не понять почему не запускается советник.
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//---
StopLevel=SPREAD*3;
if(StopLoss!=0 && StopLoss<StopLevel) Alert("Incorrect Stop Loss! Should not be less than: ",StopLevel);
if(TakeProfit!=0 && TakeProfit<StopLevel) Alert("Incorrect Take Profit! Should not be less than: ",StopLevel);
if(TrailingStop!=0 && TrailingStop<StopLevel) Alert("Incorrect TrailingStop! Should not be less than: ",StopLevel);
if(!IsTradeAllowed()) Alert("Allow the EA to trade!");
if(!IsLibrariesAllowed()) Alert("Allow DLL import!");
if(!IsExpertEnabled()) Alert("Allow startup advisors!");
if(Lots<=0) Alert("A wrong Lot has to be greater than zero!");
if(Slip<=0) Alert("A wrong Slip has to be greater than zero!");
if(MA1Period<=0) Alert("A wrong MA1Period has to be greater than zero!");
if(MA2Period<=0) Alert("A wrong MA2Period has to be greater than zero!");
if(Delta<=0) Alert("A wrong Delta has to be greater than zero!");
if(Shift<=0) Alert("A wrong MA1Period has to be greater than zero!");
if(Magic<0) Alert("A wrong Shift may not be less than zero!");
if(Lots<MarketInfo(NULL,MODE_MINLOT) || Lots>MarketInfo(NULL,MODE_MAXLOT)) Alert("Incorrect lot!");
//---
return(INIT_SUCCEEDED);
}
Добавим во входные переменные попытки и паузы:
extern int MaxEntry = 10; // количество попыток
extern int LongPause = 300; // длительная пауза
extern int ShortPause = 10; // короткая пауза
Заменим функции для тестера на реальные и добавим функции обработки ошибок. В трале и при выставлении ордера сделаем проверки на стоплевел.
if(Delta<StopLevel) Delta=(int)StopLevel;
if(TrailingStop<StopLevel) TrailingStop=(int)StopLevel;
И вот наконец то мы получили желаемое. Советник около семисот строк, где все по самому минимуму.
Код советника и еще 2 примера от других разработчиков можно скачать по ссылке:
www.opentraders.ru/downloads/1256/
Комментарии (14)
P.S. как-то так: #include <stdlib.mqh> Редактирован: 17 июля 2016, 21:25
27 Oxy Сообщений: 3430 - ..ιllιlι.lι.ιllι.ιlι..
35 AM2 Автор Сообщений: 16247 - Андрей
27 Oxy Сообщений: 3430 - ..ιllιlι.lι.ιllι.ιlι..
for (index = OrdersTotal() — 1; index >= 0; index--)?
Одно и тоже правильно!?
8 Kudryashov Сообщений: 129
В первом случае ордера перебираются с начала во втором с конца.
35 AM2 Автор Сообщений: 16247 - Андрей
8 Kudryashov Сообщений: 129
Задать правильный лот.
35 AM2 Автор Сообщений: 16247 - Андрей
Лот определяется функцией:
8 Kudryashov Сообщений: 129
35 AM2 Автор Сообщений: 16247 - Андрей
8 Kudryashov Сообщений: 129
. И если среди этих 3600 будут такие что выбъют стоп-лос или тейк Профит то картина торговли будет совсем инная. Это мягко говоря. Как Вы собираетесь оградить выставленный ордер от сигналов и ихзменений на рынке в течении часа?
Я Вам скажу что торговля роботов по каждому тику говорит что это сливатор, которых в интернете тысячи.
Вы что не можете выложить ни одного прибыльного робота? Тогда зачем и кому нужны функции которые Вы описываете если они не приносят прибыль?
0 user999 Сообщений: 1
Происходит только обработка сигналов на открытие и закрытие сделок по ценам открытия, но учитываются все изменения внутри бара, которые повлияют на судьбу сделки. Если был всплеск внутри бара против позиции на 150 пунктов, а стоп стоит 50, то сделка будет корректно закрыта по стопу. Никаких проблем с этим нет.
45 Bishop Сообщений: 5802 - АЛЬФАХАМЕЦ-Машковод
Нашел на MQL4 вот такую функцию:
Вставил ее перед OrderSend в следующем виде:
но при компиляции выскакивает ошибка: 'CheckVolumeValue' — wrong parameters count
Однако изменив функцию на:
компиляция прошла успешно.
В связи с вышеперечисленым шаманством… вопрос:
1. Что не так сделал в первый раз когда функция выглядела так ?
2.Насколько критичны внесенные мной изменения?
8 Kudryashov Сообщений: 129
Тут функцию открытия ордеров надыбал…
На сколько она правильная
В советник вставил разницы невижу
8 Kudryashov Сообщений: 129
Зарегистрируйтесь или авторизуйтесь, чтобы оставить комментарий