Организация цикла перебора ордеров - страница 5

 
Vasiliy Sokolov:

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

Вместо зацикливания, нужно наоборот, стараться как можно быстрее завершить пользовательский поток. Если так хочется держать "руку на пульсе" - анализируйте OnTradeTransaction в МТ5. МТ4 вообще плохо для таких вывертов подходит, ибо простота как говориться хуже воровства. 

Речь шла не о конкретной реализации, а о принципе перетряхивания ТС после любой паузы. Ну и где там страшное зацикливание - не ясно. Как и непонятно, зачем торопиться завершать пользовательский поток.

 
fxsaber:

Ну и где там страшное зацикливание - не ясно.

Вызов OnTick из OnTick - нетривиальное зацикливание через рекурсию:

// Редкий, но правильный костяк модификации ордеров
for (int i = OrdersTotal() - 1; i >= 0; i--)
  if (OrderSelect(i, SELECT_BY_POS))
    if (OrderModify(OrderTicket(), Price, SL, TP, OrderExpiration()))     
    {
      i = OrdersTotal(); // Хотя бы так
      
      // А лучше так
      // OnTick(); break; // вместо строки выше лучше делать такой вызов (переполнения стека от рекурсивных вызовов быть не должно)
    }

Как и непонятно, зачем торопиться завершать пользовательский поток.

Мы работаем с событийной моделью. Следовательно, нужно как можно быстрее обработать текущее событие, что бы перейти в режим ожидания следующего. Время проведенное в потоке - это черная дыра. Чем больше времени мы проводим в потоке, тем более устаревшее торговое окружение с которым мы работаем.

 
Vasiliy Sokolov:

Вызов OnTick из OnTick - нетривиальное зацикливание через рекурсию:

Видимо, только это отпугивает.

Мы работаем с событийной моделью. Следовательно, нужно как можно быстрее обработать текущее событие, что бы перейти в режим ожидания следующего. Время проведенное в потоке - это черная дыра. Чем больше времени мы проводим в потоке, тем более устаревшее торговое окружение с которым мы работаем.

Ну это же неправда!
 
:
void OnTick()
{
   for(int i = 0; i < symbols.Total(); i++)
   {
      request.symbol = symbols.At(i); 
      OrderSendAsynch(request, result); // Начиная с этой строки, анализировать торговое окружение в текущем потоке не имеет смысла
                                        // Единственная верная стратегия - как можно быстрее завершить цикл, и выйти из OnTick
                                        // Для дальнейшего анализа например в OnTransaction
   }
}

з.ы. Вообще мы друг друга категорически не понимаем. Я не думаю, что между нами может получиться какой-либо диалог.

 
Vasiliy Sokolov:
:

Где Вы в своем коде увидели паузу, только наличие которой является причиной перетряхивания ТС с нуля? Ее у Вас нет!

 
fxsaber:

Где Вы в своем коде увидели паузу, только наличие которой является причиной перетряхивания ТС с нуля? Ее у Вас нет!

Так данный код и является иллюстрацией того, почему текущий поток нужно завершить как можно быстрее. Нельзя даже пытаться запрашивать торговое окружение в OnTick:

void OnTick()
{
   for(int i = 0; i < symbols.Total(); i++)
   {
      request.symbol = symbols.At(i); 
      OrderSendAsynch(request, result); // Начиная с этой строки, анализировать торговое окружение в текущем потоке не имеет смысла
                                        // Единственная верная стратегия - как можно быстрее завершить цикл, и выйти из OnTick
                                        // Для дальнейшего анализа например в OnTransaction      
   }
   // Далее торговое окружение начинает меняться. Мы не можем анализировать его в OnTick
   // Бессмысленно зацикливать OnTick дальше.
   // Результат работы этого кода будет неопределен
   Sleep(50);
   int total_1 = OrdersTotal();
   Sleep(50);
   int total_2 = OrdersTotal();
   //Результат операции не определен
   if(total_1 == total_2)
}

Находясь в точке сравнения двух переменных, мы не можем их сравнивать, т.к. окружение продолжает меняться. Значения в total_1 и total_2 уже либо не равны друг другу, либо устарели оба, либо они содержат не существующее количество ордеров, либо содержат правильные значения. Бессмысленно бороться с меняющимся торговым окружением в OnTick, вместо этого нужно простой выйти из OnTick, сразу после цикла for, и ждать новых событий, указывающих об изменении торгового окружения.

 
Vasiliy Sokolov:

Так данный код и является иллюстрацией того, почему текущий поток нужно завершить как можно быстрее. Нельзя даже пытаться запрашивать торговое окружение в OnTick:

Находясь в точке сравнения двух переменных, мы не можем их сравнивать, т.к. окружение продолжает меняться. Значения в total_1 и total_2 уже либо не равны друг другу, либо устарели оба, либо они содержат не существующее количество ордеров, либо содержат правильные значения. Бессмысленно бороться с меняющимся торговым окружением в OnTick, вместо этого нужно простой выйти из OnTick, сразу после цикла for, и ждать новых событий, указывающих об изменении торгового окружения.

Так зачем паузы наставили?!


Еще раз, после любой паузы (слипы или синхронные торговые приказы) ТС должна перетряхиваться - торговая логика запускаться с нуля. Соответственно, если используются асинхронные торговые приказы, то упомянутых пауз не происходит и идет выход из Event-функции с ожиданием нового события. Если же асинхронных операций нет, то всю торговую логику можно даже засунуть в зацикленный скрипт.

 
fxsaber:

Так зачем паузы наставили?!

Еще раз, после любой паузы (слипы или синхронные торговые приказы) ТС должна перетряхиваться - торговая логика запускаться с нуля. Соответственно, если используются асинхронные торговые приказы, то упомянутых пауз не происходит и идет выход из Event-функции с ожиданием нового события. Если же асинхронных операций нет, то всю торговую логику можно даже засунуть в зацикленный скрипт.

Я Вам про Фому, Вы мне про Ерёму. Короче завершим наш диалог. Создавайте дальше свои зацикленные скрипты. Да, это действительно работает, но рекомендовать это как прием работы категорически нельзя.

 

Интересно мнение бывалых на такую ситуацию в MT4, как кто ее разруливает?


ТЗ советника -  на каждом тике держать отложенники и тэйки открытых позиций на каком-то фиксированном расстоянии от текущей цены.


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


Итак, бежим в обратном цикле (в сторону убывания индекса SELECT_BY_POS) и делаем соответствующие OrderModify.


Так вот во время этого цикла, запиханного в OnTick, может произойти следующее

  1. OrdersTotal может увеличиться (руками, например, открыл или частичные исполение (partial fillings)).
  2. Произойти переиндексация отложенников и позиций (например, какой-то отложенник исполнился во время цикла или некоторые отложенники были руками удалены, а некоторые выставлены на машине с коротким пингом).
  3. 1-й или 2-й пункт, но ошибки OrderSelect и OrderModify не происходит. Просто во время цикла из-за п.1/2 некоторые ордера/позиции окажутся пропущенными.

Как быть?

Вопрос косвенно касается дискуссии выше, но это не для ее продолжения (тема закрыта). Мне нужно решить некоторые не очевидные нюансы в MT4Orders для MT5. Поэтому полезно будет услышать мнение на описанные ситуации от тех, кто хорошо владеет именно MT4. Ну и не мне одному, наверное, это будет полезно.


Решить вопрос через OnTimer - это, наверное, сразу предложат. Но давайте без него - только OnTick.

 
fxsaber:

Интересно мнение бывалых на такую ситуацию в MT4, как кто ее разруливает?


ТЗ советника -  на каждом тике держать отложенники и тэйки открытых позиций на каком-то фиксированном расстоянии от текущей цены.


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


Итак, бежим в обратном цикле (в сторону убывания индекса SELECT_BY_POS) и делаем соответствующие OrderModify.


Так вот во время этого цикла, запиханного в OnTick, может произойти следующее

  1. OrdersTotal может увеличиться (руками, например, открыл или частичные исполение (partial fillings)).
  2. Произойти переиндексация отложенников и позиций (например, какой-то отложенник исполнился во время цикла или некоторые отложенники были руками удалены, а некоторые выставлены на машине с коротким пингом).
  3. 1-й или 2-й пункт, но ошибки OrderSelect и OrderModify не происходит. Просто во время цикла из-за п.1/2 некоторые ордера/позиции окажутся пропущенными.

Как быть?

Вопрос косвенно касается дискуссии выше, но это не для ее продолжения (тема закрыта). Мне нужно решить некоторые не очевидные нюансы в MT4Orders для MT5. Поэтому полезно будет услышать мнение на описанные ситуации от тех, кто хорошо владеет именно MT4. Ну и не мне одному, наверное, это будет полезно.


Решить вопрос через OnTimer - это, наверное, сразу предложат. Но давайте без него - только OnTick.

Во-первых, ситуация представлена нестандартная и мало кто эту ситуацию уже разруливал, если вообще есть такие.

Чисто теоретически:

Для OrderModify организовывать обратный цикл не обязательно, поэтому пусть будет прямой

int i, total = OrdersTotal();
for(i = 0; i < total; i++)

И дальше поставить проверку на изменение списка ордеров

if(total != OrdersTotal())
 {
  i = 0;
  total = OrdersTotal();
  continue;
 }

Если произошло изменение количества, начнём цикл заново с новым количеством ордеров.

И ещё вопрос:

fxsaber:

  1. OrdersTotal может увеличиться (руками, например, открыл или частичные исполение (partial fillings)).
  2. Произойти переиндексация отложенников и позиций (например, какой-то отложенник исполнился во время цикла или некоторые отложенники были руками удалены, а некоторые выставлены на машине с коротким пингом).
  3. 1-й или 2-й пункт, но ошибки OrderSelect и OrderModify не происходит. Просто во время цикла из-за п.1/2 некоторые ордера/позиции окажутся пропущенными.

Понятно, что если были добавлены, то они или другие будут пропущены. А если просто были удалены??? Не получится выход за границы списка ордеров?