iCustom Generic parameter

 

Hi,

I'm writing an EA for testing combinations of different indicators.

For that I want want to have different parameter sets for each indicator. 

My problem is that the code is getting a bit redundant I would like to initialize the indicators based on the metadata.

Parameters shal be stored in an structure (see code:   ??                parameterSet1[];) including the possible parameters and on initialization (see code initIndicator()) I want to take the data from there.

For only the path that way is working, but I need some help with the ... in iCustom.

here is the code:

struct IndicatorDescriptor
  {
   string            path;
   int               bufferIndexValue;
   int               bufferIndexSignal;
   int               paramsSetCount;
   ??                parameterSet1[];
   ??                parameterSet2[];
  };

bool metadata_initialized = false;

// collection of settings

// Volume: waddah attar
int      Waddah_Fast_MA[] = {9, 11, 13, 15, 20, 25, 30, 35, 40};       // Waddah: Period of the fast MACD moving average
int      Waddah_Slow_MA[] = {30, 35, 40, 47, 55, 60};       // Waddah: Period of the slow MACD moving average
int      Waddah_BBPeriod[]= {9, 11, 13, 15, 20, 25, 30, 35, 40};       // Waddah: Bollinger period
double   Waddah_BBDeviation[]= {2};   // Waddah: Number of Bollinger deviations
int      Waddah_Sensetive[]= {150};     // Waddah: Sensetive
// V1: Damiani 7, 65, 1.3
uint                 Damiani_InpViscosity[]      =  {5, 7, 9, 11, 15, 10, 12, 13};             // Damiani: Viscosity
uint                 Damiani_InpSedimentation[]  =  {35, 50, 65};            // Damiani: Sedimentation
double               Damiani_InpThreshold[]      =  {1.1};           // Damiani: Threshold
// V1: PZ Volatmeter
int          PZVolat_Fast[] = {5,10,15}; // PZ Volatmeter Fast
int          PZVolat_Slow[] = {10,15,20}; // PZ Volatmeter Slow
// V1: Trend direction and force
int          TDF_Period[] = {4, 6, 8}; // Trend direction and force Period
double       TDF_TriggerUpDown[] = {0.05, 0.1, 0.2}; // Trend direction and force Trigger up*down
// V1:
int          ATRR_Period_Fast[] = {7, 4};
int          ATRR_Period_Slow[] = {49, 21};

// All indicators to have an unique index for each indicator
enum ENUM_MetadataIndicator
  {
   IMD_NONE = -1,
   IMD_REX = 0,
   IMD_METRO = 1,
   IMD_TREND_DIRECTION_AND_FORCE = 2,
   IMD_WADDAH = 3,
   IMD_DAMIANI = 4,
   IMD_PZ_VOLATMETER = 5,
   IMD_FISHER_TRANSFORM = 6,
   IMD_ATR_RATIO = 7,

// add new indicators before _ENUM_MetadataIndicator_ENTRIES
   _ENUM_MetadataIndicator_ENTRIES // Must be the last entry (!!)
  };
IndicatorDescriptor metadata_indicators[_ENUM_MetadataIndicator_ENTRIES];

// subset for Volume indicators
enum ENUM_MetadataIndicatorV1
  {
   IMD_V1__NONE = IMD_NONE, // No V1
   IMD_V1__WADDAH = IMD_WADDAH,   // Waddah Attar Explosion
   IMD_V1__DAMIANI = IMD_DAMIANI,    // Damiani Volatmeter
   IMD_V1__PZ_VOLATMETER = IMD_PZ_VOLATMETER, // PZ Volatmeter 2.0
   IMD_V1__TDF = IMD_TREND_DIRECTION_AND_FORCE, // Trend direction and force
   IMD_V1__ATR_RATIO = IMD_ATR_RATIO // ATR Ratio
  };

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void initIndicatorMetadata()
  {
// if already initialized early out
   if(metadata_initialized)
      return;
   imd_setMD(IMD_REX, "rex", 0, 1);
   imd_setMD(IMD_METRO,"metro", 1, 2);
   imd_setMD(IMD_TREND_DIRECTION_AND_FORCE, "Volume/Trend direction and force", 2, -1);
   imd_setMD(IMD_WADDAH, "Volume/waddah_attar_explosion", 0, 0);
   imd_setMD(IMD_DAMIANI, "Volume/Damiani_Volatmeter", 0, 0);
   imd_setMD(IMD_PZ_VOLATMETER, "Market/PZ Volatmeter MT5", 0, 0);
   imd_setMD(IMD_FISHER_TRANSFORM, "crossing/Ehlers Fisher transform (original)", 0, 1);
   imd_setMD(IMD_ATR_RATIO, "Volume/atrratio", 0, -1);
// set metadata as initialized
   metadata_initialized = true;
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void imd_setMD(int idx, string path, int bufferIndexValue, int bufferValueSignal)
  {
   metadata_indicators[idx].path = path;
   metadata_indicators[idx].bufferIndexValue = bufferIndexValue;
   metadata_indicators[idx].bufferIndexSignal = bufferValueSignal;
   metadata_indicators[idx].paramsSetCount = 0;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int imd_CopyBufferValue(int indicatorIndex,int handle, int startpos,int count,double &double_array[])
  {
   initIndicatorMetadata();
   int buffer_num = metadata_indicators[indicatorIndex].bufferIndexValue;
   return CopyBuffer(handle,buffer_num,startpos,count,double_array);
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string imd_getPath(int indicatorIndex)
  {
   initIndicatorMetadata();
   return metadata_indicators[indicatorIndex].path;
  }

int initIndicator(int indicatorIdx, int param1, int param2) {
  return iCustom(NULL, PERIOD_CURRENT, imd_getPath(indicatorIdx), metadata_indicators[indicatorIndex].parameterSet2[param2], metadata_indicators[indicatorIndex].parameterSet2[param2]);
}
//+------------------------------------------------------------------+

Which datatype can I use to store int, double, bool, enums and string which are the parameters fo different indicator?

Thanks for any hint

Regards

Daniel


 
Daniel Nettesheim:

Hi,

...

Which datatype can I use to store int, double, bool, enums and string which are the parameters fo different indicator?

Structs: https://www.mql5.com/en/docs/basis/types/classes

But first you have to find a unified presentation of all of your indicator parameters.

Documentation on MQL5: Language Basics / Data Types / Structures, Classes and Interfaces
Documentation on MQL5: Language Basics / Data Types / Structures, Classes and Interfaces
  • www.mql5.com
Structures, Classes and Interfaces - Data Types - Language Basics - MQL5 Reference - Reference on algorithmic/automated trading language for MetaTrader 5
 

Thanks, perhaps I do not get your point. Is what your wrote not just a repetition of my question as a task which I'm not able to find out.


But at least I have found out that I can use double as datatype for int parameters. And as far as I can see, my indicators are only using uint, int and double. So probably I just need double as baseclass for parameters ...

One indicator is using a string input, but I have the source code and can modify that indicator and remove that string input.

This is not really a nice solution but for testing good enough. I'll give it a try.

Regards

Daniel

 
Daniel Nettesheim #:

Thanks, perhaps I do not get your point. Is what your wrote not just a repetition of my question as a task which I'm not able to find out.

But this depends very much on the things you want to do with it. So it's hard for others to develop a suitable solution.

 

I solved it this way:

struct IndicatorParam
  {
   double            vals[];
  };

struct IndicatorDescriptor
  {
   string            path;
   int               bufferIndexValue;
   int               bufferIndexSignal;
   int               paramsSetCount;
   IndicatorParam    parameters[4];
  };

void initIndicatorMetadata()
  {
 ...
   imd_setMD(IMD_FISHER_TRANSFORM, "crossing/Ehlers Fisher transform (original)", 0, 1);
   imd_setMD(IMD_ATR_RATIO, "Volume/atrratio", 0, -1);
   imd_addPs(IMD_ATR_RATIO, 0, 7, 4, 10);
// set metadata as initialized
   metadata_initialized = true;
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void imd_addPs(int indicatorIdx, int paramNo, double val1, double val2=IMD_INVALID_PARAM, double val3=IMD_INVALID_PARAM)
  {
   imd_addP(indicatorIdx, paramNo, val1);
   if(val2 > IMD_INVALID_PARAM)
     {
      imd_addP(indicatorIdx, paramNo, val2);
     }
   if(val3 > IMD_INVALID_PARAM)
     {
      imd_addP(indicatorIdx, paramNo, val3);
     }
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void imd_addP(int indicatorIdx, int paramNo, double val)
  {
   int siz = ArraySize(metadata_indicators[indicatorIdx].parameters[paramNo].vals);
   ArrayResize(metadata_indicators[indicatorIdx].parameters[paramNo].vals, siz+1);
   metadata_indicators[indicatorIdx].parameters[paramNo].vals[siz] = val;

   if(metadata_indicators[indicatorIdx].paramsSetCount <= paramNo)
     {
      metadata_indicators[indicatorIdx].paramsSetCount = paramNo + 1;
     }
  }
 

You can use MqlParam for this.

int IndicatorInit(int indicatorIdx, MqlParam &pars[])
 {
   switch(indicatorIdx)
    {
      case IMD_FISHER_TRANSFORM:
        return iCustom(NULL, PERIOD_CURRENT, imd_getPath(indicatorIdx), pars[0].integer_value, pars[1].double_value);
      ...

For documentation about MqlParam see the MQL5 reference. See also the IndicatorCreate() function with generic parameters.

Documentation on MQL5: Timeseries and Indicators Access / IndicatorCreate
Documentation on MQL5: Timeseries and Indicators Access / IndicatorCreate
  • www.mql5.com
IndicatorCreate - Timeseries and Indicators Access - MQL5 Reference - Reference on algorithmic/automated trading language for MetaTrader 5
 

Yes, thats how I do it currently. With 30 indicators you have a lot of redundant code because you need to add each new indicator into the switch case.

Now I have a generic mechanism with any need to extend that code, except I need more than 5 parameters

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int initIndicator(int indicatorIdx, int param1=0, int param2=0, int param3=0, int param4=0, int param5=0)
  {
   int handle = INVALID_HANDLE;
   int valueIdxArr[] = {param1,param2, param3, param4, param5};
   initIndicatorMetadata();
   if(indicatorIdx == IMD_NONE)
     {
      return INVALID_HANDLE;
     }
   switch(metadata_indicators[indicatorIdx].paramsSetCount)
     {
      case 0:
         handle = iCustom(NULL, PERIOD_CURRENT, metadata_indicators[indicatorIdx].path);
      case 1:
         handle = iCustom(NULL, PERIOD_CURRENT, metadata_indicators[indicatorIdx].path,
                          imd_getP(indicatorIdx, 0, valueIdxArr));
      case 2:
         handle = iCustom(NULL, PERIOD_CURRENT, metadata_indicators[indicatorIdx].path,
                          imd_getP(indicatorIdx, 0, valueIdxArr),
                          imd_getP(indicatorIdx, 1, valueIdxArr));
      case 3:
         handle = iCustom(NULL, PERIOD_CURRENT, metadata_indicators[indicatorIdx].path,
                          imd_getP(indicatorIdx, 0, valueIdxArr),
                          imd_getP(indicatorIdx, 1, valueIdxArr),
                          imd_getP(indicatorIdx, 2, valueIdxArr));
      case 4:
         handle = iCustom(NULL, PERIOD_CURRENT, metadata_indicators[indicatorIdx].path,
                          imd_getP(indicatorIdx, 0, valueIdxArr),
                          imd_getP(indicatorIdx, 1, valueIdxArr),
                          imd_getP(indicatorIdx, 2, valueIdxArr),
                          imd_getP(indicatorIdx, 3, valueIdxArr));
      case 5:
         handle = iCustom(NULL, PERIOD_CURRENT, metadata_indicators[indicatorIdx].path,
                          imd_getP(indicatorIdx, 0, valueIdxArr),
                          imd_getP(indicatorIdx, 1, valueIdxArr),
                          imd_getP(indicatorIdx, 2, valueIdxArr),
                          imd_getP(indicatorIdx, 3, valueIdxArr),
                          imd_getP(indicatorIdx, 4, valueIdxArr));
     }
   return handle;
  }
 
Daniel Nettesheim #:

Yes, thats how I do it currently. With 30 indicators you have a lot of redundant code because you need to add each new indicator into the switch case.

Now I have a generic mechanism with any need to extend that code, except I need more than 5 parameters

You don't. Use IndicatorCreate() and code in a generic way.
Reason: