Can an EA using custom indicator be listed on Market?

 

Hi Respectful Friends,

If my EA use signal and confirmation form custom indicator , Can it be listed on Market? I am worry that it would fail the auto validation.

Thanks.

 

It was described on this part of the article:

The checks a trading robot must pass before publication in the Market - Calling custom indicators with iCustom()

The checks a trading robot must pass before publication in the Market
The checks a trading robot must pass before publication in the Market
  • www.mql5.com
Before any product is published in the Market, it must undergo compulsory preliminary checks in order to ensure a uniform quality standard. This article considers the most frequent errors made by developers in their technical indicators and trading robots. An also shows how to self-test a product before sending it to the Market.
 

Plactical example:

Forum on trading, automated trading systems and testing trading strategies

How to start with MQL5

Vladimir Karputov, 2021.08.28 19:56

Custom Moving Average as a resource

Code: Custom Moving Average as a resource.mq5

It is often asked: "If an Expert Advisor uses a custom indicator, how should you write the Expert Advisor code correctly to make the Expert Advisor work on the MQL5 VPS"?

The answer is this: the indicator must be created as a resource. See example below:

Please note: I moved the 'Custom Moving Average' indicator to the root folder 'Indicators'

//+------------------------------------------------------------------+
//|                          Custom Moving Average as a resource.mq5 |
//|                              Copyright © 2021, Vladimir Karputov |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2021, Vladimir Karputov"
#property version   "1.000"
#property description "An example of using the MQL5 VPS: the Expert Advisor uses the 'Custom Moving Average' indicator as a resource"
#resource "\\Indicators\\Custom Moving Average.ex5"
//--- input parameters
input int            InpMAPeriod = 13;          // Period
input int            InpMAShift  = 0;           // Shift
input ENUM_MA_METHOD InpMAMethod = MODE_SMMA;   // Method
input bool           InpPrintLog = true;        // Print log
//---
int      handle_iCustom;                        // variable for storing the handle of the iCustom indicator
datetime m_prev_bars             = 0;           // "0" -> D'1970.01.01 00:00';
bool     m_init_error            = false;       // error on InInit
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- create timer
   EventSetTimer(60);
//--- create handle of the indicator iCustom
   handle_iCustom=iCustom(Symbol(),Period(),"::Indicators\\Custom Moving Average.ex5");
//--- if the handle is not created
   if(handle_iCustom==INVALID_HANDLE)
     {
      //--- tell about the failure and output the error code
      PrintFormat("Failed to create handle of the iCustom indicator for the symbol %s/%s, error code %d",
                  Symbol(),
                  EnumToString(Period()),
                  GetLastError());
      //--- the indicator is stopped early
      m_init_error=true;
      return(INIT_SUCCEEDED);
     }
   Print(__FUNCTION__);
//---
   double array_ma[];
   ArraySetAsSeries(array_ma,true);
   int start_pos=0,count=3;
   if(iGetArray(handle_iCustom,0,start_pos,count,array_ma))
     {
      Print("---");
      Print(TimeToString(m_prev_bars,TIME_DATE|TIME_MINUTES));
      string text="";
      for(int i=0; i<count; i++)
         text=text+IntegerToString(i)+": "+DoubleToString(array_ma[i],Digits()+1)+"\n";
      //---
      Print(text);
     }
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- destroy timer
   EventKillTimer();
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
  }
//+------------------------------------------------------------------+
//| Timer function                                                   |
//+------------------------------------------------------------------+
void OnTimer()
  {
//---
   if(m_init_error)
      return;
//--- we work only at the time of the birth of new bar
   datetime time_0=iTime(Symbol(),Period(),0);
   if(time_0==m_prev_bars)
      return;
   m_prev_bars=time_0;
//---
   double array_ma[];
   ArraySetAsSeries(array_ma,true);
   int start_pos=0,count=3;
   if(!iGetArray(handle_iCustom,0,start_pos,count,array_ma))
     {
      m_prev_bars=0;
      return;
     }
   Print("---");
   Print(__FUNCTION__);
   Print(TimeToString(m_prev_bars,TIME_DATE|TIME_MINUTES));
   string text="";
   for(int i=0; i<count; i++)
      text=text+IntegerToString(i)+": "+DoubleToString(array_ma[i],Digits()+1)+"\n";
   Print(text);
//---
  }
//+------------------------------------------------------------------+
//| Get value of buffers                                             |
//+------------------------------------------------------------------+
bool iGetArray(const int handle,const int buffer,const int start_pos,
               const int count,double &arr_buffer[])
  {
   bool result=true;
   if(!ArrayIsDynamic(arr_buffer))
     {
      if(InpPrintLog)
         PrintFormat("ERROR! EA: %s, FUNCTION: %s, this a no dynamic array!",__FILE__,__FUNCTION__);
      return(false);
     }
   ArrayFree(arr_buffer);
//--- reset error code
   ResetLastError();
//--- fill a part of the iBands array with values from the indicator buffer
   int copied=CopyBuffer(handle,buffer,start_pos,count,arr_buffer);
   if(copied!=count)
     {
      //--- if the copying fails, tell the error code
      if(InpPrintLog)
         PrintFormat("ERROR! EA: %s, FUNCTION: %s, amount to copy: %d, copied: %d, error code %d",
                     __FILE__,__FUNCTION__,count,copied,GetLastError());
      //--- quit with zero result - it means that the indicator is considered as not calculated
      return(false);
     }
   return(result);
  }
//+------------------------------------------------------------------+


I have compiled an indicator and an advisor. The EA attached it to the chart and carried out the migration. The result of working at the MQL5 VPS:

Custom Moving Average as a resource

As you can see, everything works great!


 
Sergey Golubev #:

Plactical example:


That's very helpful. Thanks for your sharing. 

 

I tested and it worked like charm! It allows my EA to run on any other terminal without installing the Indicator.

//+------------------------------------------------------------------+
//|                                                   DHT Trader.mq4 |
//|                                  Copyright 2025, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+

#resource "\\Indicators\\BFS\\DHT.ex4" 

#property copyright "Copyright 2025, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property strict
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{
   
   return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
    
}
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
{
   double up = iCustom(_Symbol,_Period,"::Indicators\\BFS\\DHT.ex4",6,0,0);
   Comment(DoubleToString(up,_Digits));   
}
//+------------------------------------------------------------------+

I learn that if the indicator keep calculating from the first bar on the chart, the EA will got stuck and timeout. The indicator must have proper handling with the rates_total and prev_calculated. 

int limit = MathMin(rates_total -1, rates_total - prev_calculated);
//Main loop
for(int i=limit; i>=0; i--)
{
        //Code here
}