Циклы и закрытие или удаление заказов

 

Это одна из самых распространенных ошибок, которые я вижу, возможно, отчасти из-за такого мусора, как Expert Advisor Builder. Поэтому я решил, что пришло время создать тему, посвященную этому вопросу, чтобы на нее можно было ссылаться в будущем.

Проблема

Давайте рассмотрим простой пример: нам нужна функция для закрытия всех открытых ордеров нашего советника, примеров много, но давайте создадим один с нуля.

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

int PositionIndex;    //  <-- this variable is the index used for the loop

int TotalNumberOfOrders;   //  <-- this variable will hold the number of orders currently in the Trade pool

TotalNumberOfOrders = OrdersTotal();    // <-- we store the number of Orders in the variable

for(PositionIndex = 0; PositionIndex < TotalNumberOfOrders; PositionIndex++)  //  <-- for loop to loop through all Orders
   {
   if( ! OrderSelect(PositionIndex, SELECT_BY_POS, MODE_TRADES) ) continue;   // <-- if the OrderSelect fails advance the loop to the next PositionIndex
   
   if( OrderMagicNumber() == MagicNo       // <-- does the Order's Magic Number match our EA's magic number ? 
      && OrderSymbol() == Symbol()         // <-- does the Order's Symbol match the Symbol our EA is working on ? 
      && ( OrderType() == OP_BUY           // <-- is the Order a Buy Order ? 
      ||   OrderType() == OP_SELL ) )      // <-- or is it a Sell Order ?

      if ( ! OrderClose( OrderTicket(), OrderLots(), OrderClosePrice(), Slippage ) )               // <-- try to close the order
         Print("Order Close failed, order number: ", OrderTicket(), " Error: ", GetLastError() );  // <-- if the Order Close failed print some helpful information 
      
   } //  end of For loop

Этот код плох. . . НЕ ИСПОЛЬЗУЙТЕ ЕГО. . . Я объясню почему в следующем разделе ... .

Объяснение

Давайте проработаем приведенный выше код... строка за строкой, ордер за ордером...

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

Позиция Номер билета
0111
1222
2 333
3444
4555

Первый проход по циклу:

начальное значение PositionIndex равно 0, поэтому выбирается заказ на позиции 0, билет номер 111, этот заказ успешно удаляется, а остальные заказы меняют позицию следующим образом:

Позиция Номер билета
0222
1 333
2444
3555

2-й проход по циклу:

теперь значение PositionIndex равно 1, поэтому выбирается ордер на позиции 1, билет номер 333, этот ордер успешно удаляется, а остальные ордера меняют позицию следующим образом:

Позиция Номер билета
0222
1 444
2555

3-й проход по циклу:

теперь значение PositionIndex равно 2, поэтому выбирается ордер на позиции 2, билет номер 555, этот ордер успешно удаляется, а остальные ордера меняют позицию следующим образом:

Позиция Номер билета
0222
1 444

4-й проход по циклу:

теперь значение PositionIndex равно 3 OrderSelect() пытается выбрать ордер на позиции 3 и терпит неудачу, continue переносит выполнение кода на следующее значение в цикле. ...


Пятый и последний запуск цикла:

теперь значение PositionIndex равно 4 OrderSelect() пытается выбрать ордер в позиции 4 и не удается, continue переводит выполнение кода на следующее значение в цикле ... цикл завершен.


Теперь у нас осталось 2 заказа, билеты 222 и 444, которые должны были быть закрыты, но не были... Далее, как решить эту проблему.

Решение

Следующий код является правильным подходом при закрытии открытых ордеров или удалении отложенных ордеров. ...

Ключевое отличие заключается в том, что цикл уменьшает значение от ( TotalNumberOfOrders - 1 ) до 0

.

int PositionIndex;    //  <-- this variable is the index used for the loop

int TotalNumberOfOrders;   //  <-- this variable will hold the number of orders currently in the Trade pool

TotalNumberOfOrders = OrdersTotal();    // <-- we store the number of Orders in the variable

for(PositionIndex = TotalNumberOfOrders - 1; PositionIndex >= 0 ; PositionIndex --)  //  <-- for loop to loop through all Orders . .   COUNT DOWN TO ZERO !
   {
   if( ! OrderSelect(PositionIndex, SELECT_BY_POS, MODE_TRADES) ) continue;   // <-- if the OrderSelect fails advance the loop to the next PositionIndex
   
   if( OrderMagicNumber() == MagicNo       // <-- does the Order's Magic Number match our EA's magic number ? 
      && OrderSymbol() == Symbol()         // <-- does the Order's Symbol match the Symbol our EA is working on ? 
      && ( OrderType() == OP_BUY           // <-- is the Order a Buy Order ? 
      ||   OrderType() == OP_SELL ) )      // <-- or is it a Sell Order ?
   
      if ( ! OrderClose( OrderTicket(), OrderLots(), OrderClosePrice(), Slippage ) )               // <-- try to close the order
         Print("Order Close failed, order number: ", OrderTicket(), " Error: ", GetLastError() );  // <-- if the Order Close failed print some helpful information 
      
   } //  end of For loop

Давайте еще раз проработаем приведенный выше код ... строка за строкой, ордер за ордером ...

У нас те же заказы, что и раньше:

Позиция Номер билета
0111
1222
2333
3444
4555

1-й проход по циклу:

начальное значение PositionIndex равно TotalNumberOfOrders - 1, что равно 5 - 1 = 4, поэтому выбирается заказ на позиции 4, номер билета 555, этот заказ успешно удаляется, а остальные заказы меняют позицию следующим образом:

Позиция Номер билета
0111
1222
2333
3444

2-й проход по циклу:

теперь значение PositionIndex равно 3, поэтому выбирается ордер на позиции 3, билет номер 444, этот ордер успешно удаляется, а остальные ордера меняют позицию следующим образом:

Позиция Номер билета
0111
1222
2333

3-й проход по циклу:

теперь значение PositionIndex равно 2, поэтому выбирается ордер на позиции 2, билет номер 333, этот ордер успешно удаляется, а остальные ордера меняют позицию следующим образом:

Позиция Номер билета
0111
1222

4-й проход по циклу:

теперь значение PositionIndex равно 1 , поэтому выбирается ордер на позиции 1, билет номер 222, этот ордер успешно удаляется, а остальные ордера меняют позицию следующим образом:

Позиция Номер билета
0111

5-й и последний проход по циклу:

теперь значение PositionIndex равно 0 поэтому выбирается заказ на позиции 0, билет номер 111, этот заказ успешно удаляется, значение 0 - последнее допустимое значение для цикла ... цикл завершен.

Мы успешно удалили все совпадающие ордера...

Ссылка на эту тему: Циклы и закрытие или удаление ордеров

 

Возьмем более сложный пример...

Предположим, что у нас есть следующие ордера, которые мы хотим закрыть, все они имеют одинаковый магический номер, но некоторые имеют другой символ, чем наш советник, мы хотим, чтобы наш код закрывал ордера по тому же символу, что и наш советник, EURUSD:

Позиция Номер билета Символ
0111 EURUSD
1222 EURUSD
2333GBPUSD
3444 EURUSD
4555 EURUSD


Первый проход по циклу:

начальное значение PositionIndex равно TotalNumberOfOrders - 1, что равно 5 - 1 = 4, поэтому выбирается ордер на позиции 4, номер билета 555, этот ордер соответствует магическому номеру и символу, поэтому успешно удаляется, а остальные ордера меняют позицию следующим образом:

Позиция Номер билета Символ
0111EURUSD
1222EURUSD
2333GBPUSD
3444EURUSD

2-й проход по циклу:

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

Позиция Номер билета Символ
0111EURUSD
1222EURUSD
2333GBPUSD


3-й проход по циклу:

теперь значение PositionIndex равно 2, поэтому выбирается ордер на позиции 2, тикет номер 333, этот ордер соответствует магическому номеру, но НЕ символу, поэтому он не удаляется, остальные ордера не меняются:

Позиция Номер билета Символ
0111EURUSD
1222EURUSD
2333GBPUSD

4-й проход по циклу:

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

Позиция Номер билета Символ
0111EURUSD
1333GBPUSD

5-й и последний проход по циклу:

теперь значение PositionIndex равно 0 , поэтому выбран ордер на позиции 0, билет номер 111, этот ордер успешно удален, значение 0 - последнее допустимое значение для цикла ... цикл завершен.

Мы успешно удалили все наши совпадающие ордера, оставив один ордер, который не соответствовал нашему символу, билет номер 333 теперь на позиции 0. ...

Позиция Номер билета Символ
0333GBPUSD


Ссылка на эту тему: Петли и закрытие или удаление ордеров

 
См. также, почему вы должны вести обратный отсчет и проверять состояние OrderSelect
 

Спасибо Raptor за это важное объяснение.

Y.

 
Это чрезвычайно полезно для меня, короля мусорного конструктора советников! О, как мне нравится ковыряться в получившемся коде. Большое спасибо.
 

Ничего себе. Вся эта информация для закрытия ордера.

Интересно, сколько информации нужно, чтобы получать 50+ пунктов в день, последовательно, каждый день (в среднем) - без сбоев, на протяжении последних 137 сделок.

Покажите мне, как сделать что-то подобное, и я буду считать это чрезвычайно полезной информацией, и Гуру, да будет ваш титул, во веки веков, аминь.

 
CFx:

Ничего себе. Вся эта информация для закрытия ордера.

Интересно, сколько информации нужно, чтобы получать 50+ пипсов в день, последовательно, каждый день (в среднем) - без сбоев, на протяжении последних 137 сделок.

Меня не интересуют пипсы... что я могу с ними делать? Я не могу их потратить, какова ставка GBPPIPS? Вы показываете свое невежество, считая успех в пунктах....
 
CFx:

Интересно, сколько информации нужно, чтобы получать 50+ пипсов в день, последовательно, каждый день (в среднем) - без сбоев, на протяжении последних 137 сделок.

Покажите мне, как сделать что-то подобное, и я буду считать это чрезвычайно полезной информацией, а Гуру будет вашим титулом, во веки веков, аминь.

  1. Не засоряйте тему информацией не по теме
  2. Мы НЕ собираемся показывать вам это, потому что вы не прочитали правила Любые обсуждения, кроме касающихся MetaQuotes Language 4 и автотрейдинга, запрещены.
 

Raptor, с первого взгляда на ваше сообщение я понял, что вы являетесь экспертом в mql4. Эта тема снова помогла развеять мои сомнения! Продолжайте в том же духе. tnx

 

Просто еще одна идея:

for(PositionIndex = 0; PositionIndex < OrdersTotal() ; PositionIndex ++)  //  <-- for loop to loop through all Orders . .   COUNT DOWN TO ZERO !
   {
   if( ! OrderSelect(PositionIndex, SELECT_BY_POS, MODE_TRADES) ) continue;   // <-- if the OrderSelect fails advance the loop to the next PositionIndex
   
   if( OrderMagicNumber() == MagicNo       // <-- does the Order's Magic Number match our EA's magic number ? 
      && OrderSymbol() == Symbol()         // <-- does the Order's Symbol match the Symbol our EA is working on ? 
      && ( OrderType() == OP_BUY           // <-- is the Order a Buy Order ? 
      ||   OrderType() == OP_SELL ) )      // <-- or is it a Sell Order ?
   
         add_trade_to_close_queue( OrderTicket());  // <--  You need to model the queue mechanism ...
      
   } //  end of For loop


С уважением.

 
abstract_mind:


Просто еще одна идея:


С уважением.

Да, понимая логику МТ4, вы можете сами кодировать увеличение или уменьшение счетчика.