Оператор досрочного завершения цикла break
Как я уже сказал, оператор break используется для досрочного выхода из ближайшего вложенного внешнего оператора цикла while или for. Также оператор break используется для выхода из оператора switch (я расскажу о нем в следующих выпусках).
Пример использования этого оператора:
int i;
for ( i = 0; i<10; i++ )
{
...
if ( i == 5 ) break;
}
В нашем примере цикл исполнится не 10 раз, а только 6, т.к. в тот момент, когда переменная i будет равна 5, в операторе if-else условие i=5 станет истинным и будет выполнен оператор break, т.к. произойдет досрочный выход из цикла.
В следующем выпуске я расскажу об операторе досрочного завершения текущей итерации - об операторе continue.
Досрочное завершение очередной итерации цикла с помощью оператора continue
В прошлом выпуске я рассказал о том, как можно досрочно выйти из цикла с помощью оператора break. Однако иногда нам нужно не навсегда выйти из цикла, а просто завершить досрочно очередную его итерацию. Для этого используется оператор continue.
Оператор continue прерывает выполнение текущей итерации и передает управление на начало ближайшего внешнего оператора цикла for или while, запуская на исполнение следующую итерацию.
Пример использования оператора continue:
int i;
for ( i = 0; i < 10; i++)
{
...
continue;
Print ("Изучаем оператор continue"); // этот оператор никогда не будет выполнен
}
В следующем выпуске я расскажу об операторе-переключателе switch.
Оператор переключения switch
Ранее я рассказал об условном операторе if-else, с помощью которого можно изменить порядок выполнения операторов в эксперте. Достаточно часто возникают ситуации, когда нам надо заложить в эксперте не два, а больше варианта развития событий. Например, переменная i может принимать целочисленные значения от 1 до 5 и в зависимости от того, какое значение имеет эта переменная, возможны 5 различных последовательностей операторов. Такую задачу легко можно решить с использованием множества вложенных условных операторов if-else.
if (i == 1)
оператор1;
else
if (i == 2)
оператор2;
else
if (i == 3)
оператор3;
else
if (i == 4)
оператор4;
else
if (i == 5)
оператор5;
Такой код будет работать, но его очень тяжело читать и воспринимать. Для большей наглядности в таких случаях лучше использовать оператор переключения switch.
Формат оператора switch:
switch(выражение)
{
case константа1: операторы1
case константа2: операторы2
...
default: операторы_default
}
Принцип работы этого оператора: сначала вычисляется значение "выражения", потом среди констант "константа1", "константа2" и др. ищется константа, которая равна результату "выражения". Если такая константа найдена, то оправление передается на соответствующую группу операторов. После этого последовательно выполняются все операторы этой группы и всех последующих, пока не будет выполнен последний оператор в операторе switсh или не будет осуществлен досрочный выход из оператора switсh с помощью оператора break. Если же не было найдено подходящей константы, то управление передается на группу операторов "операторы_default".
Метка default и группа операторов "операторы_default" могут отсутствовать. В этом случае просто не будет выполняться никаких действий, если ни одна из констант не соответствует результату "выражения". Default не обязательно должен быть последним.
Каждый вариант case может быть помечен целой константой, символьной константой или константным выражением.
Теперь в качестве примере перепишем наш пример с переменной i и 5 вариантами действий с помощью оператора switch:
switch (i)
{
case 1: оператор1; break;
case 2: оператор2; break;
case 3: оператор3; break;
case 4: оператор4; break;
case 5: оператор5; break;
}
По-моему, выглядит гораздо более читаемо.
Я уверен, что Вам уже не терпиться научить Вашего эксперта торговать. Язык MetaQuotes Language 4 позволяет осуществлять ПОЛНЫЙ контроль над торговым счетом - открывать/закрывать позиции, размещать/модифицировать и удалять ордера, получать информацию об открытых позициях и уже закрытых сделках и многое-многое другое.
В следующем выпуске я хочу привести полный список торговых функций, которые можно вызывать в эксперте, а далее подробно остановлюсь на каждой функции.
Учим эксперта торговать
Я уверен, что Вам уже не терпиться научить Вашего эксперта торговать. Язык MetaQuotes Language 4 позволяет осуществлять ПОЛНЫЙ контроль над торговым счетом - открывать/закрывать позиции, размещать/модифицировать и удалять ордера, получать информацию об открытых позициях и уже закрытых сделках и многое-многое другое.
В этом выпуске я хочу привести полный список торговых функций, которые можно вызывать в эксперте, а в следующих выпусках подробно остановлюсь на каждой функции.
Функция | Краткое описание |
HistoryTotal | Количество закрытых позиций и удаленных ордеров |
OrderClose | Закрывает позицию |
OrderCloseBy | Закрывает позицию другой позицией (локированной) |
OrderClosePrice | Цена закрытия выбранного функцией OrderSelect() ордера/позиции |
OrderCloseTime | Дата и время закрытия выбранного функцией OrderSelect() ордера/позиции |
OrderComment | Комментарий выбранного функцией OrderSelect() ордера/позиции |
OrderCommission | Комиссия выбранного функцией OrderSelect() ордера/позиции |
OrderDelete | Удаляет отложенный ордер |
OrderExpiration | Дата истечения выбранного функцией OrderSelect() ордера/позиции |
OrderLots | Количество лотов в выбранном функцией OrderSelect() ордере/позиции |
OrderMagicNumber | "Магическое" число выбранного функцией OrderSelect() ордера/позиции |
OrderModify | Изменяет уровень и дату эксперации отложенного ордера, уровни Stop Loss и Take Profit и "магическое" число открытой позиции или отложенного ордера |
OrderOpenPrice | Цена открытия выбранного функцией OrderSelect() ордера/позиции |
OrderOpenTime | Дата и время размещения/открытия выбранного функцией OrderSelect() ордера/позиции |
OrderPrint | Выводит параметры ордера в журнал |
OrderProfit | Прибыль/убыток выбранного функцией OrderSelect() ордера/позиции |
OrderSelect | Выбрать ордер для получения информации по нему |
OrderSend | Открытие позиции или установка отложенного ордера |
OrderStopLoss | Stop Loss выбранного функцией OrderSelect() ордера/позиции |
OrdersTotal | Количество открытых позиций и отложенных ордеров |
OrderSwap | Величина сториджа выбранного функцией OrderSelect() ордера/позиции |
OrderSymbol | Аббревиатура инструмента выбранного функцией OrderSelect() ордера/позиции |
OrderTakeProfit | Take Profit выбранного функцией OrderSelect() ордера/позиции |
OrderTicket | Тикет выбранного функцией OrderSelect() ордера/позиции |
OrderType | Тип выбранного функцией OrderSelect() ордера/позиции |
В следующих выпусках я рассмотрю эти функции более подробно.
Выбор ордера или позиции с помощью OrderSelect()
В прошлом выпуске я привел полный перечень торговых функций, которые можно использовать в эксперте. Как Вы уже, наверное, успели заметить, подавляющее большинство этих функций позволяет получить какую-то информацию об ордере или позиции, которые были предварительно выбраны с помощью функции OrderSelect().
Формат функции OrderSelect():
bool OrderSelect ( int index, int select, int pool=MODE_TRADES )
Как мы видим, функция возвращает значение логического типа: true - когда ордер или позиция были успешно выбраны, false - в случае какой-то ошибки. Код этой ошибки можно получить впоследствии с помощью функции GetLastError().
Ордер/позицию можно выбрать двумя способами:
1. по номеру тикера;
2. по порядковому номеру ордера/позиции в списке.
Если Вы знаете тикер ордера или позиции, то в качестве параметра select надо передать значение SELECT_BY_TICKET, а в качестве параметра index - номер тикера ордера или позиции. Третий параметр в этом случае не используется и его можно опустить.
Пример выбора по тикеру:
//---- выбираем ордер/позицию с тикером 77777
if ( OrderSelect (77777, SELECT_BY_TICKET) == true)
Print("Ордер #77777 выбран успешно");
else
Print("OrderSelect() вернул ошибку - ",GetLastError());
Если Вы не знаете тикера, то существует другой способ выбрать ордер или позицию. Для этого Вам надо выбрать ордер или позицию из списка открытых позиций или неудаленных отложенных ордеров (значение параметра pool равно MODE_TRADES) или из списка закрытых позиций или удаленных ордеров (параметр pool равен MODE_HISTORY). В обоих случаях параметр select должен быть равен SELECT_BY_POS. В параметре index Вы должны указать порядковый номер этой позиции или ордера в списке открытых позиций или неудаленных отложенных ордеров (pool равен MODE_TRADES) или в списке закрытых позиций и удаленных отложенных ордеров (pool равен MODE_HISTORY).
Этот способ очень полезен, когда Вам нужно "пробежаться", например, по всем открытым позициям:
int pos;
int total = OrdersTotal();
for ( pos = 0; pos<total; pos++ )
{
if (OrderSelect(pos, SELECT_BY_POS, MODE_TRADES) == true)
{
Print("Выбран ордер номер ", pos, " в списке открытых позиций");
// делаем что-то с этой позицией
}
else
Print("Ошибка ", GetLastError(), " при выборе ордера номер ", pos);
}
В этом примере для нас новой является функция OrdersTotal(). Эта функция выводит количество открытых позиций и неудаленных отложенных ордеров. Ее, а также функцию HistoryTotal(), я рассмотрю в следующих выпусках.
HistoryTotal(): количество закрытых позиций и удаленных ордеров
В выпуске про OrderSelect() - функцию выбора ордера или позиции - я рассказал, что можно также выбрать закрытую позицию или удаленный отложенный ордер, указав в качестве параметра select значение SELECT_BY_POS, а в качестве pool - MODE_HISTORY. В качестве первого параметра (index) функции OrderSelect() в этом случае указывается номер позиции/ордера в этом списке.
Зачастую, чтобы найти нужную нам позицию, приходится "пробежаться" по всему списку. Для этого нам нужно знать общее количество позиций и ордеров в списке закрытых позиций и удаленных отложенных ордеров. В этом нам поможет функция HistoryTotal().
Формат функции HistoryTotal():
int HistoryTotal ()
Эта функция возвращает количество закрытых позиций или удаленных отложенных ордеров, которые загруженны в клиентском терминале MetaTrader 4 в соответствии с текущими настройками вкладки "История счета".
Пример использования HistoryTotal():
int pos;
int total = HistoryTotal();
for ( pos = 0; pos<total; pos++ )
{
if (OrderSelect(pos, SELECT_BY_POS, MODE_HISTORY) == true)
{
Print("Выбран ордер номер ", pos, " в списке закрытых позиций");
// делаем что-то с этой позицией
}
else
Print("Ошибка ", GetLastError(), " при выборе ордера номер ", pos);
}
В следующих выпусках я расскажу, какую информацию мы можем получить после выделения позиции или ордера с помощью функции OrderSelect().
OrderClosePrice() - цена закрытия выделенного ордера или позиции
После того, как мы выделим ордер или позицию с помощью функции OrderSelect(), мы можем получить об ордере саму различную информацию. В этом выпуске я расскажу о функции OrderClosePrice().
Формат функции OrderClosePrice():
double OrderClosePrice()
Функция OrderClosePrice() возвращает цену закрытия ордера или позиции, выделенной с помощью функции OrderSelect().
Рассмотрим пример использования функции OrderClosePrice(). Предположим, что мы знаем, что позиция закрылась по ордеру и нам надо определить по какому: по Stop Loss или Take Profit:
//---- выбираем ордер/позицию с тикером 77777
if ( OrderSelect (77777, SELECT_BY_TICKET) == true)
{
// позиция выбрана успешно
if ( OrderClosePrice() == OrderStopLoss() )
{
// позиция закрылась по Stop Loss
// ...
}
else
{
// позиция закрылась по Take Profit
// ...
}
}
else
Print("OrderSelect() вернул ошибку - ",GetLastError());
К сожалению, наш пример будет работать только в тех случаях, когда Stop Loss сработал без проскальзывания. В следующих выпусках мы усложним пример и сделаем так, чтобы даже если ордера были сработаны с проскальзыванием, наш кусочек кода правильно это определял.
В этом примере Вам незнакома функция OrderStopLoss(). Эта функция возвращает значение Stop Loss выделенного ордера или позиции. Подробно эту функцию мы рассмотрим в следующем выпуске.
OrderStopLoss() - цена закрытия выделенного ордера или позиции
В прошлом выпуске, рассказывая о функции OrderClosePrice(), я рассмотрел пример, как определить по какому ордеру (Stop Loss или Take Profit) была закрыта позиция, если точно известно, что она была закрыта по ордеру.
В этом примере была использована функция OrderStopLoss(). Из названия абсолютно понятно ее предназначение, но лучше все-таки остановиться на ней поподробнее.
Для того, чтобы изучение функции OrderStopLoss() стало не просто скучным теоретическим описанием, попробуем слегка изменить прошлый пример, чтобы получить максимум практической пользы.
Прошлый наш пример работал только в тех случаях, когда Stop Loss был сработан без проскальзывания. Изменим немного наш код:
//---- выбираем ордер/позицию с тикером 77777
if ( OrderSelect (77777, SELECT_BY_TICKET) == true)
{
// позиция выбрана успешно
if ( ((OrderClosePrice() <= OrderStopLoss()) && (OrderType() == OP_BUY)) ||
((OrderClosePrice() >= OrderStopLoss()) && (OrderType() == OP_SELL)) )
{
// позиция закрылась по Stop Loss
// ...
}
else
{
// позиция закрылась по Take Profit
// ...
}
}
else
Print("OrderSelect() вернул ошибку - ",GetLastError());
Этот пример базируется на том, что:
- Если позиция была на покупку (условие OrderType() == OP_BUY истинно), то Stop Loss сработает или по цене ордера, или хуже, т.е. ниже: (OrderClosePrice() <= OrderStopLoss()).
- Если позиция была на продажу (условие OrderType() == OP_SELL истинно), то Stop Loss сработает или по цене ордера, или хуже, т.е. выше: (OrderClosePrice() >= OrderStopLoss()).
Таким образом, в любом из этих случаех мы можем быть уверены, что позиция закрылась по Stop Loss ордеру.
В нашем примере мы опять столкнулись с незнакомой функцией - OrderType(). Забегая вперед, скажу, что эта функция возвращает тип ордера, но более подробно я хотел бы рассмотреть ее в следующем выпуске.
Получение типа ордера с помощью OrderType()
В прошлых выпусках мы научились получать информацию о выделенном с помощью функции OrderSelect() ордере или позиции:
- Stop Loss (функция OrderStopLoss);
- Цену закрытия (функция OrderClosePrice).
В этом выпуске я расскажу о функции OrderType().
int OrderType()
Функция OrderType() возвращает значение, которое определяет тип операции ордера, который предварительно выбран с помощью OrderSelect():
- OP_BUY - позиция на покупку,
- OP_SELL - позиция на продажу,
- OP_BUYLIMIT - отложенный ордер Buy Limit,
- OP_BUYSTOP - отложенный ордер Buy Stop,
- OP_SELLLIMIT - отложенный ордер Sell Limit,
- OP_SELLSTOP - отложенный ордер Sell Stop.
В предыдущем выпуске я поместил пример, которые определял, как была закрыта позиция - по Stop Loss ордеру или по Take Profit. Вместе с тем в этом примере есть небольшая ошибка: если выделенный ордер является отложенным ордером, то этот кусочек кода будет ошибочно считать, что позиция закрылась по Take Profit. Изменим наш пример, чтобы исключить эту ошибку:
//---- выбираем ордер/позицию с тикером 77777
if ( OrderSelect (77777, SELECT_BY_TICKET) == true)
{
if ((OrderType() == OP_BUY) || (OrderType() == OP_SELL))
{
// позиция выбрана успешно
if ( ((OrderClosePrice() <= OrderStopLoss()) && (OrderType() == OP_BUY)) ||
((OrderClosePrice() >= OrderStopLoss()) && (OrderType() == OP_SELL)) )
{
// позиция закрылась по Stop Loss
// ...
}
else
{
// позиция закрылась по Take Profit
// ...
}
}
else
Print("Ошибка: это не закрытая позиция, а отложенный ордер");
}
else
Print("OrderSelect() вернул ошибку - ",GetLastError());
Путем добавления дополнительной проверки, нам удастся отделить закрытые позиции от отложенных ордеров:
if ((OrderType() == OP_BUY) || (OrderType() == OP_SELL))
Наш исправленный пример все равно имеет несколько недостатков. Один из них - неправильная работа, если была выделена открытая позиция, а не закрытая. Как устранить этот недостаток я расскажу в следующем выпуске, который будет посвящен функции OrderCloseTime().
OrderCloseTime() - время закрытия позиции
В прошлом выпуске я слегка модифицировал наш пример определения по какому ордеру была закрыта позиция. Теперь если по ошибке мы выделили с помощью функции OrderSelect() отложенный ордер, а не позицию, эта ситуация выявляется.
Однако возможен случай, когда мы по ошибке выделили открытую позицию. Выявить этот случай нам поможет функция OrderCloseTime().
datetime OrderCloseTime()
Функцию можно вызвать после того, как ордер или позиция были предварительно выбраны с помощью функции OrderSelect().
Возвращает дату и время закрытия позиции или ордера:
- Если позиция открыта, то возвращает 0 (ноль).
- Если позиция закрыта, то возвращает дату и время закрытия позиции.
- Если отложенный ордер удален, то возвращает дату и время удаления ордера.
- Если отложенный ордер еще не удален, то возвращает 0 (ноль).
Исходя из этих правил нам надо проверить время закрытия выделенной позиции. Если оно равно нулю, то это открытая позиция и нам надо сообщить об ошибке:
//---- выбираем ордер/позицию с тикером 77777
if ( OrderSelect (77777, SELECT_BY_TICKET) == true)
{
// это позиция, а не отложеный ордер?
if ((OrderType() == OP_BUY) || (OrderType() == OP_SELL))
{
// это закрытая позиция, а не открытая?
if ( OrderCloseTime() != 0 )
{
if ( ((OrderClosePrice() <= OrderStopLoss()) && (OrderType() == OP_BUY)) ||
((OrderClosePrice() >= OrderStopLoss()) && (OrderType() == OP_SELL)) )
{
// позиция закрылась по Stop Loss
// ...
}
else
{
// позиция закрылась по Take Profit
// ...
}
}
else
Print("Ошибка: это не закрытая позиция, а открытая");
}
else
Print("Ошибка: это не закрытая позиция, а отложенный ордер");
}
else
Print("OrderSelect() вернул ошибку - ",GetLastError());
То, что это не может быть отложенный ордер, мы уже проверили (см. прошлый выпуск).
Теперь наш пример по определению типа ордера, по которому была закрыта позиция, стал содержать на одну ошибку меньше, но по-прежнему остается небезгрешным. Мы почему-то с первых строчек кода безусловно верим в тот факт, что позиция закрыта именно по Stop Loss или Take Profit ордера. А если нет?
Об этом мы поговорим в следующем выпуске, когда будем рассматривать функцию OrderTakeProfit().
OrderTakeProfit() - уровень Take Profit ордера
В прошлых выпусках мы уже достаточно сильно продвинулись в вопросе, как определить, была ли позиция закрыта по Take Profit ордеру или по Stop Loss. Параллельно мы изучили следующие торговые функции советника:
- OrderSelect(),
- OrdersTotal(),
- HistoryTotal(),
- OrderClosePrice(),
- OrderStopLoss(),
- OrderType(),
- OrderCloseTime().
В этом выпуске мы изучим функцию OrderTakeProfit() и доработаем наш пример. Мы почему-то с первых строчек кода безусловно верим в тот факт, что позиция была закрыта именно по Stop Loss или Take Profit ордера. А если нет? Это легко проверить.
- Если для позиции на покупку цена закрытия находится не ниже уровня Take Profit, то позиция закрыта по Take Profit.
- Если для позиции на продажу цена закрытия находится не выше уровня Take Profit, то позиция закрыта по Take Profit.
Мы знаем, что уровень Stop Loss ордера выделенной позиции или ордера можно определить с помощью функции OrderStopLoss(). По аналогии уровень Take Profit определяется с помощью функции OrderTakeProfit():
double OrderTakeProfit()
Ордер должен быть предварительно выбран с помощью функции OrderSelect().
Изменим наш пример, чтобы убедиться, что позиция закрыта по ордеру, а не с рынка:
//---- выбираем ордер/позицию с тикером 77777
if ( OrderSelect (77777, SELECT_BY_TICKET) == true)
{
// это позиция, а не отложеный ордер?
if ((OrderType() == OP_BUY) || (OrderType() == OP_SELL))
{
// это закрытая позиция, а не открытая?
if ( OrderCloseTime() != 0 )
{
if ( ((OrderClosePrice() <= OrderStopLoss()) && (OrderType() == OP_BUY)) ||
((OrderClosePrice() >= OrderStopLoss()) && (OrderType() == OP_SELL)) )
{
// позиция закрылась по Stop Loss
// ...
}
else
{
if ( ((OrderClosePrice() >= OrderTakeProfit()) && (OrderType() == OP_BUY)) ||
((OrderClosePrice() <= OrderTakeProfit()) && (OrderType() == OP_SELL)) )
{
// позиция закрылась по Take Profit
// ...
}
else
Print("Ошибка: позиция закрыта не по ордеру");
}
}
else
Print("Ошибка: это не закрытая позиция, а открытая");
}
else
Print("Ошибка: это не закрытая позиция, а отложенный ордер");
}
else
Print("OrderSelect() вернул ошибку - ",GetLastError());
В следующем выпуске я продолжу изучение торговых функций языка MetaQuotes Language 4 и расскажу о функции OrderSymbol().
OrderSymbol() - инструмент выделенного ордера
Очень часто перед трейдером стоит задача перебрать все открытые позиции или отложенные ордера и что-то сделать с позициями или ордерами, которые выставлены по инструменту, к которому прикреплен советник. Предположим, что нас интересуют только отложенные ордера.
Используя функцию OrderSymbol(), мы можем получить информация о выделенном с помощью функции OrderSelect() ордере или позиции.
string OrderSymbol()
Напишем кусочек кода, который просматривает все наши неудаленные отложенные ордера и производит какие-то действия с ордерами, которые выставлены по инструменту, к которому прикреплен советник.
int pos;
for (pos=0; pos<OrdersTotal(); pos++)
{
// выделим ордер
if (OrderSelect(pos, SELECT_BY_POS, MODE_TRADES) == true)
{
// ордер выбран; проверим является ли этот ордер отложенным
if (OrderType()>=OP_BUYLIMIT)
{
// ордер оказался отложенным; проверим инструмент
if (OrderSymbol()==Symbol())
{
// делаем что-то с ордером
// ...
}
}
}
else
Print("Ошибка ", GetLastError(), " при выборе ордера номер ", pos);
В этом коде Вам могут быть непонятны два момента.
Во-первых, я как-то странно на первый взгляд провожу определение типа ордера: if (OrderType()>=OP_BUYLIMIT). На самом деле условие OrderType()>=OP_BUYLIMIT будет истинно в тех случаях, когда выбран ордер, и ложно в тех случаях, когда выбрана позиция. Дело в том, что константы, определяющие тип ордера, имеют следующие числовые значения:
Константа | Значение | Описание |
OP_BUY | Позиция на покупку | |
OP_SELL | Продажа | |
OP_BUYLIMIT | Отложенный ордер BUY LIMIT | |
OP_SELLLIMIT | Отложенный ордер SELL LIMIT | |
OP_BUYSTOP | Отложенный ордер BUY STOP | |
OP_SELLSTOP | Отложенный ордер SELL STOP |
Как мы видим, во всех случаях, когда выделен отложенный ордер, значение функции OrderType() будет больше или равно OP_BUYLIMIT (т.е. больше или равно 2).
Второй непонятный момент в коде - функция Symbol(). Эта функция возвращает текстовую строку с именем финансового инструмента, к которому прикреплен советник:
string Symbol()
Все остальное Вы уже на данный момент знаете:
- целочисленные переменные (int),
- цикл for,
- функцию выделения ордера OrderSelect(),
- функцию получения типа выделенного ордера OrderType(),
- функцию печати информации в журнал экспертов Print().
В следующем выпуске я продолжу рассмотрение торговых функций.
OrderComment() - комментарий выделенного ордера
В прошлых выпусках мы решали задачу определения того, была ли закрыта позиция по Stop Loss или Take Profit ордеру. Существует еще один способ узнать это. При этом данный способ будет более простым, чем рассмотренные ранее.
В этом нам поможет функция OrderComment().
string OrderComment()
После того как ордер или позиция выбраны функцией OrderSelect() вызов функции OrderComment() вернет комментарии этого ордера/позиции в виде строки.
Очень часто сервер пишет в комментарий ордера или позиции полезные вещи:
- [sl] - если сработал Stop Loss;
- [tp] - если сработал Take Profit;
- cancelled - если отложенный ордер был отменен клиентом;
- deleted [no money] - если отложенный ордер должен был сработать, но был удален сервером из-за недостатка свободных средств на счете;
- partial close - если позиция была закрыта частично;
- close hedge by #тикер - если локированная позиция была закрыта полностью другой локированной позицией;
- [число%] - позиция была закрыта по Stop Out (т.е. сервер автоматически закрыл позицию, когда equity стало меньше 20% необходимой маржи);
- deleted [good for day] - удаленный отложенный ордер по CFD, который имел статус Day Order;
- expiration [YYYY.MM.DD HH:MM] - отложенный ордер, который был удален сервером при достижении даты эксперации YYYY.MM.DD HH:MM;
- split from #тикер - при закрытии одной позицией другой с разными объемами появляется в рынке новая позиция с таким комментарием; #тикер - номер тикера позиции с бОльшим объемом.
Может быть этот список неполон, но в данный момент нас это не должно волновать. Нас интересуют те позиции и ордера, в комментарии которых встречается подстрока [sl] (позиция закрыта по Stop Loss ордеру) или подстрока [tp] (позиция закрыта по Take Profit ордеру):
//---- выбираем ордер/позицию с тикером 77777
if ( OrderSelect (77777, SELECT_BY_TICKET) == true)
{
// это позиция, а не отложеный ордер?
if ((OrderType() == OP_BUY) || (OrderType() == OP_SELL))
{
// это закрытая позиция, а не открытая?
if ( OrderCloseTime() != 0 )
{
if ( StringFind(OrderComment(), "[sl]") != -1 )
{
// позиция закрылась по Stop Loss
// ...
}
else
{
if ( StringFind(OrderComment(), "[tp]") != -1 )
{
// позиция закрылась по Take Profit
// ...
}
else
Print("Ошибка: позиция закрыта не по ордеру");
}
}
else
Print("Ошибка: это не закрытая позиция, а открытая");
}
else
Print("Ошибка: это не закрытая позиция, а отложенный ордер");
}
else
Print("OrderSelect() вернул ошибку - ",GetLastError());
В этом примере есть неизвестная пока нам функция - StringFind():
int StringFind ( string text, string matched_text, int start=0 )
Эта функция ищет в строке text подстроку matched_text начиная с позиции start (если третий параметр не указан, то поиск идет с нулевой позиции, т.е. с первого элемента). Если подстрока не найдена, то функция возвращает -1; если найдена - номер позиции в строке, с которой начинается искомая подстрока.
В следующем выпуске я продолжу рассмотрение торговых функций.
OrderSwap() - начисленный сторидж по выделенному ордеру
В прошлых выпусках мы рассмотрели очень нужные с практической точки зрения трейдеру функции, с помощью которых можно получить информацию о выделенном с помощью функции OrderSelect() ордере или позиции.
В этом выпуске я расскажу о функции OrderSwap(). Честно говоря, я совершенно не вижу практического применения этой функции в экспертах, но раз она присутствует, то лучше о ней рассказать.
double OrderSwap()
Функция OrderSwap() возвращает начисленный или списанный сторидж (т.е. плату за перенос позиции на следующий день) по ордеру или позиции, выделенных с помощью функции OrderSelect().
В следующем выпуске я расскажу о функции OrderCommission().
OrderCommission() - комиссия выделенного функцией OrderSelect() ордера
Вчерашний и сегодняшний выпуски посвящены не очень нужным с практической точки зрения торговым функциям: OrderSwap() и OrderCommission().
К сожалению, при всей моей достаточно буйной фантазии я так и не смог придумать практического применения этих функций. Но раз эти функции присутствуют, то лучше о них расcказать. Вдруг вам они все-таки пригодятся.
double OrderCommission()
Функция OrderCommission() возвращает удержанную комиссию по ордеру, выделенному функцией OrderSelect().
В следующем выпуске я расскажу о более полезных торговых функциях, которым очень легко найти практическое применение и которые вследствие этого очень часто применяются при написании экспертов.
OrderOpenPrice() - получение информации о цене открытии позиции или цене отложенного ордера
В этом выпуске я рассмотрю функцию OrderOpenPrice(). В качестве практического примера применения этой функции рассмотрим установку и управление трейлинг стопом.
Напомню, что 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);
}
}
}
Прежде всего нас интересует новая функция OrderOpenPrice():
double OrderOpenPrice()
Эта функция возвращает цену открытия для выбранного функцией OrderSelect() ордера или позиции.
В этом коде Вам могут быть непонятны еще несколько функций:
- OrderTicket() - возвращает тикер выделенного функцией OrderSelect() ордера или позиции;
- Bid - Bid последней котировки по инструменту, к которому прикреплен эксперт;
- Ask - Ask последней котировки по инструменту, к которому прикреплен советник;
- Point - размер пункта текущего инструмента в валюте котировки (для EURUSD это 0.0001, для USDJPY- 0.01 и т.д.).
В следующем выпуске я расскажу о функции OrderTicket().
OrderTicket() - тикер выделенного ордера
В прошлом выпуске я рассказал о реализации алгоритма трейлинг стопа на языке MetaQuotes Language 4.
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);
}
}
}
В этом примере нами была использована функция OrderTicket():
int OrderTicket()
Эта функция возвращает тикер выделенного с помощью функции OrderSelect() ордера или позиции.
В следующем выпуске я продолжу рассмотрение торговых функций.
OrderProfit() - прибыль выделенного ордера
Я еще не начал рассмотрение торговых функций, с помощью которых можно открывать/закрывать позиции и управлять ордерами. Я уверен, что Вам уже не терпится научить Вашего эксперта торговать, и я очень скоро Вас этому научу. Однако перед этим я хотел бы рассмотреть несколько оставшихся торговых функций, с помощью которых можно получить информацию об ордере, выделенном с помощью функции OrderSelect().
Сегодня я расскажу о функции OrderProfit().
double OrderProfit()
Функция OrderProfit() возвращает прибыль для ордера, выделенного с помощью функции OrderSelect().
Предположим, что мы хотим подсчитать прибыль, которую мы получили по закрытым позициям.
int profit = 0;
int pos;
for ( pos = 0; pos<HistoryTotal(); pos++ )
{
// выделим позицию
if (OrderSelect(pos, SELECT_BY_POS, MODE_HISTORY) == true)
{
// это не отложенный ордер?
if ( OrderType() <= OP_SELL) profit += OrderProfit();
}
else
Print("Ошибка ", GetLastError(), " при выделении ордера ", OrderTicket());
}
Print("Суммарный профит по закрытым позициям = ", profit);
В следующем выпуске я продолжу рассмотрение торговых функций и расскажу о функции OrderOpenTime().
OrderOpenTime() - время открытия ордера или позиции, выделенного функцией OrderSelect()
В прошлом выпуске мы посчитали прибыль по закрытым позициям. Теперь усложним задачу: сосчитаем прибыль только по закрытым позициям, которые были открыты сегодня.
С помощью функции OrderOpenTime() мы можем получить дату и время открытия ордера или позиции, выделенного предварительно с помощью функции OrderSelect().
datetime OrderOpenTime()
- В случае отложенного ордера функция OrderOpenTime() возвращает дату и время выставления ордера.
- В случае открытой или закрытой позиции функция возвращает дату и время открытия позиции.
Для того, чтобы определить, что позиция открыта сегодня, нам нужно знать значение типа datetime для сегодняшней даты в 00:00:00 часов.
В этом нам помогут четыре новых функции:
- 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<HistoryTotal(); pos++ )
{
// выделим позицию
if (OrderSelect(pos, SELECT_BY_POS, MODE_HISTORY) == true)
{
// это не отложенный ордер?
if ( OrderType() <= OP_SELL)
{
// ордер был открыт сегодня?
if (OrderOpenTime()>=day_start) profit += OrderProfit();
}
}
else
Print("Ошибка ", GetLastError(), " при выделении ордера ", OrderTicket());
}
Print("Суммарный профит по закрытым позициям = ", profit);
В следующем выпуске я продолжу рассмотрение торговых функций и расскажу о функции OrderLots().
OrderLots() - количество лотов в выделенном ордере или позиции
В последующих функциях мы рассмотрим торговые функции, с помощью которых можно открывать/закрывать позиции, размещать/модифицировать и удалять ордера:
- OrderClose()
- OrderCloseBy()
- OrderDelete()
- OrderModify()
- OrderSend()
Очень часто необходимо указать количество лотов открытой позиции или отложенного ордера. Самой простой вариант получить это значение - это выделить позицию или ордер с помощью функции OrderSelect(), а потом вызвать функцию OrderLots().
double OrderLots()
Функция возвращает количество лотов в выделенном ордере или позиции.
Как я уже сказал, основное применение функции - передать количество лотов в качестве параметра в функции OrderClose() и OrderModify().
Забегая вперед, расскажу о формате функции OrderClose():
bool OrderClose(int ticket, double lots, double price, int slippage, color Color=CLR_NONE)
Где:
- ticket - тикер ордера или позиции;
- lots - количество лотов для закрытия позиции;
- price - цена закрытия;
- slippage - з<