OrdersTotal( ) как заставить его работать в MQL5? - страница 2

 
Renat:

Параметр sy зря в автозаполнение поставили - при нем результат будет заведомо отрицательный.

Вообще код лучше вот так переделать - быстрее работать будет:


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

Urain:

Опятьже для меня остался непонятным момент что произойдёт если выставленны одновременно несколько ордеров,

как будет это отрабатываться в OnTrade()?

OrdersTotal() будет > 1, также и HistoryDealsTotal()  при последовательных вызовах QnTrade() может меняться на на величину > 1.

Без учёта отложников.

 
Renat:

Вы неправильно поняли таймаут в параметре функции PositionSelect. Там не задержка, а именно таймаут ожидания разблокировки/обновления торговой базы.

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

А если это займет N+1 секунду?

Может лучше дождаться хоть какого то  ответа на первый запрос (принят\не принят, установлен\не установлен) и уж потом, либо повторять либо нет.

Выбрать что то конкретное из этого

struct MqlTradeResult
  {
   uint     retcode;          // Код результата операции
   ...
  };


10004 TRADE_RETCODE_REQUOTE Реквота
10006 TRADE_RETCODE_REJECT Запрос отвергнут
10007 TRADE_RETCODE_CANCEL Запрос отменен трейдером
10008 TRADE_RETCODE_PLACED Ордер размещен
10009 TRADE_RETCODE_DONE Заявка выполнена
10010 TRADE_RETCODE_DONE_PARTIAL Заявка выполнена частично

и т.д.

 

 
SHOOTER777:

А если это займет N+1 секунду?

Может лучше дождаться хоть какого то  ответа на первый запрос (принят\не принят, установлен\не установлен) и уж потом, либо повторять либо нет.

Выбрать что то конкретное из этого 

дожидаться вроде не вариант. событие void OnTick() прервет его и вроде еще ограничение есть в 2.5 секунды, больше выполняться не может. будет прерывание.  хотя я в этом неуверен. но что то такое было
 
Prival:

очень непонятно тогда справка написана, прочитав её, считал, что я задерживаю все опрерации на 100 милисекунд, т.е. жду это время и пытаюсь выбрать позицию, не появилась позиция в течении этого времени, значит её нет.

Когда Вы запрашиваете состояние позиции, торговая база терминала может быть в необновленном состоянии (например, при раннем старте или реконнекте к счету) и тогда значение таймаута даст вам время подождать обновления данных.

Значение в 100 миллисекунд конечно мало, разумно ставить секунды 3. В 99.9% случаев ответ будет выдаваться мгновенно без задержек, но при реконнектах подождать 3 (в максимуме) имеет смысл.

 
Prival:
дожидаться вроде не вариант. событие void OnTick() прервет его и вроде еще ограничение есть в 2.5 секунды, больше выполняться не может. будет прерывание.  хотя я в этом неуверен. но что то такое было

 

 Ну не знаю... Все же верным решением было бы обрабатывать  MqlTradeResult
 Пока в справке про поведение void OnTick() подробно не расписано, но вот аналог из MQL4 функции start()

При поступлении новых котировок выполняется функция start() у присоединенных советников и пользовательских индикаторов. 
Если при поступлении новой котировки выполнялась функция start(), запущенная на предыдущей котировке, то пришедшая котировка будет проигнорирована советником. 
Все пришедшие во время выполнения программы новые котировки программой игнорируются до тех пор, пока не завершится очередное выполнение функции start().  

А про 99,9% думаю так) 

Профессионализм людей, совершенные технологии и выверенные инструкции  делают столкновения самолетов в воздухе практически невозможными. На уровне 1 на сто миллионов.

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

 
Renat:

Параметр sy зря в автозаполнение поставили - при нем результат будет заведомо отрицательный.

Вообще код лучше вот так переделать - быстрее работать будет:

bool WhetherIsPosition(string sy, ENUM_POSITION_TYPE op=-1, int mn=-1) 
  {
   bool rez=false;         // результат запроса 
    
   if(PositionSelect(sy,100))                                  // есть открытая позиция
     {
      if(op== -1 || PositionGetInteger(POSITION_TYPE) == op)     // проверка типа
        {
         if(mn== -1 || PositionGetInteger(POSITION_MAGIC) == mn) // проверка магика
            rez=true; 
         }
     } 
 
   return(rez); 
  }

Имеется ввиду, что для случаев op == -1 и mn == -1 PositionGetInteger() вызываться не будет?

А в документации сказано, что Логические выражения вычисляются полностью, т.е., к ним не применяется схема так называемой "короткой оценки".

 
Prival:

Это торговый блок.

Lots=0.1;
         if(WhetherIsPosition(sy,POSITION_TYPE_BUY,Magic)) Lots*=2;
         if(!WhetherIsPosition(sy,POSITION_TYPE_SELL,Magic))
           {
            OpenPosition(sy,ORDER_TYPE_SELL,Lots,sl,tp,Magic);
           }

 т.е. если есть открытая позиция бай, я удваиваю лот и переворачиваюсь в селл (для бай логика наоборот). если есть уже открытая позиция то я ничего не делаю. По идее в рынке должна быть позиция только 0.1 лота. 

но однажды у меня появился лот 0.2 (просто висел на демо счете советник, не в тестере). я долго анализировал и пришол к выводу, что сервер принял команду, но её еще не успел выполнить польностью, как пришол новый тик, и раз открытых позиций нет пошла команда открыть  позицию,  и эти приказы выполнились последовательно.

на чемпионате это дисквалификация 

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

З.Ы. спасибо за замечания и  правку кода

Однако, функция WhetherIsPosition() возвращает false не только в случае отсутствия позиции, но и в случае ошибки при вызове функции PositionSelect().

Теперь, учитывая вышесказанное, предположим, что открыта позиция SELL 0.1 лота. Далее, предположим также, что приходит тик, логика эксперта вызывает торговый блок, однако, при вызове PositionSelect() из WhetherIsPosition() всё время возникает ошибка, и поэтому последняя всё время возвращает false.

Тогда при выполнении

if(WhetherIsPosition(sy,POSITION_TYPE_BUY,Magic)) Lots*=2;

удвоения переменной Lots не произойдёт. А при последующем выполнении

if(!WhetherIsPosition(sy,POSITION_TYPE_SELL,Magic))

тип позиции ошибочно будет определён как "НЕ являющаяся SELL" (хотя она по условиям вначале рассуждений - как раз SELL), и будет произведена "доливка" к позиции ещё 0.1 лота. В результате общий объём позиции станет 0.2 лота.

Также могут возникнуть ошибки логики работы эксперта, связанные с тем, что один раз функция WhetherIsPosition() может вернуть одно, а при другом её вызове - другое. Поэтому имеет смысл вызывать функцию один раз, запоминать возвращённое значение в переменной и использовать в дальнейшей обработке лишь эту переменную (в логически связном блоке, а не вообще; то есть, чтобы логика блока, рассчитанная на непротиворечивость значений, возвращаемых функцией, не "рвалась").

Имеет смысл изменить "дизайн" функции, чтобы можно было обрабатывать ошибки в стиле C (для стиля C++ нужен механизм исключений, но в MQL5 он отсутствует). Например:

enum MY_POS_TYPE {                        /* Наше "личное" перечисление  */
  MY_POS_TYPE_NONE,                       /* Нет позиции                 */
  MY_POS_TYPE_BUY, MY_POS_TYPE_SELL,      /* Реальный тип позиции        */
  MY_POS_TYPE_TO_ERR, MY_POS_TYPE_GEN_ERR /* Ошибка (timeout или другая) */
};

MY_POS_TYPE GetPositionType(string sy, int mn = -1, uint to = 3000) 
{
  if(!PositionSelect(sy, to))
    return GetLastError() == ERR_TRADE_SELECT_TIMEOUT ?
             MY_POS_TYPE_TO_ERR : /* Timeout error */
             MY_POS_TYPE_GEN_ERR; /* General error */

  /* Здесь используется ?: вместо || с целью эмуляции схемы "короткой оценки":
     PositionGetInteger(POSITION_MAGIC) вычисляется лишь тогда, когда mn != 1
     ("короткую оценку" для логики, наверное, лишь в MQL6 сделают) */
  if(mn == -1 ? true : PositionGetInteger(POSITION_MAGIC) == mn)
    return PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY ?
             MY_POS_TYPE_BUY :      /* Обнаружена POSITION_TYPE_BUY  */
             PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL ?
               MY_POS_TYPE_SELL :   /* Обнаружена POSITION_TYPE_SELL */
               MY_POS_TYPE_GEN_ERR; /* Общая ошибка (НЕ timeout)     */

  return MY_POS_TYPE_NONE; /* Позиции с указзаным MAGIC не обнаружено */
}

void TradingPart(string sy, int Magic)
{
  double      Lots    = 0.1;
  MY_POS_TYPE PosType = GetPositionType(sy, Magic); /* Вызывается один раз */
  int         sl;
  int         tp;

  switch(PosType)
  {
  case MY_POS_TYPE_BUY:
  case MY_POS_TYPE_SELL:
    Lots *= 2; /* Переворот позиции (кроме случая MY_POS_TYPE_NONE) */
    break;
  case MY_POS_TYPE_GEN_ERR:
  case MY_POS_TYPE_TO_ERR:
    Print("Error!!!");
    return; /* В случае ошибки выходим и не пытаемся с позициями работать */
  }

  /* Вычисляем sl и tp... */

  /* Работа с позициями (при отсутствии позиции будет открыт одинарный SELL) */
  OpenPosition(sy,
               PosType != MY_POS_TYPE_SELL ?
                 ORDER_TYPE_SELL :
                 ORDER_TYPE_BUY,
               Lots,
               sl,
               tp,
               Magic);
}

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

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

 
simpleton:

Имеется ввиду, что для случаев op == -1 и mn == -1 PositionGetInteger() вызываться не будет?

А в документации сказано, что Логические выражения вычисляются полностью, т.е., к ним не применяется схема так называемой "короткой оценки".

В MQL5 документацию по ошибке перекочевала фраза из MQL4 - обязательно исправим.

В MQL5 выражения вычисляются правильно - по короткой схеме. 

 
simpleton:

Имеется ввиду, что для случаев op == -1 и mn == -1 PositionGetInteger() вызываться не будет?

А в документации сказано, что Логические выражения вычисляются полностью, т.е., к ним не применяется схема так называемой "короткой оценки".

Это ошибка документирования. На самом деле логические операции вычисляются по схеме "короткой оценки". Описание будет исправлено и добавлены примеры. Спасибо за сообщение.