Come ottenere la lunghezza di enum e item in MQL4/MQL5? - pagina 4

 
Penso che stia cercando un modo per catturare tutti gli input degli indicatori
in un EA aggirando la necessità di valori di input per ogni indicatore.
L'alternativa nel suo backtester è di modificare manualmente ogni indicatore
con un buffer di segnale.
 

Prova questo un po' diretto ma l'unico approccio possibile finora.

enum XXX {x1 = -10, x2 = 0, x3 = 11};

template<typename E>
int EnumToArray(E dummy, int &values[], const int start = INT_MIN, const int stop = INT_MAX)
{
  string t = typename(E) + "::";
  int length = StringLen(t);
  
  ArrayResize(values, 0);
  int count = 0;
  
  for(int i = start; i < stop && !IsStopped(); i++)
  {
    E e = (E)i;
    if(StringCompare(StringSubstr(EnumToString(e), 0, length), t) != 0)
    {
      ArrayResize(values, count + 1);
      values[count++] = i;
    }
  }
  return count;
}

int OnInit()
{
  Print("ENUM elements:");
  XXX a;
  int result[];
  int n = EnumToArray(a, result, -100, 100);
  Print("Count=", n);
  for(int i = 0; i < n; i++)
  {
    Print(i, " ", EnumToString((XXX)result[i]), "=", result[i]);
  }
  
  return 0;
}

Uscite:

Elementi ENUM:

Count=3

0 x1=-10

1 x2=0

2 x3=11

È importante specificare valori ragionevoli per i parametristart estop, perché il ciclo dal minimo al massimo valore intero (che è usato di default quando i parametri sono saltati) viene eseguito troppo lentamente tenendo conto che le funzioni stringa sono usate all'interno.

 
   template<typename ENUMTYPE>
   bool              AddEnum(ENUMTYPE enumIn) {
      enumIn = 0;
      
      //iterate through enum and add as combo box
      for(int i = 0; i<sizeof(enumIn); i++, enumIn++) {
         m_list.AddItem(EnumToString(enumIn),i);
         PrintFormat("adding %i = %s", i, EnumToString(enumIn));            
       }
      return(0);  
   }


Ho aggiunto questo alla classe CComboBox, in modo da poter passare qualsiasi tipo ENUM, e lo aggiungerebbe come casella combinata.


Ma puoi cambiarlo per fare ciò di cui hai bisogno.

Il problema è che se non passate un ENUM e passate qualcosa come un doppio o un float, potreste mandare in crash la vostra app.

Non credo che ci sia un modo per controllare il datatype passato.

 
dazamate:
   template<typename ENUMTYPE>
   bool              AddEnum(ENUMTYPE enumIn) {
      enumIn = 0;
      
      //iterate through enum and add as combo box
      for(int i = 0; i<sizeof(enumIn); i++, enumIn++) {
         m_list.AddItem(EnumToString(enumIn),i);
         PrintFormat("adding %i = %s", i, EnumToString(enumIn));            
       }
      return(0);  
   }


Ho aggiunto questo alla classe CComboBox, in modo da poter passare qualsiasi tipo di ENUM, e l'avrebbe aggiunto come casella combinata.


Ma puoi cambiarlo per fare ciò di cui hai bisogno.

Il problema è che se non passate un ENUM e passate qualcosa come un doppio o un float, potreste mandare in crash la vostra app.

Non credo che ci sia un modo per controllare il tipo di dati passato.

Ho paura che sizeof(enumIn) sia sempre uguale a 4.
 

Sì, lo fa, oops. L'ho appena notato.

Si dà il caso che quando l'ho fatto, l'ENUM che stavo usando in realtà aveva 4 proprietà:\

 

enum Combolist1{item1, item2, item3, item4, item5};

for(int i = 0; GetLastError()==0; i++) {
ComboBox1.ItemAdd(EnumToString(Combolist1(i)),Combolist1(0));
}
 
Xiangdong Guo: Come ottenere la lunghezza di enum e item in MQL4/MQL5?

Per esempio, c'è una definizione enum:

enum ENUM_FRUIT {APPLE, BANANA, GRAPE};

Poi, voglio usarlo in un ciclo:

for (int i = 0; i < length_of_enum; i++) {
  Print(EnumToString(get_enum_item(i)));
} 
Non c'è alcun modo, bisogna codificarlo.
Se non sarà un input, uso questo schema
enum ENUM_FRUIT {APPLE, BANANA, GRAPE,
                 FRUIT_FIRST=APPLE, FRUIT_LAST=GRAPE};
for (ENUM_FRUIT i = APPLE; i <= FRUIT_LAST; ++i) {
  Print(EnumToString(i));
}
Usarlo con un incremento (++i) presuppone che siano adiacenti numericamente.
Se sarà un ingresso, uso questo schema
enum ENUM_FRUIT {APPLE, BANANA, GRAPE}
#define FRUIT_FIRST APPLE
#define FRUIT_LAST  GRAPE
for (ENUM_FRUIT i = APPLE; i <= FRUIT_LAST; ++i) {
  Print(EnumToString(i));
}
Se non sono numericamente adiacenti
const ENUM_TIMEFRAMES  gcPeriods[]={   PERIOD_CURRENT,
   PERIOD_M1,  PERIOD_M2,  PERIOD_M3,  PERIOD_M4,  PERIOD_M5,  PERIOD_M6,
   PERIOD_M10, PERIOD_M12, PERIOD_M15, PERIOD_M20, PERIOD_M30, PERIOD_H1,
   PERIOD_H2,  PERIOD_H3,  PERIOD_H4,  PERIOD_H6,  PERIOD_H8,  PERIOD_H12,
   PERIOD_D1,  PERIOD_W1,  PERIOD_MN1};
ENUM_TIMEFRAMES  next(ENUM_TIMEFRAMES curr){
   for(int i=0; gcPeriods[i] != curr; ++i){}
   return gcPeriods[i+1];
}
 
Lorentzos Roussos:
Cattiva progettazione di cosa

significa che il numero di membri del negozio in enum?

 

So che questa conversazione è abbastanza vecchia, ma ecco un modo semplice per riempire un array di qualsiasi tipo enum.


void OnStart()
{
   ENUM_TIMEFRAMES array[];
   int total_elements = enumFillArray(array);
   printf("There are %d elements in the ENUM_TIMEFRAMES array.",
      total_elements
   );
   
   for(int i=0;i<total_elements;i++)
      Print(EnumToString(array[i]));
}
   
template<typename T>
int enumFillArray(T& res_array[])
{
   ArrayResize(res_array,0);
   int iter = 100000;
   for(int i=-iter;i<iter;i++)
      if(StringFind(EnumToString((T)i),"::")<0)
      {
         int index = ArrayResize(res_array,ArraySize(res_array)+1)-1;
         res_array[index] = (T)i;
      }
   return ArraySize(res_array);
}
 

Sto solo aggiungendo la mia soluzione per le generazioni future su come ho risolto questo.

Quindi il problema è conoscere il numero di voci nell' enum dinamicamente con la possibilità di aggiungere o rimuovere valori enum. Ho bisogno di saperlo per creare array di dimensioni fisse con valori enum come indice dell'array. Quello che tendo a fare è aggiungere un valore riservato alla fine dell'enum che viene usato solo come valore di lunghezza. Ecco un esempio.

enum ENUM_ENTRIES
{
        SMALL_ENTRY = 0,
        MEDIUM_ENTRY,
        LARGE_ENTRY,
        VERY_LARGE_ENTRY,
        _ENUM_ENTRIES
};

ObjectType *entryArray[_ENUM_ENTRIES];

// Setting individual entries
entryArray[MEDIUM_ENTRY] = new ObjectType();
entryArray[LARGE_ENTRY] = new ObjectType();

// Looping through the array
for(int i = 0; i < _ENUM_ENTRIES; i++) {

        entryArray[i] = new ObjectType();       
}
Questo è bello e facile perché non avete bisogno di essere fissati all'ultima voce ovunque come
// Fixed to last entry +1
ObjectType *entryArray[VERY_LARGE_ENTRY + 1];

for(int i = 0; i <= VERY_LARGE_ENTRY; i++) {

}

oppure potete aggiungere più voci alla fine dell'enum e l'array e il ciclo funzioneranno ancora.

/*
 *  Expanded enum entries
 */
enum ENUM_ENTRIES
{
        SMALL_ENTRY = 0,
        MEDIUM_ENTRY,
        LARGE_ENTRY,
        VERY_LARGE_ENTRY,
        EXTRA_LARGE_ENTRY,
        EXTREMELY_LARGE_ENTRY,
        _ENUM_ENTRIES
};

/* 
 * Previous code untouched and still works
 */

ObjectType *entryArray[_ENUM_ENTRIES];

// Setting individual entries
entryArray[MEDIUM_ENTRY] = new ObjectType();
entryArray[LARGE_ENTRY] = new ObjectType();

// Looping through the array
for(int i = 0; i < _ENUM_ENTRIES; i++) {

        entryArray[i] = new ObjectType();       
}
Documentation on MQL5: Constants, Enumerations and Structures / Environment State / Symbol Properties
Documentation on MQL5: Constants, Enumerations and Structures / Environment State / Symbol Properties
  • www.mql5.com
To obtain the current market information there are several functions: SymbolInfoInteger(), SymbolInfoDouble() and SymbolInfoString(). The first parameter is the symbol name, the values of the second function parameter can be one of the identifiers of ENUM_SYMBOL_INFO_INTEGER, ENUM_SYMBOL_INFO_DOUBLE and ENUM_SYMBOL_INFO_STRING. Some symbols...
Motivazione: