Удаление отложенных ордеров в тестере

 
Столкнулся с тем, что тестер не удаляет отложенные ордера sell stop (при том, что buy stop удаляются нормально). Проблема сохранилась в билде от 14 декабря.
Подробнее: Советник ставит отложенные stop ордера в обе стороны, при открытии одного из них, второй должен удаляться. Вот фрагмент кода:

if (Order_Type == OP_BUYSTOP || Order_Type == OP_SELLSTOP) {
if (Order_Type == OP_BUYSTOP) Print("Delete Buy Stop ",OrderTicket());
if (Order_Type == OP_SELLSTOP) Print("Delete Sell Stop ",OrderTicket());
if(OrderDelete(OrderTicket()) == FALSE) {
err=GetLastError();
Print("error(",err,"): ",ErrorDescription(err));
}
return(0);
}

Как видно, конструкция абсолютно симметрична по отношению к buy и stop.
А это фрагмент лога:

23:09:56 Swings EURUSD,M1: loaded successfully
23:09:56 Swings inputs: OrdersRange=10; TakeProfit=50; StopLoss=30; TrailingStop=15; Lots=0.1;
23:09:56 2005.07.22 08:42 Swings EURUSD,M1: open #1 sell stop 0.10 EURUSD at 1.2168 sl: 1.2201 tp: 1.2118 ok
23:09:56 2005.07.22 08:42 Swings EURUSD,M1: open #2 buy stop 0.10 EURUSD at 1.2190 sl: 1.2157 tp: 1.2240 ok
23:09:56 2005.07.22 09:41 Tester: order #1, sell 0.10 EURUSD is opened at 1.2168
23:09:56 2005.07.22 09:41 Swings EURUSD,M1: Delete Buy Stop 2
23:09:56 2005.07.22 09:41 Swings EURUSD,M1: delete #2 buy stop 0.10 EURUSD at 1.2190 sl: 1.2157 tp: 1.2240 ok
23:09:56 2005.07.22 15:53 Tester: take profit #1 at 1.2118 (1.2114 / 1.2117)
23:09:56 2005.07.22 15:53 Swings EURUSD,M1: open #3 sell stop 0.10 EURUSD at 1.2104 sl: 1.2137 tp: 1.2054 ok
23:09:56 2005.07.22 15:53 Swings EURUSD,M1: open #4 buy stop 0.10 EURUSD at 1.2130 sl: 1.2097 tp: 1.2180 ok
23:09:56 2005.07.22 16:00 Tester: order #4, buy 0.10 EURUSD is opened at 1.2130
23:09:56 2005.07.22 16:17 Tester: order #3, sell 0.10 EURUSD is opened at 1.2104

То есть тестер даже не делает попытки удалить sell stop ордер (отладочные Print'ы молчат).
Дальше лог приводить смысла нет, удаление sell stop повсюду игнорируется.
В предыдущем билде тестер всё же пытался их удалять, при этом Print("error(",err,"): ",ErrorDescription(err)); давал ошибку 2.
 
К сожалению, Вы не приложили полный код.
 
К сожалению, Вы не приложили полный код.

Исправляюсь:
#property copyright "Copyright © 2005, Candid"
#property link      ""

#include <stdlib.mqh>

#define MAGICMA  20050610

extern int       OrdersRange    = 10;  
extern int       TakeProfit     = 50;
extern int       StopLoss       = 30;
extern int       TrailingStop   = 15;
extern double    Lots           = 0.1;

double  rTakeProfit;
double  rStopLoss;
double  rTrailingStop;
double  rOrdersRange;  

bool FirstComplete = FALSE;
bool AllComplete   = FALSE;
int TotalOrders    = 0;
int Order_Type;
//+------------------------------------------------------------------+
//| expert initialization function                                   |
//+------------------------------------------------------------------+
int init() {
//---- 
  rTakeProfit = TakeProfit*Point;
  rStopLoss = StopLoss*Point;
  rTrailingStop = TrailingStop*Point; 
  rOrdersRange = OrdersRange*Point; 
  
//----
  return(0);
}
//+------------------------------------------------------------------+
//| expert deinitialization function                                 |
//+------------------------------------------------------------------+
int deinit() {
//---- 
   
//----
  return(0);
}
//+------------------------------------------------------------------+
//| Функция проверки сигнала на закрытие позиций                     |
//+------------------------------------------------------------------+
bool CloseSignal() {
  TotalOrders = OrdersTotal();
  if (TotalOrders == 2) {
    for(int pos=0;pos<TotalOrders;pos++) {
      OrderSelect(pos,SELECT_BY_POS);
      Order_Type=OrderType();
      if (Order_Type == OP_BUY || Order_Type == OP_SELL) {
        return(TRUE);
      } else return(FALSE);
    }
  } else return(FALSE);
}
//+------------------------------------------------------------------+
//| Функция проверки сигнала на постановку позиций                   |
//+------------------------------------------------------------------+
bool OpenSignal() {
  TotalOrders = OrdersTotal();
  if (TotalOrders == 0) {
    FirstComplete = FALSE;
    AllComplete = FALSE;
    return (TRUE);
  } else return (FALSE);
}
//+------------------------------------------------------------------+
//| expert start function                                            |
//+-----------------------------------------------------------------+
int start() {
  int err;
// Закрытие(удаление) "своих" позиций
  if (CloseSignal()) {
    if (TotalOrders == 2) {
      for(int pos=0;pos<TotalOrders;pos++) {
        OrderSelect(pos,SELECT_BY_POS);
        Order_Type=OrderType();
        if (Order_Type == OP_BUYSTOP || Order_Type == OP_SELLSTOP) {
          if (Order_Type == OP_BUYSTOP) Print("Delete Buy Stop  ",OrderTicket());
          if (Order_Type == OP_SELLSTOP) Print("Delete Sell Stop  ",OrderTicket());
          if(OrderDelete(OrderTicket()) == FALSE) {
            err=GetLastError();
            Print("error(",err,"): ",ErrorDescription(err));
          }
          return(0);
        }
      }
    }
  }

  if (OpenSignal() || !AllComplete) {
    if (!FirstComplete) {
      FirstComplete = TRUE;
      OrderSend(Symbol(),OP_SELLSTOP,Lots,Bid-rOrdersRange,3,Ask+rStopLoss-rOrdersRange,Bid-rTakeProfit-rOrdersRange,"",MAGICMA,0,Red);
      return(0);
    }
    if (!AllComplete) {
      AllComplete = TRUE;
      OrderSend(Symbol(),OP_BUYSTOP,Lots,Ask+rOrdersRange,3,Bid-rStopLoss+rOrdersRange,Ask+rTakeProfit+rOrdersRange,"",MAGICMA,0,Blue);
      return(0);
    }
  }
//----
  return(0);
}
//+------------------------------------------------------------------+
 
Тут сразу 2 ошибки
1) идет _увеличивающийся_ цикл for(int pos=0;pos<TotalOrders;pos++)
первая позиция нормально удаляется и OrdersTotal() уже выдаст единицу, а не 2.
на следующей итерации идет обращение ко второму ордеру по списку, хотя в списке остался всего один ордер!

2) не проверяется результат OrderSelect(). А ведь это сразу бы показало, что второй ордер не может быть найден!

Стандартный механизм массовой обработки ордеров - это использование цикла с конца списка. То есть:
for(int i=OrdersTotal();i>=0;i--)
 
Уважаемый Renat, Ваш ответ косвенным образом помог мне найти ошибку, спасибо. Ошибка была в функции CloseSignal() и состояла в использовании return вместо continue - то есть и после открытия отложенного buy функция продолжала возвращать FALSE. Теперь странным выглядит то, что на предыдущем билде советник и в этой ситуации всё же пытался закрывать ордера(что, собственно, и спровоцировало меня искать ошибку в другом месте), но разбираться с этим видимо смысла нет.
1) идет _увеличивающийся_ цикл for(int pos=0;pos<TotalOrders;pos++)
первая позиция нормально удаляется и OrdersTotal() уже выдаст единицу, а не 2.
на следующей итерации идет обращение ко второму ордеру по списку, хотя в списке остался всего один ордер!
Здесь я не могу с Вами согласиться. TotalOrders - это не функция MQL, а моя переменная, перед входом в цикл её значение проверяется и далее в цикле не меняется. По логу видно, что конструкция не срабатывала для sell stop (и срабатывала для buy stop) именно тогда, когда имеется 2 ордера (а только в этом случае она и должна работать).
 
Стандартный механизм массовой обработки ордеров - это использование цикла с конца списка. То есть:
for(int i=OrdersTotal();i>=0;i--)


Наверное будет for(int i=OrdersTotal()-1;i>=0;i--)
 
Здесь я не могу с Вами согласиться. TotalOrders - это не функция MQL, а моя переменная, перед входом в цикл её значение проверяется и далее в цикле не меняется. По логу видно, что конструкция не срабатывала для sell stop (и срабатывала для buy stop) именно тогда, когда имеется 2 ордера (а только в этом случае она и должна работать).

Было 2 ордера в позициях 0 и 1. После закрытия ордера в позиции 0, она удаляется и оставшиеся ордера сдвигаются к началу. То есть, позиция 1 переходит в позицию 0. И тут Ваш код пытается обратиться к позиции 1 (уже несуществующей!), да еще без проверки корректности вызова OrderSelect.

Это стандартное заблуждение многих программистов, когда они думают, что программа линейна и все процессы синхронны. А большинство процессов в терминале полностью асинхронны. То есть, происходят независимо и одновременно. Конечно же, в самом терминале конфликтов нет, так как терминал был написан с четким пониманием асинхронности и вовсю используются синхронизаторы.

Программисты на MQL4 зачастую думают, что их код выполняется в одиночестве и мгновенно при неизменных условиях, что никакого терминала и других процессов вокруг нет. Совершенно забывая, что во время работы одного эксперта ордеры могут быть изменены или удалены другими экспертами или человеком вручную. Иногда (как в Вашем случае) даже не учитывают своих собственных действий, которые непосредственным образом влияют на окружающее состояние.
Кстати, мы постоянно требуем - "всегда проверяйте результат вызова OrderSelect()".

Наверное будет for(int i=OrdersTotal()-1;i>=0;i--)

Да, точно. Похоже ошибся второпях. Извините.
 
В своё оправдание :) могу лишь сказать, что пока это только заготовка для эксперта. Предполагается длинный путь эволюции на тестере и лишь затем, возможно, перевод в боевой вариант. В какой мере ради ускорения отработки алгоритма можно пренебрегать техникой безопасности? Вопрос, видимо, риторический.
Асинхронность же действительно создаёт серьёзные трудности, так что полученная информация весьма полезна, ещё раз спасибо.
Причина обращения: