OrderDelete - логика работы

 
for(int i = 0; i < OrdersTotal(); i ++)
     {
       if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
        { if (IsStopOrder()) 
            OrderDelete(OrderTicket());
        }
     }

Есть такой код, вроде все правильно, но удаляет почему то только один ордер, хотя на самом деле их два. ф-ия IsStopOrder возвращает истина если ордер OP_BUYSTOP или OP_SELLSTOP. На второй итерации удаляется и второй.

Почему они оба сразу не удаляются? смещаются индексы? кк тогда быть подскажите

 
scorpionk:

Почему они оба сразу не удаляются? смещаются индексы? кк тогда быть подскажите


как вариант - удалять циклом i--

либо скидывать тикеты в массив и потом удалять по тикетам. это работает всегда и на 100% :-)

 
Старые грабли. Цикл сделайте с конца.
for(int i = OrdersTotal() - 1; i >= 0 ; i --)
 
Talex:
Старые грабли. Цикл сделайте с конца.
for(int i = OrdersTotal() - 1; i >= 0 ; i --)

Так и подумал, поискал на форуме не нашел ответа

спасибо

 

Была таже проблема, только код другой немного.

А скажите плиз в чём "грабли"?

 
kermit писал (а):
А скажите плиз в чём "грабли"?

На примере двух ордеров. Индексы 0 и 1. Удаляется ордер с индексом 0. Ордер с индексом 1 становится на его место. Оставшийся ордер переиндексируется, смещается и ему присваивается индекс 0. В цикле следующим берётся ордер с индексом 1, которого уже нет. Вместо него опять ордер с индексом 0, который остаётся неудалённым.

Удалять ордера можно двумя способами:
1. Цикл любой. Внутри цикла удалять ордер с нулевым индексом.
2. Цикл с обратным проходом. Внутри цикла удалять ордер с индексом счётчика цикла.

 
KimIV:
kermit писал (а):
А скажите плиз в чём "грабли"?

На примере двух ордеров. Индексы 0 и 1. Удаляется ордер с индексом 0. Ордер с индексом 1 становится на его место. Оставшийся ордер переиндексируется, смещается и ему присваивается индекс 0. В цикле следующим берётся ордер с индексом 1, которого уже нет. Вместо него опять ордер с индексом 0, который остаётся неудалённым.

Удалять ордера можно двумя способами:
1. Цикл любой. Внутри цикла удалять ордер с нулевым индексом.
2. Цикл с обратным проходом. Внутри цикла удалять ордер с индексом счётчика цикла.

Также желательно после OrderDelete() поставить Sleep(), т.к. можно нарваться на реквоты - торговый поток всего один, а торговых операций в цикле несколько
 
Reshetov:
Также желательно после OrderDelete() поставить Sleep(), т.к. можно нарваться на реквоты - торговый поток всего один, а торговых операций в цикле несколько


Можно нарваться не только на реквоты, поэтому лучше обрабатывать ошибки, примерно так:
if(!OrderClose(OrderTicket(), OrderLots(), ClosePrice, slippage, CLR_NONE)) {
   err = GetLastError();
   Error(...параметры...) - функция для обработки ошибок.
}
И не только после OrderDelete().
 
Reshetov:
KimIV:
kermit писал (а):
А скажите плиз в чём "грабли"?

На примере двух ордеров. Индексы 0 и 1. Удаляется ордер с индексом 0. Ордер с индексом 1 становится на его место. Оставшийся ордер переиндексируется, смещается и ему присваивается индекс 0. В цикле следующим берётся ордер с индексом 1, которого уже нет. Вместо него опять ордер с индексом 0, который остаётся неудалённым.

Удалять ордера можно двумя способами:
1. Цикл любой. Внутри цикла удалять ордер с нулевым индексом.
2. Цикл с обратным проходом. Внутри цикла удалять ордер с индексом счётчика цикла.

Также желательно после OrderDelete() поставить Sleep(), т.к. можно нарваться на реквоты - торговый поток всего один, а торговых операций в цикле несколько


А какой размер Sleep лучше использовать? Понятно, что он может быть в разных ДЦ разный, но если как "средняя температура по больнице", то какое значение чаще бывает?
 
scorpionk:
for(int i = 0; i < OrdersTotal(); i ++)
     {
       if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
        { if (IsStopOrder()) 
            OrderDelete(OrderTicket());
        }
     }

Есть такой код, вроде все правильно, но удаляет почему то только один ордер, хотя на самом деле их два. ф-ия IsStopOrder возвращает истина если ордер OP_BUYSTOP или OP_SELLSTOP. На второй итерации удаляется и второй.

Почему они оба сразу не удаляются? смещаются индексы? кк тогда быть подскажите


Это действительно грабли. Содержание граблей в том, что после удаления первого ордера количество ордеров, определяемое функцией OrdersTotal(), становится меньше на 1, поэтому в заголовке оператора for() меняется предельное значение, и очередная итерация просто не исполняется. Проанализируйте также порядок удаления ордеров. Ведь после удаления любого ордера список ордеров перестраивается, т.е. меняются индексы ордеров в списке. Если их, например, 10, то порядок удаления будет такой: 1, 3, 5.

Вообще, так это не делается. Чтобы правильно удалять ордера, необходимо опеределить их приоритет, т.е. выяснить, какой ордер нужно удалить раньше, а какой позже. Для этого нужно принять во внимание близость ордера к рынку, количество лотов и др. параметры. Возможно, Вам будет интересно почитать статью Учёт ордеров в большой программе .

А Sleep() тут ни при чём.

 
KimIV >>:

На примере двух ордеров. Индексы 0 и 1. Удаляется ордер с индексом 0. Ордер с индексом 1 становится на его место. Оставшийся ордер переиндексируется, смещается и ему присваивается индекс 0. В цикле следующим берётся ордер с индексом 1, которого уже нет. Вместо него опять ордер с индексом 0, который остаётся неудалённым.

Удалять ордера можно двумя способами:
1. Цикл любой. Внутри цикла удалять ордер с нулевым индексом.
2. Цикл с обратным проходом. Внутри цикла удалять ордер с индексом счётчика цикла.

Много времени убил на поиски этой темы. Наконец нашел.

Все верно. Но есть уточнение.

Если пользоваться циклом for(i=0;i<OrdersTotal();i++) {OrderSelect(0,...)...}

то все равно удалится только половина ордеров, т.к. кол-во ордеров-то уменьшается.

Поэтому надо сначала в отдельной переменной фиксировать count=OrdersTotal(), а после уже использовать цикл for(i=0;i<count;i++)

Зато второй вариант перебора с конца работает 100%.

А я голову ломал :)

Спасибо.

P.S. Вдогонку дополнение.

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

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