Торговые советники (Expert Advisors)
- Читать Закрыть 31
функция OrderProfit.
Функция OrderProfit() возвращает прибыль для ордера, выделенного с помощью функции OrderSelect().
Предположим, что мы хотим подсчитать прибыль, которую мы получили по закрытым позициям.
int profit = 0; int pos; for ( pos = 0; pos<= OP_SELL) profit += OrderProfit(); } else Print("Ошибка ", GetLastError(), " при выделении ордера ", OrderTicket()); } Print("Суммарный профит по закрытым позициям = ", profit);
- Читать Закрыть 32
функция OrderOpenTime.
С помощью функции OrderOpenTime() мы можем получить дату и время открытия ордера или позиции, выделенного предварительно с помощью функции OrderSelect().
datetime OrderOpenTime()
- В случае отложенного ордера функция OrderOpenTime() возвращает дату и время выставления ордера.
- В случае открытой или закрытой позиции функция возвращает дату и время открытия позиции.
Дляи:
- datetime CurTime() — время прихода последней котировки в виде количества секунд, прошедших после 00:00 1 января 1970 года;
- int TimeHour(datetime time) — возвращает порядковый номер часа для времени time;
- int TimeMinute(datetime time) — возвращает порядковый номер минуты для времени time;
- int TimeSeconds(datetime time) — возвращает количество секунд с начала минуты для времени time.
Например, для 02:16:05 функции TimeHour, TimeMinute и TimeSeconds вернут соответственно 2, 16 и 5.
Мы помним, что значение типа datetime представляет собой количество секунд, прошедшее с 00:00 1 января 1970 года. Также мы помним, что в часе 60×60 секунд, а в минуте 60 секунд. Поэтому, зная текущее время (мы можем получить его с помощью CutTime), мы можем получить время текущего дня на 00:00:00 часов:
int c_time = CurTime(); datetime day_start; day_start=c_time-TimeHour(c_time)*60*60-TimeMinute(c_time)*60-TimeSeconds(c_time);
А полный код, который подсчитывает прибыль по всем закрытым позициям, которые открыты сегодня, будет таким:
//---- вычислим начало дня - переменная day_start int c_time = CurTime(); datetime day_start; day_start=c_time-TimeHour(c_time)*60*60-TimeMinute(c_time)*60-TimeSeconds(c_time); //---- подсчитаем прибыль int profit = 0; int pos; for ( pos = 0; pos<= OP_SELL) { // ордер был открыт сегодня? if (OrderOpenTime()>=day_start) profit += OrderProfit(); } } else Print("Ошибка ", GetLastError(), " при выделении ордера ", OrderTicket()); } Print("Суммарный профит по закрытым позициям = ", profit);
- Читать Закрыть 33
функция OrderMagicNumber.
Оч
- Читать Закрыть 34
функция OrderSend.
Формат функции:
int OrderSend(string symbol, int cmd, double volume, double price, int slippage, double stoploss, double takeprofit, string comment=NULL, int magic=0, datetime expiration=0, color arrow_color=CLR_NONE)
Ф
- Читать Закрыть 35
функция OrderModify.
Функция OrderModify().
bool OrderModify(int ticket, double price, double stoploss, double takeprofit, datetime expiration, color arrow_color=CLR_NONE)
Эта функция позволяет изменять параметры отложенных ордеров и открытых позиций. В случае успеха она возвращает true, а в случае неудачи — false. Код ошибки можно будет получить с помощью функции GetLastError().
Параметры функции:
- ticket — тикер отложенного ордера или открытой позиции;
- price — новый уровень отложенного ордера (для открытых позиций не может быть изменен);
- stoploss — новый уровень Stop Loss;
- takeprofit — новый уровень Take Profit;
- expiration — новые дата и время истечения отложенного ордера (если к этой дате и времени отложенный ордер не сработает, то он будет удален — см. выпуск «OrderExpiration() — дата истечения отложенного ордера»);
- arrow_color — цвет открывающей стрелки на графике. Если параметр отсутствует или его значение равно CLR_NONE, то открывающая стрелка не отображается на графике.
В случае неправильных параметров функция возвращает следующие коды ошибок:
- 1 (ERR_NO_RESULT) — если ни один из параметров не был изменен;
- 147 (ERR_TRADE_EXPIRATION_DENIED) — если в настройках торгового сервера запрещено выставлять дату эксперации ордера. В этом случае параметр expiration всегда должен быть равен нулю).
В качестве практического примера применения этой функции рассмотрим установку и управление трейлинг стопом.
Напомню, что Trailing Stop (трейлинг стоп) — это алгоритм управления уровнем Stop Loss ордера. После выставления трейлинг-стопа (например, на Х пипсов) происходит следующее:
- MetaTrader не предпринимает никаких действий до того момента, пока по открытой позиции не образуется прибыль в Х пипсов. После этого MetaTrader выставляет Stop Loss ордер на расстоянии Х пипсов от текущей цены (в данном случае — на уровне безубыточности).
- После выполнения первого шага MetaTrader посылает команду на изменение уровня Stop Loss ордера на расстояние Х пипсов от текущей котировки каждый раз, когда расстояние между ней и старым уровнем ордера превысит Х пипсов. В результате этого Stop Loss ордер «подтягивается» к текущей цене.
Реализуем этот принцип на языке MetaQuotes Language 4. Будем полагать, что открытая позиция уже выбрана и мы точно знаем, что эта позиция открыта по инструменту, к которому прикреплен эксперт. Также предположим, что значение трейлинг стопа в пипсах содержится в переменной TrailingStop.
int err; if (OrderType() == OP_BUY) { // позиция на покупку if ((Bid-OrderOpenPrice())>=(TrailingStop*Point)) { // выставляем Stop Loss if (OrderModify(OrderTicket(), OrderOpenPrice(), Bid-TrailingStop*Point, OrderTakeProfit(), 0)) Print("#", OrderTicket(),": trailing stop ", Bid-TrailingStop*Point); else { err = GetLastError(); Print("#", OrderTicket(),": trailing stop error ", err); } } } else { // позиция на продажу if ((OrderOpenPrice()-Ask)>=(TrailingStop*Point)) { // выставляем Stop Loss if (OrderModify(OrderTicket(), OrderOpenPrice(), Ask+TrailingStop*Point, OrderTakeProfit(), 0)) Print("#", OrderTicket(),": trailing stop ", Ask+TrailingStop*Point); else { err = GetLastError(); Print("#", OrderTicket(),": trailing stop error ", err); } } }
- Читать Закрыть 36
функция OrderDelete.
Мы уже знаем, как можно выставить отложенный ордер. Для этого надо использовать функцию OrderSend(). Также мы умеем изменять параметры отложенных ордеров с помощью функции OrderModify().
В этом выпуске расскажем о том, как можно удалить отложенный ордер. Это можно сделать с помощью функции OrderDelete().
bool OrderDelete(int ticket)
Эта функция удаляет отложенный ордер с тикером ticket. Функция возвращает true в случае успешного удаления и false — в случае возникновения ошибки. Код ошибки можно получить, вызвав функцию GetLastError().
Применение функции OrderDelete() рассмотрим на следующем примере:
Предположим, что наш эксперт по какой-то логике (не будем здесь вдаваться в подробности) выставляет по одному инструменту сразу два отложенных ордера — Buy Limit и Sell Limit. Наша задача — если один из ордеров сработал, то удалить оставшийся отложенный ордер.
Предположим, что по данному инструменту работает только наш эксперт.Пусть в момент выставления каждого отложенного ордера было задано «магическое» число, одинаковое для каждого отложенного ордера. Предположим, что это «магическое» число хранится в переменной MyMagicNumber.
// просмотрим все открытые позиции и выставленные ордера int pos; for(pos=0; pos<=OP_SELL)) { // найти второй отложенный ордер int i; for(i=0; iOP_SELL)) { // ордер найден - удалим его if (OrderDelete(OrderTicket())) { Print("Ордер удален"); } else { Print("Ошибка ", GetLastError(), " при удалении ордера"); } } } } // выйти из цикла break; } } }
- Читать Закрыть 37
функция OrderClose.
Пришло время рассказать о том, как закрыть открытую позицию с помощью функции OrderClose().
bool OrderClose(int ticket, double lots, double price, int slippage, color Color=CLR_NONE)
Параметры функции:
- ticket — тикер открытой позиции;
- lots — объем в лотах;
- price — цена закрытия позиции;
- slippage — максимально допустимое отклонение между price и ценой сервера, при котором позиция будет закрыта;
- arrow_color — цвет закрывающей стрелки на графике. Если параметр отсутствует или его значение равно CLR_NONE, то стрелка не отображается на графике.
Функция OrderClose() вернет true, если позиция закрыта успешно. Если же произошла какая-то ошибка, то функция вернет false и код ошибки можно будет получить с помощью функции GetLastError().
Практических примеров применения этой функции можно привести бесчисленное количество, т.к. в большинстве экспертов существует потребность закрывать позиции не только по Stop Loss или Take Profit ордеру, но и по текущей цене.
Мы же в качестве примера применения функции OrderClose() рассмотрим эксперт, который закрывает все открытые позиции и удаляет все отложенные ордера в пятницу после 22:00 (по времени торговой платформы).
//+------------------------------------------------------------------+ //| Close everything on Friday.mq4 | //| Copyright © 2006, Andrey Vedikhin | //| http://www.vedikhin.ru | //+------------------------------------------------------------------+ #property copyright "Copyright © 2006, Andrey Vedikhin" #property link "http://www.vedikhin.ru"
//---- input parameters extern int MyHour=22; extern int MyMinute=00;
// 5 - Friday #define MyDay 5
datetime LastTradeTime;
//+------------------------------------------------------------------+ //| expert initialization function | //+------------------------------------------------------------------+ int init() { //---- // установим время последней торговой операции вчерашним днем LastTradeTime = CurTime()-24*60*60; //---- return(0); } //+------------------------------------------------------------------+ //| expert deinitialization function | //+------------------------------------------------------------------+ int deinit() { //----
//---- return(0); } //+------------------------------------------------------------------+ //| expert start function | //+------------------------------------------------------------------+ int start() { //---- // проверим, не закрывали ли мы все уже сегодня // если да - выходим if (TimeDayOfYear(CurTime())==TimeDayOfYear(LastTradeTime)) return(0);
// если не пятница - выходим if (DayOfWeek()!=MyDay) return(0);
// проверим, не наступило ли время закрывать позиции if (((TimeHour(CurTime())==MyHour)&&(TimeMinute(CurTime())>=MyMinute)) ||(TimeHour(CurTime())>MyHour)) { // закроем все позиции и удалим ордера while (OrdersTotal()>0) { // выделим первую позицию или ордер в списке if (!OrderSelect(0, SELECT_BY_POS)) break; // в случае неудачи выйти из цикла
// если отложенный ордер, то удалить if (OrderType()>OP_SELL) { if (!OrderDelete(OrderTicket())) { Print("Ошибка ", GetLastError()," при удалении отложенного ордера ", OrderTicket()); break; } } // если открытая позиция, то закрыть else { double price; if (OrderType()==OP_SELL) price = MarketInfo(OrderSymbol(), MODE_ASK); else price = MarketInfo(OrderSymbol(), MODE_BID);
if (!OrderClose(OrderTicket(), OrderLots(), price, 3)) { Print("Ошибка ", GetLastError()," при закрытии позиции ", OrderTicket()); break; } }
// пауза 10 секунд Sleep(10000); } if (OrdersTotal()==0) LastTradeTime = CurTime(); }
//---- return(0); } //+------------------------------------------------------------------+
Разоберем каждую строчку кода этого советника.
Прежде всего этот эксперт имеет несколько параметров:
extern int MyHour=22; extern int MyMinute=00;
Эти параметры имеют следующих смысл:
MyHour и MyMinute — час и минута, когда эксперт закрывает открытые позиции и удаляет отложенные ордера.
Напомню, что о том, как описать в коде параметры эксперта, я рассказывал в выпуске «Внешние переменные».
Мы объявили глобальную переменную LastTradeTime:
datetime LastTradeTime;
С ее помощью мы сможем избежать «сработки» эксперта на каждом тике после 22:00, если в этот день мы уже закрыли все открытые позиции и удалили отложенные ордера.
При инициализации эксперта в функции init() мы присваиваем этой переменной значение вчерашнего дня:
int init() { //---- // установим время последней торговой операции вчерашним днем LastTradeTime = CurTime()-24*60*60; //---- return(0); }
Напомню, что функция CurTime() возвращает текущее время в формате datetime.
На каждом тике вызывается функция start(), в которой мы сначала проверяем, не закрывали ли мы уже сегодня открытые позиции и не удаляли ли мы уже отложенные ордера:
if (TimeDayOfYear(CurTime())==TimeDayOfYear(LastTradeTime)) return(0);
Здесь используется функция TimeDayOfYear():
int TimeDayOfYear( datetime date )
Эта функция возвращает порядковый номер дня (с начала года): 1 — 1 января, , 365 или 366 — 31 декабря.
Если же порядковый номер дня последней торговой операции — TimeDayOfYear(LastTradeTime) — равен порядковому дню текущего времени — TimeDayOfYear(CurTime()), — значит мы уже сегодня ордера удаляли и позиции закрывали, поэтому выходим из эксперта: return(0).
Проверим, не пятница ли сегодня:
if (DayOfWeek()!=MyDay) return(0);
Функция DayOfWeek() возвращает порядковый номер дня недели (воскресенье — 0, 1 — понедельник, , 6 — суббота) последнего известного времени сервера.
Теперь проверим, не наступило ли время закрывать позиции:
if (((TimeHour(CurTime())==MyHour)&&(TimeMinute(CurTime())>=MyMinute)) ||(TimeHour(CurTime())>MyHour)) { ... }
В этом кусочке кода я использовал две новые функции:
- int TimeHour(datetime time) — возвращает час для времени time: 0..23;
- int TimeMinute(datetime time) — возвращает минуту для времени time: 0..59.
Далее с помощью функции OrderSelect() мы начинаем выделять первую позицию/ордер в списке, пытаться ее закрыть или удалить ордер, а потом с помощью цикла while этот процесс повторяется вновь и вновь, пока есть открытые позиции или отложенные ордера. Также цикл прерывается в случае ошибки.
Обязательно между торговыми операциями мы выдерживаем паузу в 10 секунд:
Sleep(10000);
Функция Sleep(int milliseconds) делает паузу в работе эксперта на milliseconds милисекунд (1 секунда = 1000 милисекунд).
После того, как все позиции закрыты и все отложенные ордера удалены, мы задаем время последней «сработки» советника текущим временем:
if (OrdersTotal()==0) LastTradeTime = CurTime();
В коде эксперта Вы видите еще одну незнакомую нам функцию — MarketInfo():
double MarketInfo(string symbol, int type)
С помощью этой функции можно получить различную информацию об инструменте symbol. Вид получаемой информации зависит от значения параметра type:
Константа Значение Описание MODE_LOW 1 Минимальная цена за день MODE_HIGH 2 Максимальная цена за день MODE_TIME 5 Время поступления последней котировки MODE_BID 9 Последний Bid MODE_ASK 10 Последний Ask MODE_POINT 11 Размер пункта в валюте котировки MODE_DIGITS 12 Количество цифр после десятичного точки в цене инструмента MODE_SPREAD 13 Спрэд в пунктах MODE_STOPLEVEL 14 Минимально допустимый уровень стоп-лосса/тейк-профита в пунктах MODE_LOTSIZE 15 Размер контракта в базовой валюте инструмента MODE_TICKVALUE 16 Размер минимального изменения цены инструмента в валюте котировки MODE_TICKSIZE 17 Минимальный шаг изменения цены инструмента в пунктах MODE_SWAPLONG 18 Сторидж для длинных позиций MODE_SWAPSHORT 19 Сторидж для коротких позиций MODE_STARTING 20 Дата начала торгов по инструменту (для фьючерсов) MODE_EXPIRATION 21 Дата окончания торгов по инструменту (для фьючерсов) MODE_TRADEALLOWED 22 Флаг разрешения торгов по данному инструменту MODE_MINLOT 23 Минимальный размер лота MODE_LOTSTEP 24 Шаг изменения размера лота MODE_MAXLOT 25 Максимальный размер лота - Читать Закрыть 38
функция OrderCloseBy.
Давайте перепишем нашего эксперта с учетом этого совета. В этом нам поможет функция OrderCloseBy():
//+------------------------------------------------------------------+ //| Close everything on Friday.mq4 | //| Copyright © 2006, Andrey Vedikhin | //| http://www.vedikhin.ru | //+------------------------------------------------------------------+ #property copyright "Copyright © 2006, Andrey Vedikhin" #property link "http://www.vedikhin.ru"
//---- input parameters extern int MyHour=22; extern int MyMinute=00;
// 5 - Friday #define MyDay 5
datetime LastTradeTime;
//+------------------------------------------------------------------+ //| expert initialization function | //+------------------------------------------------------------------+ int init() { //---- // установим время последней торговой операции вчерашним днем LastTradeTime = CurTime()-24*60*60; //---- return(0); } //+------------------------------------------------------------------+ //| expert deinitialization function | //+------------------------------------------------------------------+ int deinit() { //----
//---- return(0); } //+------------------------------------------------------------------+ //| expert start function | //+------------------------------------------------------------------+ int start() { //---- // проверим, не закрывали ли мы все уже сегодня // если да - выходим if (TimeDayOfYear(CurTime())==TimeDayOfYear(LastTradeTime)) return(0);
// если не пятница - выходим if (DayOfWeek()!=MyDay) return(0);
// проверим, не наступило ли время закрывать позиции if (((TimeHour(CurTime())==MyHour)&&(TimeMinute(CurTime())>=MyMinute)) ||(TimeHour(CurTime())>MyHour)) { // закроем все позиции и удалим ордера while (OrdersTotal()>0) { // выделим первую позицию или ордер в списке if (!OrderSelect(0, SELECT_BY_POS)) // в случае неудачи выйти из цикла break;
// если отложенный ордер, то удалить if (OrderType()>OP_SELL) { if (!OrderDelete(OrderTicket())) { Print("Ошибка ", GetLastError()," при удалении отложенного ордера ", OrderTicket()); break; } } // если открытая позиция, то закрыть else { // попробуем найти локированную позицию по этому же инструменту int ticket0; ticket0 = OrderTicket();
string symbol0; symbol0 = OrderSymbol();
int ordertype0; ordertype0 = OrderType();
int i; for (i = 1; i
// заново выделим нулевую позицию if (!OrderSelect(ticket0, SELECT_BY_TICKET)) // в случае неудачи выйти из цикла break;
double price; if (OrderType()==OP_SELL) price = MarketInfo(OrderSymbol(), MODE_ASK); else price = MarketInfo(OrderSymbol(), MODE_BID);
if (!OrderClose(OrderTicket(), OrderLots(), price, 3)) { Print("Ошибка ", GetLastError()," при закрытии позиции ", OrderTicket()); break; } }
// пауза 10 секунд Sleep(10000); } if (OrdersTotal()==0) LastTradeTime = CurTime(); }
//---- return(0); } //+------------------------------------------------------------------+
Вначале я расскажем о самой функции, потом разберем каждую новую строчку нашего эксперта.
bool OrderCloseBy(int ticket, int opposite, color сolor=CLR_NONE)
Функция OrderCloseBy() закрывает одну позицию другой позицией по тому же самому инструменту. В случае успеха она возвращает true, а в случае ошибки — false. Код ошибки можно в дальнейшем узнать с помощью функции GetLastError().
Параметры функции OrderCloseBy():
- ticket — тикер первой позиции;
- opposite — тикер второй позиции;
- сolor — цвет закрывающей стрелки на графике. Если параметр отсутствует или его значение равно CLR_NONE, то закрывающая стрелка не отображается на графике.
Разберем каждую новую строчку нашего эксперта:
// попробуем найти локированную позицию по этому же инструменту int ticket0; ticket0 = OrderTicket();
string symbol0; symbol0 = OrderSymbol();
int ordertype0; ordertype0 = OrderType();
int i; for (i = 1; i
// заново выделим нулевую позицию if (!OrderSelect(ticket0, SELECT_BY_TICKET)) // в случае неудачи выйти из цикла break;
Вначале запомним номер тикера, инструмент и тип операции выделенной позиции (первой в списке открытых позиций и отложенных ордеров) в переменных ticket0, symbol0 и ordertype0 соответственно:
int ticket0; ticket0 = OrderTicket();
string symbol0; symbol0 = OrderSymbol();
int ordertype0; ordertype0 = OrderType();
После этого в цикле переберем все оставшиеся позиции в поиске позиции, чтобы найти позицию по тому же инструменту, но открытую в другом направлении (OrderType()==((ordertype0+1)%2)):
int i; for (i = 1; i
Если такую позицию мы нашли, то закроем ее и нашу первоначально выделенную позицию с помощью функции OrderCloseBy() и в случае успеха присвоим переменной i значение -2.
Далее мы проверяем были ли закрыты локированные позиции. Если «да», то делаем паузу и переходим к следующей итерации цикла while, т.е. смотрим следующую позицию/ордер — кандидатов на закрытие/удаление:
if (i==-2) { Sleep(10000); continue; }
Если же локированные позиции были не найдены, то вновь выделяем первую позицию в списке открытых позиций и отложенных ордеров:
if (!OrderSelect(ticket0, SELECT_BY_TICKET)) // в случае неудачи выйти из цикла break;
Далее пытаемся закрыть эту позицию с помощью функции OrderClose().
- Читать Закрыть 39
Обработка ошибок.
Как я уже неоднократно упоминал в предыдущих выпусках, если какая-то функция вернула ошибку, то код этой ошибки можно получить с помощью функции GetLastError():
int GetLastError()
После вызова этой функции код последней ошибки обнуляется, поэтому если в промежутке между двумя вызовами функции GetLastError() не произошло новой ошибки, то второй раз функция вернет 0.
Функция GetLastError() возвращает числовой код ошибки. Если же Вы хотите получить словесное описание ошибки, то используйте функцию ErrorDescription(), описанную в файле stdlib.mqh:
string ErrorDescription(int error_code) { string error_string; //---- switch(error_code) { //---- codes returned from trade server case 0: case 1: error_string="no error"; break; case 2: error_string="common error"; break; ... } //---- return(error_string); }
Коды ошибок, возвращаемые сервером:
Константа Значение Описание ERR_NO_ERROR 0 Нет ошибки ERR_NO_RESULT 1 Нет ошибки, но результат неизвестен ERR_COMMON_ERROR 2 Общая ошибка ERR_INVALID_TRADE_PARAMETERS 3 Неправильные параметры ERR_SERVER_BUSY 4 Торговый сервер занят ERR_OLD_VERSION 5 Старая версия клиентского терминала ERR_NO_CONNECTION 6 Нет связи с торговым сервером ERR_NOT_ENOUGH_RIGHTS 7 Недостаточно прав ERR_TOO_FREQUENT_REQUESTS 8 Слишком частые запросы ERR_MALFUNCTIONAL_TRADE 9 Недопустимая операция нарушающая функционирование сервера ERR_ACCOUNT_DISABLED 64 Счет заблокирован ERR_INVALID_ACCOUNT 65 Неправильный номер счета ERR_TRADE_TIMEOUT 128 Истек срок ожидания совершения сделки ERR_INVALID_PRICE 129 Неправильная цена ERR_INVALID_STOPS 130 Неправильные стопы ERR_INVALID_TRADE_VOLUME 131 Неправильный объем ERR_MARKET_CLOSED 132 Рынок закрыт ERR_TRADE_DISABLED 133 Торговля запрещена ERR_NOT_ENOUGH_MONEY 134 Недостаточно денег для совершения операции ERR_PRICE_CHANGED 135 Цена изменилась ERR_OFF_QUOTES 136 Нет цен ERR_BROKER_BUSY 137 Брокер занят ERR_REQUOTE 138 Новые цены ERR_ORDER_LOCKED 139 Ордер заблокирован и уже обрабатывается ERR_LONG_POSITIONS_ONLY_ALLOWED 140 Разрешена только покупка ERR_TOO_MANY_REQUESTS 141 Слишком много запросов ERR_TRADE_MODIFY_DENIED 145 Модификация запрещена, так как ордер слишком близок к рынку ERR_TRADE_CONTEXT_BUSY 146 Подсистема торговли занята ERR_TRADE_EXPIRATION_DENIED 147 Использование даты истечения ордера запрещено брокером ERR_TRADE_TOO_MANY_ORDERS 148 Количество открытых и отложенных ордеров достигло предела, установленного брокером
Коды ошибок выполнения, генерируемые клиентским терминалом при выполнении советника:Константа Значение Описание ERR_NO_MQLERROR 4000 Нет ошибки ERR_WRONG_FUNCTION_POINTER 4001 Неправильный указатель функции ERR_ARRAY_INDEX_OUT_OF_RANGE 4002 Индекс массива — вне диапазона ERR_NO_MEMORY_FOR_FUNCTION_CALL_STACK 4003 Нет памяти для стека функций ERR_RECURSIVE_STACK_OVERFLOW 4004 Переполнение стека после рекурсивного вызова ERR_NOT_ENOUGH_STACK_FOR_PARAMETER 4005 На стеке нет памяти для передачи параметров ERR_NO_MEMORY_FOR_PARAMETER_STRING 4006 Нет памяти для строкового параметра ERR_NO_MEMORY_FOR_TEMP_STRING 4007 Нет памяти для временной строки ERR_NOT_INITIALIZED_STRING 4008 Неинициализированная строка ERR_NOT_INITIALIZED_ARRAYSTRING 4009 Неинициализированная строка в массиве ERR_NO_MEMORY_FOR_ARRAYSTRING 4010 Нет памяти для строкового массива ERR_TOO_LONG_STRING 4011 Слишком длинная строка ERR_REMAINDER_FROM_ZERO_DIVIDE 4012 Остаток от деления на ноль ERR_ZERO_DIVIDE 4013 Деление на ноль ERR_UNKNOWN_COMMAND 4014 Неизвестная команда ERR_WRONG_JUMP 4015 Неправильный переход ERR_NOT_INITIALIZED_ARRAY 4016 Неинициализированный массив ERR_DLL_CALLS_NOT_ALLOWED 4017 Вызовы DLL не разрешены ERR_CANNOT_LOAD_LIBRARY 4018 Невозможно загрузить библиотеку ERR_CANNOT_CALL_FUNCTION 4019 Невозможно вызвать функцию ERR_EXTERNAL_EXPERT_CALLS_NOT_ALLOWED 4020 Вызовы внешних библиотечных функций не разрешены ERR_NOT_ENOUGH_MEMORY_FOR_RETURNED_STRING 4021 Недостаточно памяти для строки, возвращаемой из функции ERR_SYSTEM_BUSY 4022 Система занята ERR_INVALID_FUNCTION_PARAMETERS_COUNT 4050 Неправильное количество параметров функции ERR_INVALID_FUNCTION_PARAMETER_VALUE 4051 Недопустимое значение параметра функции ERR_STRING_FUNCTION_INTERNAL_ERROR 4052 Внутренняя ошибка строковой функции ERR_SOME_ARRAY_ERROR 4053 Ошибка массива ERR_INCORRECT_SERIES_ARRAY_USING 4054 Неправильное использование массива-таймсерии ERR_CUSTOM_INDICATOR_ERROR 4055 Ошибка пользовательского индикатора ERR_INCOMPATIBLE_ARRAYS 4056 Массивы несовместимы ERR_GLOBAL_VARIABLES_PROCESSING_ERROR 4057 Ошибка обработки глобальныех переменных ERR_GLOBAL_VARIABLE_NOT_FOUND 4058 Глобальная переменная не обнаружена ERR_FUNCTION_NOT_ALLOWED_IN_TESTING_MODE 4059 Функция не разрешена в тестовом режиме ERR_FUNCTION_NOT_CONFIRMED 4060 Функция не подтверждена ERR_SEND_MAIL_ERROR 4061 Ошибка отправки почты ERR_STRING_PARAMETER_EXPECTED 4062 Ожидается параметр типа string ERR_INTEGER_PARAMETER_EXPECTED 4063 Ожидается параметр типа integer ERR_DOUBLE_PARAMETER_EXPECTED 4064 Ожидается параметр типа double ERR_ARRAY_AS_PARAMETER_EXPECTED 4065 В качестве параметра ожидается массив ERR_HISTORY_WILL_UPDATED 4066 Запрошенные исторические данные в состоянии обновления ERR_TRADE_ERROR 4067 Ошибка при выполнении торговой операции ERR_END_OF_FILE 4099 Конец файла ERR_SOME_FILE_ERROR 4100 Ошибка при работе с файлом ERR_WRONG_FILE_NAME 4101 Неправильное имя файла ERR_TOO_MANY_OPENED_FILES 4102 Слишком много открытых файлов ERR_CANNOT_OPEN_FILE 4103 Невозможно открыть файл ERR_INCOMPATIBLE_ACCESS_TO_FILE 4104 Несовместимый режим доступа к файлу ERR_NO_ORDER_SELECTED 4105 Ни один ордер не выбран ERR_UNKNOWN_SYMBOL 4106 Неизвестный символ ERR_INVALID_PRICE_PARAM 4107 Неправильный параметр цены для торговой функции ERR_INVALID_TICKET 4108 Неверный номер тикета ERR_TRADE_NOT_ALLOWED 4109 Торговля не разрешена ERR_LONGS_NOT_ALLOWED 4110 Длинные позиции не разрешены ERR_SHORTS_NOT_ALLOWED 4111 Короткие позиции не разрешены ERR_OBJECT_ALREADY_EXISTS 4200 Объект уже существует ERR_UNKNOWN_OBJECT_PROPERTY 4201 Запрошено неизвестное свойство объекта ERR_OBJECT_DOES_NOT_EXIST 4202 Объект не существует ERR_UNKNOWN_OBJECT_TYPE 4203 Неизвестный тип объекта ERR_NO_OBJECT_NAME 4204 Нет имени объекта ERR_OBJECT_COORDINATES_ERROR 4205 Ошибка координат объекта ERR_NO_SPECIFIED_SUBWINDOW 4206 Не найдено указанное подокно ERR_SOME_OBJECT_ERROR 4207 Ошибка при работе с объектом - Читать Закрыть 40
Секреты правильной торговли.
Расскажем о трех функциях: IsExpertEnabled(), IsTradeContextBusy() и IsTradeAllowed().
Функция IsExpertEnabled()
bool IsExpertEnabled()
Функция IsExpertEnabled() возвращает true, если экспертам разрешено совершать сделки и управлять ордерами. Дело в том, что на уровне настроек клиентского терминала можно запретить ВСЕМ экспертам торговать. Это можно сделать, например, с помощью команды главного меню: Сервис -> Настройки. В появившемся окне выбираем вкладку «Советники», в которой ставим или убираем галочку напротив «Включить советники ».
Более простой способ отключать/включать советников — кнопка.
Если же на уровне настроек терминала работа экспертов запрещена, то функция IsExpertEnabled() вернет false.
Функция IsTradeContextBusy()
В каждый момент времени только один эксперт может торговать. Если в этот момент второй эксперт попытается совершить торговую операцию, то торговая функция вернет ошибку ERR_TRADE_CONTEXT_BUSY (146).
bool IsTradeContextBusy()
Функция IsTradeContextBusy() позволит Вам заблаговременно выявить ситуацию, когда другой эксперт уже пытается торговать (она вернет в этом случае значение true), и избежать нерезультативного вызова торговой функции (которая все равно завершиться с ошибкой). Обычно в таких случаях лучше подождать немного до того момента, когда другой эксперт закончит торговать (тогда функция IsTradeContextBusy() вернет значение false) и только после этого вызывать Вашу торговую функцию.
Функция IsTradeAllowed()
Функция IsTradeAllowed() объединяет все обе предыдущие функции. Она вернет true только в том случае, если торговля экспертов разрешена и торговый поток свободен для торговли, т.е. никакой другой эксперт не совершает в данный момент торговых операций.
bool IsTradeAllowed()
Как уже говорилось в каждый момент времени только один эксперт может торговать. Если в этот момент второй эксперт попытается совершить торговую операцию, то торговая функция вернет ошибку ERR_TRADE_CONTEXT_BUSY (146).
Что же делать, если у Вас торгует одновременно несколько экспертов?
Напишем функцию, которая возвращает:
- 0, если торговый поток свободен;
- 1, если работа эксперта была остановлена (см. причины ниже);
- 2, если торговля экспертов запрещена на уровне настроек клиентского терминала.
Если в момент обращения к функции торговый поток был занят, то функция ждет, пока он освободится. После этого она обновляет данные о текущих котировках с помощью функции RefreshRates() и возвращает 0.
Напомню возможные причины остановки эксперта:
- завершение работы MetaTrader 4,
- закрытие графика,
- удаление эксперта с графика,
- изменение инструмента или периода графика,
- удачная перекомпиляции программы в MetaEditor,
- изменение параметров эксперта,
- переключение на другой счет.
Исходный код функции, которая решает поставленную задачу:
//+-------------------------------------------------------------------+ //| Функция WaitUntilTradingIsAllowed возвращает:| //| 0 - если торговый поток свободен | //| 1 - если работа эксперта была остановлена | //| 2 - если торговля экспертов запрещена на | //| уровне настроекклиентского терминала | //+-------------------------------------------------------------------+ int WaitUntilTradingIsAllowed() { // Если торговля разрешена, то вернем 0 и выйдем if (IsTradeAllowed()) return(0);
// В цикле проверяем, как изменилась ситуация while (!IsStopped()) { // Если торговля экспертов запрещена на уровне настроек // клиентского терминала, то выйдем и вернем 2 if (!IsExpertEnabled()) return(2);
// Если торговый поток освободился, то обновим данные // о текущих курсах и вернем 0 if (!IsTradeContextBusy()) { RefreshRates(); return(0); }
// Если дошли до момента, то ситуация не изменилась // Поэтому делаем паузу в 0.1 секунду Sleep(100); }
// Т.к. вышли из цикла, то работа эксперта была остановлена // Вернем 1 return(1); }
Функция IsStopped().
bool IsStopped()
Функция возвращает true, если эксперт был «остановлен», и false — в противном случае.
Эксперт получает команду на завершение в следующих случаях:
- при завершении работы клиентского терминала,
- при закрытии графика, к которому прикреплен эксперт,
- при удалении эксперта с графика,
- при изменении инструмента или периода графика,
- после перекомпиляции эксперта в MetaEditor,
- после изменения параметров советника,
- при переключении на другой счет.
Чтобы не пытаться совершить сделку по старым котировкам и не получить сообщение об ошибке, мы обновляем информацию о текущих котировках с помощью функции RefreshRates().
bool RefreshRates()
Функция возвращает true, если информация была обновлена, и false, если данные не изменились и в обновлении нет нужды. Если данные были обновлены, то вызов функции RefreshRates() также обновит время последней котировки, которое возвращается функцией CurTime().
Считается хорошим тоном вызывать функцию RefreshRates() перед вызовом торговой функции, если перед этим эксперт что-то очень долго или пересчитывал. Или же если эксперт ждал, пока другой эксперт закончит торговать и торговый поток освободиться.
Поскольку, наверняка, в своей торговле Вы будете использовать сразу несколько экспертов или одного и того же эксперта, но на разных временных промежутках или инструментах, то Ваши эксперты будут периодически ожидать освобождения торгового потока и Вы будете использовать функцию RefreshRates() практически всегда.