Реквоты в тестере - что такое и как бороться? - страница 2

 
marketeer:
По исходнику можете посмотреть, что реквоты обрабатываются правильно - по крайней мере аналогичным образом, как в других пятерочных исходниках. После первой ошибки реквоты поступают новые цены, они подставляются в следующий запрос, но ошибка остается. Причем при всех последующих попытках рефреш возвращает уже одни и те же цены. Количество попыток не важно - можно пытаться отрефрешиться до бесконечности. Очень похоже на баг в тестере.

Очень похоже на баг в программе. Бегло просмотрел, по моему она находится здесь:

switch(cmd)
  {
    case OP_BUY:
      request.type = ORDER_TYPE_BUY;
    case OP_SELL:
      request.type = ORDER_TYPE_SELL;
      request.action = TRADE_ACTION_DEAL;
      break;
    case OP_BUYLIMIT:
      request.type = ORDER_TYPE_BUY_LIMIT;
    case OP_SELLLIMIT:
      request.type = ORDER_TYPE_SELL_LIMIT;
    case OP_BUYSTOP:
      request.type = ORDER_TYPE_BUY_STOP;
    case OP_SELLSTOP:
      request.type = ORDER_TYPE_SELL_STOP;
      request.action = TRADE_ACTION_PENDING;
      break;
  }
  

Ордера на покупку переквалифицируются как ордера на продажу, так как за оператором case: OP_BUY тут же выполняется case: OP_SELL_. Это же видно и из лога: устанавливается ордер OP_SELL,

а цена берётся ask.

Это же касается и отложенных ордеров.
 

 
Да, для каждого case нужен свой break. https://www.mql5.com/ru/docs/basis/operators/switch
Документация по MQL5: Основы языка / Операторы / Оператор-переключатель switch
Документация по MQL5: Основы языка / Операторы / Оператор-переключатель switch
  • www.mql5.com
Основы языка / Операторы / Оператор-переключатель switch - Документация по MQL5
 
Rosh:
Да, для каждого case нужен свой break. https://www.mql5.com/ru/docs/basis/operators/switch

Супер. Спасибо всем за помощь. Был невнимателен в новом фрагменте кода.

А что относительно доп. вопросов? Есть для них ответы?

 
marketeer:

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

Терминал еще будет дорабатываться, мы только выпустили платформу. Все разумное и полезное будет добавляться.
 
marketeer:

Дополнительные вопросы. 1) В библиотеке делается попытка получить идентификатор сделки для только что открытой позиции из result.deal, но там почему-то всегда ноль. Нужно это, чтобы в идущем следом вызове HistoryDealGetInteger(result.deal, DEAL_POSITION_ID, LID); получить идентификатор самой позиции. В общем, вопрос - как получить id позиции, "не отходя от кассы"?

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

//+------------------------------------------------------------------+
//|                            Check_DEAL_POSITION_ID_after_Open.mq5 |
//|                        Copyright 2010, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2010, MetaQuotes Software Corp."
#property link      "http://www.mql5.com"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---

//---
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---

  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   static bool opened=false;

   if(!opened)
     {
      MqlTick tick;
      if(SymbolInfoTick(Symbol(),tick));
      MqlTradeRequest request;
      request.symbol=Symbol();
      request.type=ORDER_TYPE_BUY; //ORDER_TYPE_BUY; //cmd; // ВОТ ЗДЕСЬ !!!
      request.volume=0.1;
      request.price=tick.ask;
      request.deviation=50;
      request.sl=0;
      request.tp=0;
      request.action=TRADE_ACTION_DEAL;
      request.order=0;
      request.comment="Test";

      MqlTradeResult result;
      if(OrderSend(request,result))
        {
         long posID=-1;
         int counter=0;
         ResetLastError();

         //--- пытаемся выбрать позицию с интервалом в 50 миллисекунд
         while(!PositionSelect(Symbol()) && !IsStopped())
           {
            counter++;
            bool stopped=IsStopped();
            //--- выведем текущее состояние
            Print(counter,": positions=",PositionsTotal(),"   error=",GetLastError(),"    IsStopped()=",stopped);
            //--- больше 100 попыток делать бессмысленно
            if(counter>100) break;
            ResetLastError();
            //--- заснем на 50 миллисекунд
            Sleep(50);
           }
         //--- будем считать, что позиция выбрана успешно - теперь можно получить ID розиции
         PositionGetInteger(POSITION_IDENTIFIER,posID);
         Print("posID=",posID);
         opened=true;
        }
      else
        {
         Print("Не удалось совершить покупку. Код ответа=",result.retcode,",   Ошибка ",GetLastError());
        }
     }

  }
//+------------------------------------------------------------------+
 

Вторй вариант - запросить ID позиции, к которой относится сделка. Выглядит чуть короче, но желательно все равно проверять результат выполнения HistoryDealSelect():


//+------------------------------------------------------------------+
//|                            Check_DEAL_POSITION_ID_after_Open.mq5 |
//|                        Copyright 2010, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2010, MetaQuotes Software Corp."
#property link      "http://www.mql5.com"
#property version   "1.00"

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   static bool opened=false;

   if(!opened)
     {
      MqlTick tick;
      if(SymbolInfoTick(Symbol(),tick));
      MqlTradeRequest request;
      request.symbol=Symbol();
      request.type=ORDER_TYPE_BUY; //ORDER_TYPE_BUY; //cmd; // ВОТ ЗДЕСЬ !!!
      request.volume=0.1;
      request.price=tick.ask;
      request.deviation=50;
      request.sl=0;
      request.tp=0;
      request.action=TRADE_ACTION_DEAL;
      request.order=0;
      request.comment="Test";

      MqlTradeResult result;
      if(OrderSend(request,result))
        {
         long posID=-1;
         ResetLastError();
         ulong deal=result.deal;
         //--- запросим всю историю 
         HistorySelect(0,TimeCurrent());
         HistoryDealSelect(deal);
         HistoryDealGetInteger(deal,DEAL_POSITION_ID,posID);
         Print("posID=",posID);
         opened=true;
        }
      else
        {
         Print("Не удалось совершить покупку. Код ответа=",result.retcode,",   Ошибка ",GetLastError());
        }
     }

  }
//+------------------------------------------------------------------+
 
Я сделал проверку в небольшом цикле по первому варианту, потому что этот второй вроде бы не работает - result.deal равно нулю после OrderSend. Соответственно HistoryDealSelect ничего не выделит. Попутно возникает принципиальный вопрос, зачем вызывать HistoryDealSelect, если в HistoryDealGetInteger явным образом указывается тот же самый id сделки?
Документация по MQL5: Торговые функции / HistoryDealSelect
Документация по MQL5: Торговые функции / HistoryDealSelect
  • www.mql5.com
Торговые функции / HistoryDealSelect - Документация по MQL5
 
Rosh:

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

Вот этот кусочек очень интересен:

if(SymbolInfoTick(Symbol(),tick));

Для чего здесь "if"?

Далее, если SymbolInfoTick() завершится неуспешно, - какой смысл в последующем присваивании мусора (ведь изначально переменная tick неинициализирована)?

request.price=tick.ask;

Какой смысл в последующем вызове OrderSend(), если ей передаются ошибочные данные (тот самый мусор)?

Хорошо, если это исправить, то - какой смысл 100 раз крутить цикл, вызывая PositionSelect() и выполняя задержку в 50 мс, если в документации на данный момент сказано:

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

Да, поведение функции не так давно было изменено, и, возможно, Вы на этом попались. Но если уж даже Вы попались, то каково же пользователям?

И в довершение, Вы в своём коде, который многие стараются брать за образец (как же, - код от разработчиков!), вставляете комментарии вида:

//--- будем считать, что позиция выбрана успешно - теперь можно получить ID розиции

А ведь совсем несложно было грамотно написать этот пример, чтобы не надо было "считать", а можно было бы в это месте, в случае, если до него дойдёт управление, иметь гарантию успешного выбора позиции, а не "будем считать".

Я нисколько не удивлён таким примером, потому что, очень похоже, что и сам MT5 пишется в подобном стиле, - а именно такой подход к программированию и даёт то качество, которое сейчас имеет и MT5.

Документация по MQL5: Торговые функции / PositionSelect
Документация по MQL5: Торговые функции / PositionSelect
  • www.mql5.com
Торговые функции / PositionSelect - Документация по MQL5
 
simpleton:

Хорошо, если это исправить, то - какой смысл 100 раз крутить цикл, вызывая PositionSelect() и выполняя задержку в 50 мс, если в документации на данный момент сказано:

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

Да, поведение функции не так давно было изменено, и, возможно, Вы на этом попались. Но если уж даже Вы попались, то каково же пользователям?


Таймауты для торговых функций были убраны (https://www.mql5.com/ru/forum/23/page7):

MetaTrader 5 Client Terminal build 306

  1. Terminal: При запуске терминала с ключом /config конфигурационный файл открывается только на чтение.
  2. Terminal: Исправлено сканирование точек доступа при первом запуске клиентского терминала.
  3. Terminal: Исправлено падение терминала при массовой перекомпиляции MQL5-программ.
  4. Terminal: Исправлено рисование графического объекта Fibonacci Retracement.
  5. Terminal: Исправлена обработка некорректного запроса в диалоге просмотра журнала терминала.
  6. Tester: Добавлена дефрагментация файлов исторической базы.
  7. Tester: Исправлено рисование графика результатов тестирования.
  8. MQL5: Исправлена и оптимизирована работа с торговой историей - устранены конфликты при параллельной работе нескольких экспертов и их влияние на вкладку "История" панели инструментов.
  9. MQL5: Изменено поведение функций PositionSelect, OrderSelect, HistoryOrderSelect и HistoryDealSelect - убран таймаут ожидания в случае отсутствия запрашиваемых данных. Если требуемые данные отсутствуют, немедленно возвращается false.
В документации ничего не сказано  теперь о таймаутах.
Список изменений в билдах MetaTrader 5 Client Terminal
Список изменений в билдах MetaTrader 5 Client Terminal
  • www.mql5.com
Автоматическое обновление доступно через систему LiveUpdate:.
 
simpleton:

Вот этот кусочек очень интересен:


Я нисколько не удивлён таким примером, потому что, очень похоже, что и сам MT5 пишется в подобном стиле, - а именно такой подход к программированию и даёт то качество, которое сейчас имеет и MT5.

Да, я сразу предупредил, что это примерный код. Вы можете представить свой вариант со всеми проверками и комментариями. Думаю, форумяне скажут спасибо.
Причина обращения: