home

Формат функции:

 

 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)


 

Функция OrderSend() предназначена для размещения отложенного ордера или открытия позиции. Функция вовзращает номер тикера открытой позиции или размещенного отложенного ордера. В случае неудачи функция OrderSend() возвращает число -1.

При этом:

  • symbol — инструмент, по которому будет открыта позиция или размещен отложенный ордер;
  • cmd — тип ордера (см. таблицу 1);
  • volume — объем в лотах;
  • price — цена открытия позиции или уровень отложенного ордера;
  • slippage — максимально допустимое отклонение между price и ценой сервера, при которым позиция будет открыта (для установки отложенных ордеров величина параметра slippage значения не имеет);
  • stoploss — уровень Stop Loss;
  • takeprofit — уровень Take Profit;
  • comment — комментарий к ордеру или позиции (впоследствии это поле может быть изменено сервером — см. выпуск «OrderComment() — комментарий выделенного ордера»);
  • magic — магическое число ордера (может быть впоследствии получено функцией OrderMagicNumber());
  • expiration — дата и время истечения отложенного ордера (если к этой дате и времени отложенный ордер не сработает, то он будет удален — см. выпуск «OrderExpiration() — дата истечения отложенного ордера»);
  • arrow_color — цвет открывающей стрелки на графике. Если параметр отсутствует или его значение равно CLR_NONE, то открывающая стрелка не отображается на графике.

В параметре cmd мы передаем тип приказа:

Таблица 1. Возможные значения параметра cmd функции OrderSend()

Константа Значение Описание
OP_BUY 0 Открыть позицию на покупку
OP_SELL 1 Открыть позицию на продажу
OP_BUYLIMIT 2 Разместить отложенный ордер BUY LIMIT
OP_SELLLIMIT 3 Разместить отложенный ордер SELL LIMIT
OP_BUYSTOP 4 Разместить отложенный ордер BUY STOP
OP_SELLSTOP 5 Разместить отложенный ордер SELL STOP

Таким образом, для того, чтобы открыть позицию на продажу в качестве параметра cmd надо указать OP_SELL. Для открытия позиции на покупку — OP_BUY. Для установки отложенного ордера надо использовать значения OP_BUYLIMIT, OP_SELLLIMIT, OP_BUYSTOP или OP_SELLSTOP в зависимости от типа размещаемого отложенного ордера.

При открытии позиции в качестве параметра price надо использовать текущий Bid (если cmd равен OP_SELL) или текущий Ask (если cmd равен OP_BUY):

  • функция Bid возвращает текущий Bid по инструменту, к которому «прикреплен» эксперт;
  • функция Ask возвращает текущий Ask по инструменту, к которому «прикреплен» эксперт;
  • функция MarketInfo(string symbol, int type) c параметром type, равным MODE_BID или MODE_ASK, возвращает текущий Bid или Ask по инструменту, который передан ей в качестве параметра symbol.

 


Важно:
Ни в коем случае нельзя использовать цену, которую Вы рассчитали по какой-то формуле, или цену, которую Вы не привели (нормализовали) к тому количеству знаков после запятой, сколько должно быть у данного инструмента.

 

Для того, чтобы «нормализовать» цену, надо использовать функцию NormalizeDouble():

 

 double NormalizeDouble ( double value, int digits )


 

Эта функция округляет вещественное число value с точностью до digits знаков после запятой. Число цифр после десятичной точки должно быть в диапазоне 0 .. 8.

 

В случае использования «неправильной» цены в параметре price будут выданы следующие коды ошибок:

  • ERR_INVALID_PRICE (129) — если цена не была «нормализована» или такой цены вообще не было в потоке;
  • ERR_REQUOTE (138) — если цена сильно устарела (независимо от значения параметра slippage);

 

Если же цена устарела, но еще присутствует в потоке, то будет совершена сделка по текущей цене, если текущая цена находится в диапазоне price +/- slippage.

Когда Вы открываете позициию (выставляете отложенный ордер), то ордера Stop Loss и Take Profit должны находиться по отношению к текущей цене (цене отложенного ордера) не ближе, чем на расстоянии определенного количества пунктов. Например, если Вы имеет счет в Компании Альпари, то Вы не можете выставлять Stop Loss и Take Profit ордера на FOREX ближе одного спрэда к текущей цене для открытой позиции или к цене отложенного ордера.

Если Вы попытаетесь разместить Stop Loss или Take Profit ближе, чем это дозволено, то функция OrderSend() вернет ошибку 130 (ERR_INVALID_STOPS).

Если Вы не знаете этого минимально допустимого значения, то Вы всегда можете его получить с помощью функции MarketInfo(). Функция MarketInfo(string symbol, int type) c параметром type, равным MODE_STOPLEVEL, возвращает это значение по инструменту, который передан ей в качестве параметра symbol.

Инструмент графика, к которому прикреплен эксперт, можно получить с помощью функции Symbol():

 

 string Symbol()


 

Если функция OrderSend() возратила ошибку 147 (ERR_TRADE_EXPIRATION_DENIED), это означает, что на торговом сервере запрещены отложенные ордера с установленной датой эксперации. В этом случае следует в дальнейшем использовать функцию OrderSend() с параметром expiration, равным нулю. Компания Альпари разрешает своим клиентам устанавливать любую дату и время, когда неисполненный отложенный ордер будет удален автоматически.

Если функция OrderSend() вернула ошибку 148 (ERR_TRADE_TOO_MANY_ORDERS), это означает, что на торговом сервере установлено ограничение на максимально возможное число открытых позиций и выставленных отложенных ордеров по одному счету. Пытаясь открыть еще одну позицию или выставить еще один отложенный ордер, Вы превышаете допустимый лимит, поэтому Вам в этом будет отказано.

Пример использования функции OrderSend() можно найти в нашем первом эксперте:

 

 MyOrderTicket = OrderSend(Symbol(), OP_SELL, LotsNumber, Bid, 3, 0, 0, 
NULL, 0, 0, CLR_NONE);
if (MyOrderTicket<0)
{
err = GetLastError();
Print("Ошибка при открытии позиции: ", err);
MyOrderTicket = 0;
}


 

Пример советника

Задача.

Советник должен в определенное время (параметры MyHour и MyMinute) на заранее заданном расстоянии от текущей цены (параметр MyPendingLevel) выставлять два ордера — Sell Stop и Buy Stop. При этом должны выставляться ордера Stop Loss на расстоянии MySL пипсов от цены ордера и Take Profit на расстоянии MyTP пипсов.

Решение.

 

 //+------------------------------------------------------------------+
//| 2nd Expert.mq4 |
//| Andrey Vedikhin |
//| http://www.vedikhin.ru |
//+------------------------------------------------------------------+
#property copyright "Andrey Vedikhin"
#property link "http://www.vedikhin.ru"

//---- input parameters
extern int MyPendingLevel=15;
extern int MySL=30;
extern int MyTP=15;
extern int MyHour=19;
extern int MyMinute=40;
extern int MyLots=1.0;

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 ((TimeHour(CurTime())==MyHour)&&(TimeMinute(CurTime())==MyMinute))
{
// выставим Buy Stop
if (OrderSend(Symbol(), OP_BUYSTOP, MyLots,
Ask+Point*MyPendingLevel, 0, Ask+Point*MyPendingLevel-Point*MySL,
Ask+Point*MyPendingLevel+Point*MyTP)!=-1)
LastTradeTime = CurTime();
// ордер не выставлен
else
return(0);

// обязательная пауза в 10 секунд
Sleep(10000);

// обновим текущий Bid и Ask
RefreshRates();


// выставим Sell Stop
if (OrderSend(Symbol(), OP_SELLSTOP, MyLots,
Bid-Point*MyPendingLevel, 0, Bid-Point*MyPendingLevel+Point*MySL,
Bid-Point*MyPendingLevel-Point*MyTP)!=-1)
LastTradeTime = CurTime();
// ордер не выставлен
else
return(0);
}
//----
return(0);
}
//+------------------------------------------------------------------+


 

Прежде всего этот эксперт имеет несколько параметров:

 

 extern int MyPendingLevel=15;
extern int MySL=30;
extern int MyTP=15;
extern int MyHour=19;
extern int MyMinute=40;
extern int MyLots=1.0;


 

Эти параметры имеют следующих смысл:

  • MyPendingLevel — расстояние в пипсах от текущей цены, на котором выставляется отложенный ордер;
  • MySL и MyTP — Stop Loss и Tale Profit в пипсах от цены отложенного ордера;
  • MyHour и MyMinute — час и минута, когда выставляет отложенный ордер;
  • MyLots — размер лота отложенного ордера.

Напомню, что о том, как описать в коде параметры эксперта, я рассказывал в выпуске «Внешние переменные».

В реальности может возникнуть ситуация, когда на баре MyHour:MyMinute может быть несколько тиков, поэтому чтобы избежать выставления отложенных ордеров на каждом тике, мы завели глобальную переменную LastTradeTime:

 

 datetime LastTradeTime; // время последней торговой операции


 

Этой переменной мы присваиваем в качестве начального значения вчерашнюю дату при инициализации эксперта — в функции init():

 

 //+------------------------------------------------------------------+
//| expert initialization function |
//+------------------------------------------------------------------+
int init()
{
//----
// установим время последней торговой операции вчерашним днем
LastTradeTime = CurTime()-24*60*60;
//----
return(0);
}


 

На каждом тике вызывается функция 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 ((TimeHour(CurTime())==MyHour)&&(TimeMinute(CurTime())==MyMinute))
{
...
}



 

Расскажу о двух незнакомых функциях в этом участке кода:

  • int TimeHour(datetime time) — возвращает час для времени time: 0..23;
  • int TimeMinute(datetime time) — возвращает минуту для времени time: 0..59.

Если уже пора выставить отложенный ордер, то сначала с помощью функции OrderSend() размещаем ордер Buy Stop.

Потом выжидаем паузу в 10 секунд с помощью функции Sleep():

 

 void Sleep(int milliseconds)


 

Эта функция делает паузу в работе эксперта на milliseconds милисекунд (1 секунда = 1000 милисекунд).

За эти 10 секунд текущий бид и аск могли измениться, поэтому мы обновляем их с помощью функции RefreshRates().

Далее мы выставляем отложенный ордер Sell Stop.

Вот мы и дошли до конца нашего эксперта. Хочу заметить, что этот эксперт может пропустить момент, когда надо было выставить отложенный ордер, если в этом баре не было котировок и функция start() не вызывалась. Думаю, что у моего читателя уже достаточно собственных знаний, чтобы самостоятельно подправить этот недостаток эксперта.