Can I intialize CExpert in OnTimer or OnTick instead of OnInit ? - page 2

 

So, I have taken a look at the code for the classes CExpertBase and CExpert, and as you have already mentioned, what is preventing you from changing the symbol, is the current phase of the objects initialisation, which only allows changing the symbol during the INIT_PHASE_TUNING (which is after the Init() method but before the ValidationSettings() method).

Also, by default the CExpert constructor sets the member variable "m_other_symbol" to true, so it allows you to change the symbol when using Symbol() method, during the "INIT_PHASE_TUNING" phase.

So, what I would suggest is the following:

  1. I would initialise the object in the OnInit() event handler as normal, with the Init() method, and set up Signals, Trailing Stops, Money Management, and others. However, I would NOT call the any method that alters the current phase, such as ValidationSettings() or InitIndicators(), so that it remains in the "INIT_PHASE_TUNING" phase.
  2. Instead, I would wait until knowing the name of the trade symbol, then, in the OnTick() or in the OnTimer(), I would first check the current phase of the object, and if it is still in "INIT_PHASE_TUNING" phase, I would then update the symbol via the Symbol() method, and then proceed with calling the methods that would change the phase such as ValidationSettings() or InitIndicators(). Once the phase is changed, this part of the code will no longer try to update the symbol on the next call to OnTick() or in the OnTimer().
Since I don't use the Standard Library, I cannot confirm if this is the correct or best method, but it seems to me to be the most probable based on what I have analysed so far.
Documentation on MQL5: Standard Library / Strategy Modules / Base classes for Expert Advisors / CExpertBase / InitPhase
Documentation on MQL5: Standard Library / Strategy Modules / Base classes for Expert Advisors / CExpertBase / InitPhase
  • www.mql5.com
Gets the current phase of the object initialization. Return Value Current phase of the object initialization. Note The object initialization...
 

>Once the phase is changed, this part of the code will no longer try to update the symbol on the next call to OnTick() or in the OnTimer().

Unfortunately, this solution does not work for me because my requirement is:

- the underlying source symbol (= Symbol()) for data (i.e. CSignal and its indicators); this symbol can be fixed when initializing CExpert.

- the custom symbol (= m_other_symbol ???) with custom period (= m_other_period ???) for trades (i.e. CExpertTrade); this symbol can be changed e within void onTimer()Subsequent calls to onTimer() may change the symbol again.


Btw, it seems a bit hacky to play around with internal stuff like INIT_PHASE_TUNING. I think the most clean solution is simply to override CExpert::initTrade:


//+------------------------------------------------------------------+
//| Initialization trade object                                      |
//+------------------------------------------------------------------+
bool CExpert::InitTrade(ulong magic,CExpertTrade *trade=NULL, CSymbolInfo *other_symbol)
  {
//--- удаляем существующий объект
   if(m_trade!=NULL)
      delete m_trade;
//---
   if(trade==NULL)
     {
      if((m_trade=new CExpertTrade)==NULL)
         return(false);
     }
   else
      m_trade=trade;
//--- tune trade object
   m_trade.SetSymbol(GetPointer(other_symbol)); // reference the other_symbol for trading and leave m_symbol for singals and indicators
   m_trade.SetExpertMagicNumber(magic);
   m_trade.SetMarginMode();
//--- set default deviation for trading in adjusted points
   m_trade.SetDeviationInPoints((ulong)(3*m_adjusted_point/m_symbol.Point()));
//--- ok
   return(true);
  }

  and only intitalize my custom CExpert::initTrade within OnTimer() while leaving the other CExpert initialization within int OnInit():

void onTimer(){ // within onTimer the symbol for trading can be changed 

..
CExpertTrade *trade=new CExpertTrade;
   if(trade==NULL) {
      //--- failed
      printf(__FUNCTION__+": error creating trade expert");
      myExpert.Deinit();
      return(-11);
   }
//--- Add trade to expert
   if(!myExpert.InitTrade(ExpertMagicNumber, trade, my_custom_symbol)) { // uses overriden method of CExpert::initTrade
      //--- failed
      printf(__FUNCTION__+": error initializing trade expert");
      myExpert.Deinit();
      return(-12);
   }

}


The question is:

Does this solution have any hidden risks or limitations (e.g., historical trades, positions, etc.)? Perhaps one of the Metatrader maintainers who wrote the CExpert classes knows the right solution. Perhaps the solution offered here can be added to the standard CExpert by providing an overloaded method of CExpert::initTrade that accepts my_custom_symbol as a parameter. Would be nice if some of the MetaTrader maintainers can look at this issue. 

 

Well, if your requirements are so unique, why not simply create your own base code?

The Standard Library is often too complex and tries to do too much. Plenty of its complexity is unnecessary for most EA requirements, in my opinion.

So, instead of trying to use it, simply make your own mini library or simply make classes according to your own needs. That is what I do!

I am very much in favour of the "keep it simple, stupid" principle, and that is how I code my EAs.

 

There doesn't seem to be a way around simply extending CExpert and overriding or redefining some methods. The only thing is, I don't understand the reason for the existence of m_other_symbol and m_other_period — perhaps I can use them for my use case, thus avoiding extending CExpert. But at the moment, I'm not sure.

 
harryma23 #There doesn't seem to be a way around simply extending CExpert and overriding or redefining some methods. The only thing is, I don't understand the reason for the existence of m_other_symbol and m_other_period — perhaps I can use them for my use case, thus avoiding extending CExpert. But at the moment, I'm not sure.

The fact that you want to keep changing the symbol multiple times, means then the entire CExpert object needs to keep re-initialising completely. That is neither practical nor efficient. The class is not design for that, and trying to retro-fit it is also not ideal.

Create your own base class with your requirements in mind and build on that. Keep it simple.

 

>CExpert object needs to keep re-initialising completely. That is neither practical nor efficient.

 I am looking to avoid this by overriding the appropriate methods. I need to look each class where m_symbol is used and if needed, override those methods, e.g.:
//+------------------------------------------------------------------+
//| Position select depending on netting or hedging                  |
//+------------------------------------------------------------------+
bool CExpert::SelectPosition(void) override
  {
   bool res=false;
//---
   if(IsHedging())
      // overwrite m_symbol with tradingSymbol
      res=m_position.SelectByMagic(tradingSymbol.Name(),m_magic); // m_symbol is not the symbol for trading
   else
      res=m_position.Select(tradingSymbol.Name());
//---
   return(res);
  }

I only need to change the symbol for trading and position, not for signal, indicators, etc.


> Create your own base class with your requirements in mind and build on that. Keep it simple.

I thought I'd use CExpert's standard libraries to avoid a lot of boilerplate code. I'm not sure which approach is better at the moment. Extending CExpert and overwriting or developing it from scratch. The only thing that could be a bit problematic is that if I use inheritance here, even the smallest changes to CExpert might require my class to be adapted again. Hmm. I'll look into it. 


Thank you so much so far.