Ошибка 129 при OrderClose() - кто виноват и что делать ? - страница 2

 
George Merts:

Приветствую всех.

Во время попытки закрытия ордера - возвращается код 129. "Неправильная цена". Хотя, в тестере - всегда все проходит нормально, и если перезапустить советник - то тоже все проходит нормально.

В чем причина, и что делать ?

Закрытие происходит по паре евродоллара в два часа ночи, когда рынок спокоен. Параметр slippage устанавливаю 10 пунктов. Но уже несколько раз происходит возврат этой ошибки (и при этом все нормально проходит при перезапуске).

Что порекомендуете, друзья ?

до закрытия что-то наверное долго считаете - цена уходит. Дёрните RefreshRates()
 
Artyom Trishkin:
Если во время цикла на очередном тике, советник выполняет много вычислений, то он может пропустить очередной тик. Таким образом его торговое окружение, а с ним и Bid с Ask, будут не соответствовать текущему. Поэтому всегда нужно брать актуальные цены перед выполнением торгового приказа.

Цены берутся непосредственно перед приказом:

     if(OrderType() == OP_BUY)
         dClosePrice = MarketInfo(OrderSymbol(),MODE_BID); // Раньше было dClosePrice = Bid
      else     
         dClosePrice = MarketInfo(OrderSymbol(),MODE_ASK); // Раньше было dClosePrice = Ask

      ResetLastError();
     
      if(OrderClose(iCloseTicket,dOrderLots,dClosePrice,(int)ulSlippage,CLR_NONE) != true)
         {
         int iError = GetLastError();
         TRACE_INTEGER("Не удалось удалить ордер, тикет: ",iCloseTicket);
         TRACE_INTEGER("Код ошибки: ",iError);
         Print("Can't close order, ticket: ",iCloseTicket);
         Print("Error code: ",iError);
         Print("Current Bid: ",Bid);
         Print("Current Ask: ",Ask);
         Print("Close price: ",dClosePrice);
         Print("Volume: ",dOrderLots);
         return(false);
         };

Пока - разница только в запросе самих цен. Если Bid-Ask может содержать не те цены, что в MarketInfo() - безусловно, тут может быть ошибка 129

 
goman:

Это 100% проделки брокера. Избежать этого на счетах standart не получится.

Нужно либо уходить на ECN-счета, либо отправлять повторный приказ на закрытие, при получении подобных ошибок.

Да, на ECN-счетах такого ни разу не было. 
 
George Merts:

Цены берутся непосредственно перед приказом:

     if(OrderType() == OP_BUY)
         dClosePrice = MarketInfo(OrderSymbol(),MODE_BID); // Раньше было dClosePrice = Bid
      else     
         dClosePrice = MarketInfo(OrderSymbol(),MODE_ASK); // Раньше было dClosePrice = Ask

      ResetLastError();
     
      if(OrderClose(iCloseTicket,dOrderLots,dClosePrice,(int)ulSlippage,CLR_NONE) != true)
         {
         int iError = GetLastError();
         TRACE_INTEGER("Не удалось удалить ордер, тикет: ",iCloseTicket);
         TRACE_INTEGER("Код ошибки: ",iError);
         Print("Can't close order, ticket: ",iCloseTicket);
         Print("Error code: ",iError);
         Print("Current Bid: ",Bid);
         Print("Current Ask: ",Ask);
         Print("Close price: ",dClosePrice);
         Print("Volume: ",dOrderLots);
         return(false);
         };

Пока - разница только в запросе самих цен. Если Bid-Ask может содержать не те цены, что в MarketInfo() - безусловно, тут может быть ошибка 129

Разница подходов очевидна. Так, если OrderSymbol() - не текущий символ, то Вы брали не те Bid и Ask. Получаем, что все закономерно - ошибка генерировалась правильно.
 
Ihor Herasko:
Разница подходов очевидна. Так, если OrderSymbol() - не текущий символ, то Вы брали не те Bid и Ask. Получаем, что все закономерно - ошибка генерировалась правильно.

Бот работает только на текущем символе, цены обновляются (RefreshRates) и, если надо, корректируются непосредственно перед отправкой запроса, результат тот же - #129. Вот наглядный образец из лога с комментами от бота

0 03:16:08.683    MLbT EURUSD,H1: Пара #8 на уровне 3
0 03:16:08.683    MLbT EURUSD,H1: EURUSD Order_Type: Buy Lots: 0.2 Open_Price: 1.0919 Slippage: 10 SL: 0.0 TP: 0.0 Comment: *3*  Magic: 2015 Ask=1.09191 Bid=1.09178
0 03:16:08.683    MLbT EURUSD,H1: Invalid price (129)
0 03:16:10.867    MLbT EURUSD,H1: EURUSD Order_Type: Buy Lots: 0.2 Open_Price: 1.0919 Slippage: 10 SL: 0.0 TP: 0.0 Comment: *3*  Magic: 2015 Ask=1.09192 Bid=1.09180
0 03:16:10.867    MLbT EURUSD,H1: Invalid price (129)
2 03:16:13.426    MLbT EURUSD,H1: open #316283055 buy 0.20 EURUSD at 1.09190 ok
0 03:16:13.426    MLbT EURUSD,H1: EURUSD Order_Type: Sell Lots: 0.2 Open_Price: 1.09178 Slippage: 10 SL: 0.0 TP: 0.0 Comment: *3*  Magic: 2015 Ask=1.09190 Bid=1.09179
0 03:16:13.426    MLbT EURUSD,H1: Invalid price (129)
0 03:16:15.610    MLbT EURUSD,H1: EURUSD Order_Type: Sell Lots: 0.2 Open_Price: 1.09178 Slippage: 10 SL: 0.0 TP: 0.0 Comment: *3*  Magic: 2015 Ask=1.09188 Bid=1.09177
0 03:16:15.610    MLbT EURUSD,H1: Invalid price (129)
0 03:16:17.794    MLbT EURUSD,H1: EURUSD Order_Type: Sell Lots: 0.2 Open_Price: 1.09178 Slippage: 10 SL: 0.0 TP: 0.0 Comment: *3*  Magic: 2015 Ask=1.09191 Bid=1.09179
0 03:16:17.794    MLbT EURUSD,H1: Invalid price (129)
0 03:16:19.978    MLbT EURUSD,H1: Ошибка выставления ордера на продажу. Лот = 0.2 Ask=1.09191 Bid=1.09179

Как видите, Bid и Ask обновляются, заданное проскальзывание с лихом перекрывает разницу меж ценой заказа и актуальной ценой и один хрен #129. Здесь Buy открылся с 3й попытки, на Sell разрешённых 3х не хватило

 

goman:

Это 100% проделки брокера. Избежать этого на счетах standart не получится.

Нужно либо уходить на ECN-счета, либо отправлять повторный приказ на закрытие, при получении подобных ошибок.

И я того же мнения. Эта конкретная траблема порешилась сменой ДЦ. Думаю, этот вопрос в подробностях могли бы прояснить разработчики, да оно им надо?
 
Ihor Herasko:
Разница подходов очевидна. Так, если OrderSymbol() - не текущий символ, то Вы брали не те Bid и Ask. Получаем, что все закономерно - ошибка генерировалась правильно.
В МТ4 - вроде как нельзя взять другой символ. Но, суть в том, что в тестере-то все проходит.
 
George Merts:
Да, на ECN-счетах такого ни разу не было. 

Естественно, ведь на ECN-счетах маркет исполнение, т.е. по рынку. Вы отправляете маркет ордер без цены и он исполняется по цене существующей на данный момент на рынке. А на счетах standart исполнение по потоковым ценам. Вы отсылаете маркет ордер с указанием цены открытия. И если цена на рынке отличается от цены, указанной в ордере, то Вы вместо открытия ордера получаете ошибку 129 -"неправильная цена". Поэтому я и предложил либо перейти на маркет исполнение (счет ECN), либо, при получении ошибки 129, отправлять повторный приказ.

Третьего не дано. :)

 
George Merts:

Цены берутся непосредственно перед приказом:

     if(OrderType() == OP_BUY)
         dClosePrice = MarketInfo(OrderSymbol(),MODE_BID); // Раньше было dClosePrice = Bid
      else     
         dClosePrice = MarketInfo(OrderSymbol(),MODE_ASK); // Раньше было dClosePrice = Ask

      ResetLastError();
     
      if(OrderClose(iCloseTicket,dOrderLots,dClosePrice,(int)ulSlippage,CLR_NONE) != true)
         {
         int iError = GetLastError();
         TRACE_INTEGER("Не удалось удалить ордер, тикет: ",iCloseTicket);
         TRACE_INTEGER("Код ошибки: ",iError);
         Print("Can't close order, ticket: ",iCloseTicket);
         Print("Error code: ",iError);
         Print("Current Bid: ",Bid);
         Print("Current Ask: ",Ask);
         Print("Close price: ",dClosePrice);
         Print("Volume: ",dOrderLots);
         return(false);
         };

Пока - разница только в запросе самих цен. Если Bid-Ask может содержать не те цены, что в MarketInfo() - безусловно, тут может быть ошибка 129

еще есть очень небольшой пустячок но почти всегда помогает бороться с подобными ошибками, необходимо цену перед запросом нормализовать, я обычно это делаю так

 

   if(type==OP_BUY)
     {
      price=NormalizeDouble(Ask,_Digits);
      if(AccountFreeMarginCheck(_Symbol,type,Lot)<=0)return;
     }
   if(type==OP_SELL)
     {
      price=NormalizeDouble(Bid,_Digits);
      if(AccountFreeMarginCheck(_Symbol,type,Lot)<=0)return;
     }
 
Sergey Gritsay:

еще есть очень небольшой пустячок но почти всегда помогает бороться с подобными ошибками, необходимо цену перед запросом нормализовать, я обычно это делаю так

 

Кстати да, при #property strict в восьмом знаке, хоть его и быть не должно, а он есть) может "заблудиться" единица и тогда отправим цену 1.08580001 Ecn примет, а стандарт врядли.  
 

В Сервисдеске предложили также проскальзывание увеличить.

Поставлю 50 пунктов (5-разрядных), и, действительно, NormalizeDouble() вставлю в запросе цены... Хотя, казалось бы - прямой запрос должен возвращать нормализованную цену...

Причина обращения: