MT5 and speed in action - page 19

 
Roman:

C programmers.

The example is very simple in this case. Calculating the totallifetime of all closed positions is a much more difficult task for fast performance.

 
fxsaber:

The example is very simple in this case. Calculating the totallifetime of all closed positions is a much more difficult task for quick performance.

I explained the reason to you earlier, but you didn't take it into account.

 
Roman:

I explained the reason to you earlier but you didn't take it into account.

Apparently I need to search the forum for your explanation.

 
fxsaber:

Apparently I need to search the forum for your explanation.

Last time you had a similar issue, where the passed parameter was not cached, but passed straight into the code.
And after you cached it, the speed increased. Always allocate memory for a variable and only use it later.
It's the same here, you declare a variable, memory is already allocated and further work with the variable will be faster since there are no memory allocation costs.

This also applies to getting values from mql function.
Even the developers recommended here on the forum, first get a value from a function into a variable and then use that variable in an if() condition

 
fxsaber:

Calculating the cumulativelifetime of all closed positions is a much harder task for fast performance.

Forum on trading, automated trading systems and strategy testing

Libraries: 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);
}

There may be a faster option. But a step to the left in the condition of what needs to be calculated, and the logic may have to change considerably. Not easy, in general.

 
fxsaber:

There may be a faster option. But one step to the left in the condition of what needs to be counted, and the logic may have to change considerably. Not easy, in general.

It's not the condition, it's the writing of the code.
Although you can replace condition with switch, it will work faster than if else.
Try this code, will it get faster or not? If not, try replacing if else with switch.
I hope you understand the point now, that all variable declarations should be put out of the loop, and not re-execute them 100500 times.
Also, for each returned value, allocate memory in the form of a variable.

#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);
}
 

This is another variant of the code, so that we don't have to yank History for the second condition.
You can also think which condition will be fulfilled more often, put it first in the loop and continue iteration.

#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:

This is another variant of the code, so as not to pull History for the second condition.

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

From here on, it's up to you.

 
Renat Fatkhullin:

In MT4 it works the same way, just the cache creation is hidden. At every OnTick/OnStart of MT4 the terminal automatically and sparingly creates a snapshot of the market environment for each EA.

Therefore, you cannot assess the true latency of data preparation from the MQL4 code. Fortunately, in MT4 the data is small and simple.

In case you're wondering.

closed positions.

 
fxsaber:

You can take it from here.

If you do it yourself, then you do it yourself.
But it's strange why the result is so strange, that's a question for Renate.
My suspicion is the hashmap check DealsIn.TryGetValue
Look under the profiler.

Reason: