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

 
Alexey Viktorov:

Неужели я так сложно намекнул? ДЦ зарабатывает на спредах и комиссиях, программист зарабатывает на написании кода.

Один из трейдеров говорит что надо экономить на спредах и комиссиях (по возможности не платить).

Другой из трейдеров говорит что писать код за деньги не справедливо (по возможности не платить).

И тот и другой заботятся о своём кошельке. Вроде-бы они и не отличаются друг от друга...

Только вот вы, как программист, первого поддерживаете, а со вторым спорите доказывая что он неправ.

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

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

 
Andrey Khatimlianskii:

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

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

Прекрасно. А я почему-то больше понимаю ваше нежелание писать бесплатно. И тоже никаких проблем...

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

 
Alexey Viktorov:

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

Если посчитать, не такой и маразм. Но у меня нет цели убедить.

 
Andrey Khatimlianskii:

Если посчитать, не такой и маразм. Но у меня нет цели убедить.

Считать нужно прибыль, а не расходы.

При экономии расходов, очень легко получать убытки. Если ТС рассчитана нести расходы, но при этом даёт доход, то это хорошая ТС, потому как при другом раскладе, может приносить убыток.

Да и вообще, победителей не судят!

 

А нельзя ли с 7 по текущую страницу выделить в отдельную тему (можно даже дать на неё ссылку типа "Дальнейшее обсуждение здесь"), а в этой теме продолжить то, для чего она создана?

 
Vitaly Muzichenko:

Считать нужно прибыль, а не расходы.

При экономии расходов, очень легко получать убытки. Если ТС рассчитана нести расходы, но при этом даёт доход, то это хорошая ТС, потому как при другом раскладе, может приносить убыток.

Да и вообще, победителей не судят!

Не могу уловить, о чем этот комментарий.

О неважности размера комиссии для супер-прибыльных стратегий?

 
Запустим на MT4 EURUSD такой советник
// В случае изменения количества ордеров по основному символу, сигнализирует об их количестве

// #include <MT4Orders.mqh>

const bool Init =  EventSetMillisecondTimer(1);

int AmountOrders( const string &Symb )
{
  int Res = 0;
  
  for (int i = OrdersTotal() - 1; i >= 0; i--)
    if (OrderSelect(i, SELECT_BY_POS) && (OrderSymbol() == Symb))
      Res++;
      
  return(Res);
}

void OnTimer()
{
  static int PrevAmount = 0;
  
  const int Amount = AmountOrders(_Symbol);
  
  if (Amount != PrevAmount)
  {
    PrevAmount = Amount;
    
    Alert(Amount);
  }    
}


Откроем произвольно 5 ордеров по EURUSD и 5 ордеров по USDJPY.  А теперь взглянем внимательно на безобидный код AmountOrders и представим себе такой сценарий

  1. Находимся во время выполнения советника внутри AmountOrders, где i == 3.
  2. Закрываем позицию по USDJPY. После чего идет перетряхивание ордеров в таблице текущих.
  3. Из-за перетряхивания при i == 2 через OrderSelect мы может нарваться на тот же ордер, что был в п.1. Из-за этого AmountOrders может вернуть значение на единицу больше, чем на самом деле.


А вот и подтверждение сказанному

#property strict

void OnStart()
{
  for (int i = 0; i < 5; i++)
    OrderSend(_Symbol, OP_BUY, 1, Ask, 100, 0, 0);
    
  int PrevTicket = 0;
  
  for (int i = OrdersTotal() - 1; i > 0; i--)
    if (OrderSelect(i, SELECT_BY_POS))
    {
      const int Ticket = OrderTicket();
      
      if (Ticket == PrevTicket)
        Alert("Hello World!");
        
      PrevTicket = Ticket;
      
      if (OrderSelect(i - 1, SELECT_BY_POS))      
        OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), 100);
    }
}


Результат

2017.10.06 01:28:05.885 TestTets EURUSD,M1: close #240725107 buy 1.00 EURUSD at 1.17121 at price 1.17099
2017.10.06 01:28:05.775 TestTets EURUSD,M1: Alert: Hello World!
2017.10.06 01:28:05.775 TestTets EURUSD,M1: close #240725108 buy 1.00 EURUSD at 1.17121 at price 1.17099
2017.10.06 01:28:05.673 TestTets EURUSD,M1: Alert: Hello World!
2017.10.06 01:28:05.673 TestTets EURUSD,M1: close #240725110 buy 1.00 EURUSD at 1.17121 at price 1.17099
2017.10.06 01:28:05.578 TestTets EURUSD,M1: Alert: Hello World!
2017.10.06 01:28:05.578 TestTets EURUSD,M1: close #240725111 buy 1.00 EURUSD at 1.17121 at price 1.17099
2017.10.06 01:28:05.480 TestTets EURUSD,M1: open #240725112 buy 1.00 EURUSD at 1.17121 ok
2017.10.06 01:28:05.343 TestTets EURUSD,M1: open #240725111 buy 1.00 EURUSD at 1.17121 ok
2017.10.06 01:28:05.253 TestTets EURUSD,M1: open #240725110 buy 1.00 EURUSD at 1.17121 ok
2017.10.06 01:28:05.138 TestTets EURUSD,M1: open #240725108 buy 1.00 EURUSD at 1.17121 ok
2017.10.06 01:28:05.035 TestTets EURUSD,M1: open #240725107 buy 1.00 EURUSD at 1.17121 ok


Один и тот же тикет может выбраться дважды в безобидном цикле подсчета ордеров!

Совершение сделок - Торговые операции - Справка по MetaTrader 5
Совершение сделок - Торговые операции - Справка по MetaTrader 5
  • www.metatrader5.com
Торговая деятельность в платформе связана с формированием и отсылкой рыночных и отложенных ордеров для исполнения брокером, а также с управлением текущими позициями путем их модификации или закрытия. Платформа позволяет удобно просматривать торговую историю на счете, настраивать оповещения о событиях на рынке и многое другое. Открытие позиций...
 
fxsaber:

Один и тот же тикет может выбраться дважды в безобидном цикле подсчета ордеров!

Чтобы все сомнения отбросить, делаем так.

Ставим советник

// Советник будет алертовать, если OrderSelect соседних индексов выберет один и тот же ордер
const bool Init =  EventSetMillisecondTimer(1);

void OnTimer()
{
  int PrevTicket = 0;
  
  for (int i = OrdersTotal() - 1; i >= 0; i--)
    if (OrderSelect(i, SELECT_BY_POS))
    {
      const int Ticket = OrderTicket();
      
      if (Ticket == PrevTicket)
        Alert("Hello World!");
        
      PrevTicket = Ticket;
      
      Sleep(1); // 1 миллисекунда - это много или мало?
    }
}


Запускаем скрипт

#property strict

void OnStart()
{
  // Открыли позиции
  for (int i = 0; i < 25; i++)
    OrderSend(_Symbol, OP_BUY, 1, SymbolInfoDouble(_Symbol, SYMBOL_ASK), 100, 0, 0);

  int Tickets[];
  const int Total = OrdersTotal();
  
  ArrayResize(Tickets, Total);
  
  for (int i = 0; i < Total; i++)
    if (OrderSelect(i, SELECT_BY_POS))
      Tickets[i] = OrderTicket();
    
  // Закрыли позиции
  for (int i = 0; i < Total; i++)
    OrderClose(Tickets[i], 1, SymbolInfoDouble(_Symbol, SYMBOL_BID), 100);
}


И наблюдаем, как советник под разными индексами выбирает один и те же ордера. А это может привести к полному выходу из строя торговой логики.

 
fxsaber:

советник под разными индексами выбирает один и те же ордера. А это может привести к полному выходу из строя торговой логики.

Ну и собственно сабж во всей красе! Как организовать цикл перебора ордеров? Например, как правильно написать такую функцию?

// Возращает количество ордеров данного символа
int AmountOrders( const string &Symb )
{
  int Res = 0;
  
  for (int i = OrdersTotal() - 1; i >= 0; i--)
    if (OrderSelect(i, SELECT_BY_POS) && (OrderSymbol() == Symb))
      Res++;
      
  return(Res);
}


Ветка начиналась с озвучивания необходимости некоторых повторных действий, когда происходит пауза внутри цикла переборов. Здесь достаточно паузы в районе миллисекунды, чтобы увидеть эффект.

Пока такой костыль

bool IsChange( const bool InitFlag = false )
{
  static int PrevTotal = 0;
  static int PrevHistoryTotal = 0;
  
  const int Total = OrdersTotal();
  const int HistoryTotal = OrdersHistoryTotal();    
  
  if (InitFlag)
  {
    PrevTotal = Total;
    PrevHistoryTotal = HistoryTotal;    
  }
  
  return(!InitFlag && ((Total != PrevTotal) || (HistoryTotal != PrevHistoryTotal)));
}

// Возращает количество ордеров данного символа
int AmountOrders( const string &Symb )
{
  int Res = 0;
  
  IsChange(true);
  
  for (int i = OrdersTotal() - 1; i >= 0; i--)
    if (IsChange())
    {
      i = OrdersTotal();
      
      Res = 0;
    }
    else if (OrderSelect(i, SELECT_BY_POS) && (OrderSymbol() == Symb))
      Res++;
      
  return(Res);
}

Но нет уверенности, что всегда будет работать правильно.

 
fxsaber:

Чтобы все сомнения отбросить, делаем так.

Ставим советник

Запускаем скрипт

И наблюдаем, как советник под разными индексами выбирает один и те же ордера. А это может привести к полному выходу из строя торговой логики.

Изменил

// Советник будет алертовать, если OrderSelect соседних индексов выберет один и тот же ордер
const bool Init =  EventSetMillisecondTimer(1);

bool IsChange( const bool InitFlag = false )
{
  static int PrevTotal = 0;
  static int PrevHistoryTotal = 0;
  
  const int Total = OrdersTotal();
  const int HistoryTotal = OrdersHistoryTotal();    
  
  if (InitFlag)
  {
    PrevTotal = Total;
    PrevHistoryTotal = HistoryTotal;    
  }
  
  return(!InitFlag && ((Total != PrevTotal) || (HistoryTotal != PrevHistoryTotal)));
}

void OnTimer()
{
  int PrevTicket = 0;
  
  IsChange(true);
  
  for (int i = OrdersTotal() - 1; i >= 0; i--)
    if (IsChange())
    {
      i = OrdersTotal();
      
      PrevTicket = 0;
    }
    
    else if (OrderSelect(i, SELECT_BY_POS))
    {
      const int Ticket = OrderTicket();
      
      if (Ticket == PrevTicket)
        Alert("Hello World!");
        
      PrevTicket = Ticket;
      
      Sleep(1); // 1 миллисекунда - это много или мало?
    }
}

Теперь без алертов.

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