CSymbolInfo::CheckMarketWatch bug

 

In MQL5, despite MQL4, GetLastError() doesn't reset the _LastError variable.

If CSymbolInfo::CheckMarketWatch() is called in a loop providing symbols from an array, and there is an unknown symbol in the array, subsequent calls of the function will fail.

The function is called in the Name() method to set m_name member, the Name() method should be called if desired symbol is different from the chart symbol.

So the function should reset the _LastError at first before checking its value.

The code of a script to reproduce the issue:

#include <Trade\SymbolInfo.mqh>
#property script_show_inputs
input bool Reset=false; //ResetLastError
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
{
//---
   Print("ResetLastError input: ",Reset);
   const string symbols[5]={"EURUSD","NONEXISTENT","GBPUSD","EURGBP","USDCHF"};
   for(int i=0; i<5; i++)
   {
      CSymbolInfo symbol_info;
      if(Reset)
      {
         ResetLastError();
      }
      if(symbol_info.Name(symbols[i]))
      {
         Print(symbols[i]," is now selected in MarketWatch");
      }
   }
}

The output by different script parameters:

2022.06.17 13:29:31.000 test-CSymbolInfo (CADCHF,D1) ResetLastError input: false
2022.06.17 13:29:31.001 test-CSymbolInfo (CADCHF,D1) EURUSD is now selected in MarketWatch
2022.06.17 13:29:31.001 test-CSymbolInfo (CADCHF,D1) CSymbolInfo::CheckMarketWatch: Unknown symbol 'NONEXISTENT'
2022.06.17 13:29:31.001 test-CSymbolInfo (CADCHF,D1) CSymbolInfo::CheckMarketWatch: Unknown symbol 'GBPUSD'
2022.06.17 13:29:31.001 test-CSymbolInfo (CADCHF,D1) CSymbolInfo::CheckMarketWatch: Unknown symbol 'EURGBP'
2022.06.17 13:29:31.001 test-CSymbolInfo (CADCHF,D1) CSymbolInfo::CheckMarketWatch: Unknown symbol 'USDCHF'
2022.06.17 13:29:48.518 test-CSymbolInfo (CADCHF,D1) ResetLastError input: true
2022.06.17 13:29:48.519 test-CSymbolInfo (CADCHF,D1) EURUSD is now selected in MarketWatch
2022.06.17 13:29:48.519 test-CSymbolInfo (CADCHF,D1) CSymbolInfo::CheckMarketWatch: Unknown symbol 'NONEXISTENT'
2022.06.17 13:29:48.520 test-CSymbolInfo (CADCHF,D1) GBPUSD is now selected in MarketWatch
2022.06.17 13:29:48.520 test-CSymbolInfo (CADCHF,D1) EURGBP is now selected in MarketWatch
2022.06.17 13:29:48.520 test-CSymbolInfo (CADCHF,D1) USDCHF is now selected in MarketWatch

The function would be coded as below to resolve the issue:

//+------------------------------------------------------------------+
//| Checks if symbol is selected in the MarketWatch                  |
//| and adds symbol to the MarketWatch, if necessary                 |
//+------------------------------------------------------------------+
bool CSymbolInfo::CheckMarketWatch(void)
  {
   ResetLastError();
//--- check if symbol is selected in the MarketWatch
   if(!Select())
     {
      if(GetLastError()==ERR_MARKET_UNKNOWN_SYMBOL)
        {
         printf(__FUNCTION__+": Unknown symbol '%s'",m_name);
         return(false);
        }
      if(!Select(true))
        {
         printf(__FUNCTION__+": Error adding symbol %d",GetLastError());
         return(false);
        }
     }
//--- succeed
   return(true);
  }
 

I did test with your code.

It seems the _LastError is reset automatically.

Build 3320.

 
Ziheng Zhuang #:

I did test with your code.

It seems the _LastError is reset automatically.

Build 3320.

The symbols must be hidden (Not selected) in Market Watch before running the script.
 
Mohammad Hossein Sadeghi #:
The symbols must be hidden (Not selected) in Market Watch before running the script.

Checked. You are right.

Before calling Select(), _LastError should be reset.

 

The job of a programmer is to write your code correctly. No one should reset the error for you - you should do it yourself. Example: first reset the error, then process the result

   ResetLastError();
   if(!m_symbol.Name(Symbol())) // sets symbol name
     {
      Print(__FILE__," ",__FUNCTION__,", ERROR: CSymbolInfo.Name");
      return(INIT_FAILED);
     }
 
Vladimir Karputov #:

The job of a programmer is to write your code correctly. No one should reset the error for you - you should do it yourself. Example: first reset the error, then process the result

No one should reset the error for me, OK, I agree, so the function should do it for itself too if required.

When using a framework, I should not read the function body, and determine how it is doing its job, sometimes I can't read the body as it is already compiled, I should usually rely on it and be sure it is doing the intended job as documented, it says:

//+------------------------------------------------------------------+
//| Checks if symbol is selected in the MarketWatch                  |
//| and adds symbol to the MarketWatch, if necessary                 |
//+------------------------------------------------------------------+

The function seems to act as MQL4 behavior in which the _LastError is reset when calling GetLastError().

Both methods, Name() and CheckMarketWatch() are Boolean, so I should usually check for error if it returns false. Let's have a look at this code:

CSymbolInfo symbol1;
if(!symbol1.Name("NONEXISTENT")) {
   Print(GetLastError());
}
CSymbolInfo symbol2;
if(!symbol2.Name("EURUSD")) {
   Print(GetLastError());
}

Where "NONEXISTENT" is not listed and "EURUSD" is listed but not selected in MarketWatch. The function returns false at both calls, since the _LastError is not reset, and "EURUSD" is listed but not selected, the GetLastError is compared to ERR_MARKET_UNKNOWN_SYMBOL which becomes true.

If it should not reset _LastError for me, it should first check the _LastError value, because Select() method doesn't change the _LastError as "EURUSD" exists. Or CheckMarketWatch should check for symbol existence by SymbolExist() before checking the symbol whether it is selected, instead of comparing to ERR_MARKET_UNKNOWN_SYMBOL.

It seems a bug to me, and I stated it here if someone else is relying on it and gets undesired result, the code you provided seems a workaround to the problem to me and a security measure which leads to not relying on a framework.

 

By the way the log message becomes wrong in this case:

printf(__FUNCTION__+": Unknown symbol '%s'",m_name);
 
You are obliged to carry out the control yourself! And you must understand in which cases it is you who must reset the error code yourself. No one will do your work for you.