MT5 и скорость в боевом исполнении - страница 19

 
Roman:

Си программисты.

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

 
fxsaber:

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

Я уже объяснял причину вам ранее, но вы не приняли во внимание.

 
Roman:

Я уже объяснял причину вам ранее, но вы не приняли во внимание.

Видимо, мне нужно поискать на форуме ваше объяснение.

 
fxsaber:

Видимо, мне нужно поискать на форуме ваше объяснение.

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

Это также касается получения значений из функции mql.
Даже разработчики рекомендовали тут на форуме, сперва получить значение из функции в переменную, а затем эту переменную использовать в условии if()

 
fxsaber:

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

Форум по трейдингу, автоматическим торговым системам и тестированию торговых стратегий

Библиотеки: MT4Orders

fxsaber, 2020.08.29 04:17

#include <Generic\HashMap.mqh>

// Возвращает общую длительность всех закрытых позиций.
int SumPositionsLengthMQL5( void )
{
  int Res = 0;
  
  if (HistorySelect(0, INT_MAX))
  {
    CHashMap<ulong, ulong> DealsIn;  // По PositionID возвращает DealIn.
    const int TotalDeals = HistoryDealsTotal();
    
    for (int i = 0; i < TotalDeals; i++)
    {
      const ulong TicketDeal = HistoryDealGetTicket(i);
      
      if (HistoryDealGetInteger(TicketDeal, DEAL_ENTRY) == DEAL_ENTRY_IN)
        DealsIn.Add(HistoryDealGetInteger(TicketDeal, DEAL_POSITION_ID), TicketDeal);
      else if (HistoryDealGetInteger(TicketDeal, DEAL_TYPE) <= DEAL_TYPE_SELL)
      {
        ulong TicketDealIn;
        
        if (DealsIn.TryGetValue(HistoryDealGetInteger(TicketDeal, DEAL_POSITION_ID), TicketDealIn))
          Res += (int)(HistoryDealGetInteger(TicketDeal, DEAL_TIME) - HistoryDealGetInteger(TicketDealIn, DEAL_TIME));        
      }        
    }
  }
      
  return(Res);
}

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

 
fxsaber:

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

Дело не в условии, а в написании кода.
Хотя и условие можно заменить на switch, он побыстрее будет работать чем логическое условие if else.
Попробуй такой код, станет быстрее или нет? Если нет, то попробуй if else заменить на switch.
Надеюсь теперь понятен смысл, что все объявления переменных нужно выносить за цикл, и не переобъявлять их по 100500 раз.
Так же под каждое возвращаемое значение, выделяем память в виде переменной.

#include <Generic\HashMap.mqh>

// Возвращает общую длительность всех закрытых позиций.
int SumPositionsLengthMQL5( void )
{
   int  Res     = 0;
   bool HSelect = false;
  
   HSelect = HistorySelect(0, INT_MAX);
  
   if(HSelect)
   {
      CHashMap<ulong, ulong> DealsIn;  // По PositionID возвращает DealIn.
    
      int   TotalDeals   = 0;
      ulong TicketDeal   = 0;
      bool  condition1   = false;
      bool  condition2   = false; 
      bool  condition3   = false;       
      long  PositionID   = 0;
      ulong TicketDealIn = 0;
      int   DealTime     = 0;
    
      TotalDeals = HistoryDealsTotal();
    
      for(int i=0; i < TotalDeals; i++)
      {
         TicketDeal =  HistoryDealGetTicket(i);      
         condition1 = (HistoryDealGetInteger(TicketDeal, DEAL_ENTRY) == DEAL_ENTRY_IN);
         condition2 = (HistoryDealGetInteger(TicketDeal, DEAL_TYPE) <= DEAL_TYPE_SELL);
      
         if(condition1)
         {
            PositionID = HistoryDealGetInteger(TicketDeal, DEAL_POSITION_ID);
            DealsIn.Add(PositionID, TicketDeal);          
         }
         else if(condition2)
         {       
            PositionID = HistoryDealGetInteger(TicketDeal, DEAL_POSITION_ID);
            condition3 = DealsIn.TryGetValue(PositionID, TicketDealIn);
         
            if(condition3) 
            {
               DealTime = (int)(HistoryDealGetInteger(TicketDeal, DEAL_TIME) - HistoryDealGetInteger(TicketDealIn, DEAL_TIME));
               Res += DealTime; 
            }   
         }        
      }
   }
     
   return(Res);
}
 

Ещё такой вариант кода, чтоб лишний раз не дёргать History для второго условия.
Можно ещё подумать, какое условие чаще будет выполнятся, поставить его первым в цикле, и continue переводить итерацию.

#include <Generic\HashMap.mqh>

// Возвращает общую длительность всех закрытых позиций.
int SumPositionsLengthMQL5( void )
{
   int  Res     = 0;
   bool HSelect = false;
  
   HSelect = HistorySelect(0, INT_MAX);
  
   if(HSelect)
   {
      CHashMap<ulong, ulong> DealsIn;  // По PositionID возвращает DealIn.
    
      int   TotalDeals   = 0;
      ulong TicketDeal   = 0;
      bool  condition1   = false;
      bool  condition2   = false; 
      bool  condition3   = false;       
      long  PositionID   = 0;
      ulong TicketDealIn = 0;
      int   DealTime     = 0;
    
      TotalDeals = HistoryDealsTotal();
    
      for(int i=0; i < TotalDeals; i++)
      {
         TicketDeal =  HistoryDealGetTicket(i);      
         condition1 = (HistoryDealGetInteger(TicketDeal, DEAL_ENTRY) == DEAL_ENTRY_IN);         
      
         if(condition1)
         {
            PositionID = HistoryDealGetInteger(TicketDeal, DEAL_POSITION_ID);
            DealsIn.Add(PositionID, TicketDeal);
            continue;                      
         }                  
         
         condition2 = (HistoryDealGetInteger(TicketDeal, DEAL_TYPE) <= DEAL_TYPE_SELL);
         
         if(condition2)
         {       
            PositionID = HistoryDealGetInteger(TicketDeal, DEAL_POSITION_ID);
            condition3 = DealsIn.TryGetValue(PositionID, TicketDealIn);
         
            if(condition3) 
            {
               DealTime = (int)(HistoryDealGetInteger(TicketDeal, DEAL_TIME) - HistoryDealGetInteger(TicketDealIn, DEAL_TIME));
               Res += DealTime; 
            }   
         }        
      }
   }
     
   return(Res);
}
 
Roman:

Ещё такой вариант кода, чтоб лишний раз не дёргать History для второго условия.

        3132754100
        Time[Bench(SumPositionsLengthMQL5)] = 105779
        3132754100
        Time[Bench(SumPositionsLengthMQL5_Roman)] = 106270

Дальше сами.

 
Renat Fatkhullin:

В МТ4 работает так же, просто создание кеша скрыто. На каждом OnTick/OnStart МТ4 терминал автоматически и экономно создает снепшот рыночного окружения для каждого эксперта. 

Поэтому вы не можете оценить истинных задержек на подготовке данных из MQL4 кода. К счастью, в МТ4 данных мало и все просто.

Если интересно.
 
fxsaber:

Дальше сами.

Ну раз сами, то сами.
Но странно почему такой результат, это уже вопрос Ренату.
Моё подозрение на проверку хешмап DealsIn.TryGetValue
Посмотри под профилировщиком.

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