iCustom does not return failure of custom indicator.

 

Hi,


I may be misunderstanding things, but it seems the MQL5 iCustom() call will always return a handle, even if the OnInit() of that indicator returns a failure code (such as INIT_PARAMETERS_INCORRECT).

Therefore there is no way to stop an EA due to a Custom Indicator having invalid parameters or failing for some other reason.

For example, the code from a class inherited from CIndicator calls the iCustom method and is passed parameters that will are invalid in the Indicator:

   m_handle=iCustom(symbol,period,"Ind25_RegressionChart",
                        rc_ChartLineColor,
                        rc_SampleSize,
                        rc_Power,
                        rc_AppliedPrice,
                        rc_MaxCorrelation,
                        rc_MinEquationConstant1,
                        rc_MaxEquationConstant2,
                        rc_MinEquationConstant2,
                        rc_MaxEquationConstant2,
                        rc_MinEquationConstant3,
                        rc_MaxEquationConstant3,
                        rc_MinEquationConstant4,
                        rc_MaxEquationConstant4
   );
//--- check result
   if(m_handle==INVALID_HANDLE)
      return(false);

Custom Indicator OnInit()

int OnInit()
  {

//--- Validation
   if (InpMinEquationConstant2 > InpMaxEquationConstant2) return (INIT_PARAMETERS_INCORRECT);

   ResetLastError();
//---
   return(INIT_SUCCEEDED);
  }

In this scenario during strategy testing, the Indicator is created without being initialized and a handle passed back through iCustom and it continues processing. It then seems to call OnInit() and re-do the failed validation again for every Bar until the end of testing. There is no way to tell if validation has failed (or OnInit failed for that matter), because a valid handle is passed back.

I could do a hack and try to crash the Indicator some other way to ensure a handle is not passed back, but I don't think it's the best way through this, as running the indicator on it's own will then have issues.

Am I misunderstanding something here?

 

If it does not succeed it returns:

 INVALID_HANDLE

And you can do a print:

Print("m_handle = ",m_handle,"  error = ",GetLastError());

But also:

if(GetLastError()!=0)// in case of failure
 {
  // Go here:https://www.mql5.com/en/docs/constants/errorswarnings/errorcodes
 }
 
Marco vd Heijden:

If it does not succeed it returns:

And you can do a print:

But also:

Thanks Marco,

The problem is that even though OnInit() returns a failure such as INIT_PARAMETERS_INCORRECT, the iCustom() method will still return a valid handle. So the test:

   if(m_handle==INVALID_HANDLE)
      return(false);

does not become true, and the processing continues as though the Custom indicator is valid.

As far as I can tell, there is no way to tell whether OnInit has returned a failure code.

Regards.

 

Okay i just tried it and you are right it still returns a handle.

I guess it returns a handle if the filename of the indicator is found in the same way you get a file handle.

So that is not what is returned in the indicator's OnInit() function.

Perhaps you can make the comparisons in the indicator itself and create a global variable that's picked up by the EA to let it know that something is up. 

 

And just to clarify, iCustom() calls the OnInit() of the custom indicator.

The OnInit() does not set a LastError when it returns a failure code, it's just a return code of the method. It may return the Error to the Terminal if run on it's own, but when run by the EA it's lost.

Even if you try to set a UserError via SetUserError() after validation failure in the indicator, it does not seem to go across application boundaries between EA and Indicator, so if you test for the LastError in the EA with:

if(GetLastError()!=0)// in case of failure
 {
  return false;
 }

then it will not find the Error in the EA that was created in the Indicator.

Other options are:

  • put the validation in a common header that both EA and Indicator can see.
  • use global variables to indicate status, the indicator could set it so the EA can test it.

Not nice, but will do the job.

Unless someone has a better idea or solution?

 

Maybe you can have the indicator drop a small pixel object on the chart with some error name and then have the ea see if the object exists, and if it does, it will know something is up and then you have the EA remove it again.

Like leaving a digital post it.

 
Marco vd Heijden:

Maybe you can have the indicator drop a small pixel object on the chart with some error name and then have the ea see if the object exists, and if it does, it will know something is up and then you have the EA remove it again.

Like leaving a digital post it.

Haha thanks,

Dynamically creating/deleting a global variable is probably the best idea. It looks like a problem of the EA and Indicator being in two separate apps on different threads, so there is limited communication. They try and say to put all indicator code into the EA if possible, and this is probably one reason, plus the inter-application communication seems to slow it down, for strategy testing anyway. 

I'm using the Standard Library EA framework, so I'm stuck with it for now. Interesting that even if validation fails for a parameters' combination, that during strategy testing it constantly tries to re-do the OnInit and does all the validation again over and over for every bar (or every time it's accessed). So if people haven't seen this, their strategy testing could be doing all this extra processing without knowing it.

 
Trev Henderson:

Hi,


I may be misunderstanding things, but it seems the MQL5 iCustom() call will always return a handle, even if the OnInit() of that indicator returns a failure code (such as INIT_PARAMETERS_INCORRECT).

Therefore there is no way to stop an EA due to a Custom Indicator having invalid parameters or failing for some other reason.

For example, the code from a class inherited from CIndicator calls the iCustom method and is passed parameters that will are invalid in the Indicator:

Custom Indicator OnInit()

In this scenario during strategy testing, the Indicator is created without being initialized and a handle passed back through iCustom and it continues processing. It then seems to call OnInit() and re-do the failed validation again for every Bar until the end of testing. There is no way to tell if validation has failed (or OnInit failed for that matter), because a valid handle is passed back.

I could do a hack and try to crash the Indicator some other way to ensure a handle is not passed back, but I don't think it's the best way through this, as running the indicator on it's own will then have issues.

Am I misunderstanding something here?

You are right and you can only work around it. I have reported this to Metaquotes years ago, and if I remember well I never got an answer (I can't check since they deleted all the old tickets from the Service Desk). In my opinion the easiest solution is the check the parameters before the call to iCustom so you always only pass valid parameters.
 
Alain Verleyen:
You are right and you can only work around it. I have reported this to Metaquotes years ago, and if I remember well I never got an answer (I can't check since they deleted all the old tickets from the Service Desk). In my opinion the easiest solution is the check the parameters before the call to iCustom so you always only pass valid parameters.

Thanks Alain,

I think it's got something to do with an indicator working as a separate app, the EA only has access to the pointer (handle) of the Indicator app, and it can't get the return code from the Indicator because the Indicator is only being initialised and has not completed. As I said earlier, despite how their StdLib framework is arranged they now suggest it's better to have everything in the EA, probably for reasons like this.

Using a thread per indicator may be faster when the EA is running on its own live, but when strategy testing many combinations and each combination only has one thread on an Agent, it makes no difference. And the application boundaries probably create an overhead to cause it to run slower during strategy testing (some have said a third slower). It looks like the CIndicatorBuffer class is copying data from the Indicator using CopyBuffer (being passed the handle of the Indicator). If you had a totally custom indicator, you could instead include all your calculations and keep buffers in the EA and not have to copy this data between Indicator and EA, so it would be faster. It doesn't really matter live, because machines are fast enough, but 95% of EA's probably don't make it past Strategy Testing where this could be an issue.

In the end I put the validation in a header file and #included it in the Indicator and the Signal's ValidationSettings method, global variables are not great.

Reason: