c'è qualche funzione "StringToEnum" o un'alternativa? - pagina 3

 
cyberglassed:

il tuo codice sopra è inutile perché restituirà sempre "b = 0"

e l'informazione: "b = 0" ogni volta non dà nessuna informazione.

No, restituisce 3.


o l'ultima che incontra.

Credo che tu mi abbia frainteso.

sinput string e_string="MODE_SMMA";// Input Ma Method

int b;
if(e_string==EnumToString(MODE_SMA)){b=0;}
if(e_string==EnumToString(MODE_EMA)){b=1;}
if(e_string==EnumToString(MODE_SMMA)){b=2;}
if(e_string==EnumToString(MODE_LWMA)){b=3;}

Print(b);
 

Ho capito bene? Si inizia con una stringa?

puoi anche avvolgerla ()

int b;
sinput string e_string;// Input Ma Method here AS A STRING 

void OnTick(){StringToEnum();Print(b);} 
  
void StringToEnum()
 {
 if(e_string==EnumToString(MODE_SMA)){b=0;}
 if(e_string==EnumToString(MODE_EMA)){b=1;}
 if(e_string==EnumToString(MODE_SMMA)){b=2;}
 if(e_string==EnumToString(MODE_LWMA)){b=3;}
 }

ma devi assicurarti che la stringa sia una corrispondenza esatta per ovvie ragioni, o avrà bisogno di più codice per assicurarsi che non vada male.

 
Marco vd Heijden:

no restituisce 3.

o l'ultimo che incontra.

Credo che tu mi abbia frainteso.

sì, dopo aver scritto il mio commento ho notato che non hai usato "else if" e ho cambiato in 3

Marco vd Heijden:

Ho capito bene? Si inizia con una stringa ??

puoi anche avvolgerla ()

ma dovevi assicurarti che la stringa sia una corrispondenza esatta per ovvi motivi, altrimenti ci vorrà più codice per assicurarsi che non vada a male.

sì, parto da una stringa, ecco perché la firma della funzione che propongo è:

int StringToEnum(string strId);

comunque, come tutti abbiamo analizzato, l'unico workaround che abbiamo fino ad ora è usare più "if" ;)

 

"Poi in qualche parte vuoi specificare qualche valore di qualche enum in formato stringa".

Non vedo alcun vantaggio in questo. Potresti mostrare un esempio?


Metodo 1:

int StringToEnum(string strId) {         if (false) {}         else if (strId == "PRICE_CLOSE")     return 1;         else if (strId == "PRICE_OPEN")      return 2;         else if (strId == "PRICE_HIGH")      return 3;         else if (strId == "PRICE_LOW")       return 4;         else if (strId == "PRICE_MEDIAN")    return 5;         else if (strId == "PRICE_TYPICAL")   return 6;         else if (strId == "PRICE_WEIGHTED")  return 7;         // ...         return -1; } void OnStart() {         string strId = "PRICE_MEDIAN";         printf("%s: %d ", strId, StringToEnum(strId)); }

Metodo 2:

void OnStart() {
        ENUM_APPLIED_PRICE b=PRICE_MEDIAN;
        
        printf("%s: %d ", EnumToString(b), b);
}

Devi conoscere solo il nome della stringa dell'enum in entrambi i casi. Anche il tuo codice è sbagliato questo enum parte da 0.


 
cyberglassed:

Ciao Alain, soddisfo la tua curiosità :P

Immagina di utilizzare più codici esterni mql5, quindi hai a che fare con più tipi di dati "enum" definiti su di essi, e naturalmente, come un umano, è meglio per te ricordare il nome della stringa di ogni valore di ogni "enum". Poi in alcune parti vuoi specificare qualche valore di qualche enum in formato stringa, allora non puoi farlo direttamente, quindi devi usare qualche workaround come ho scritto sopra. Questo ha due grossi svantaggi, il primo è che devi raccogliere tutti i valori di tutti gli enum coinvolti e il secondo svantaggio è la manutenzione, quindi se aggiorni qualche codice mql5 esterno dove lo sviluppatore ha cambiato il valore int associato a qualche rappresentazione costante allora potresti ottenere un comportamento inaspettato, quindi devi continuare a controllare gli aggiornamenti del codice.

Grazie ma non è proprio quello che ho chiesto. Puoi postare un esempio concreto di codice?

Sono sicuro al 100% che tutti i tuoi punti sulla funzione StringToEnum() provengono da una cattiva pratica di codifica. L'obiettivo di un enum è quello di costruire codice indipendente dal valore intero sottostante, se questo valore viene cambiato non dovrebbe avere alcun impatto sul tuo codice. Inoltre non vedo perché non puoi ricordare un identificatore come MODE_SMA ma puoi con una stringa "MODE_SMA".

Riguardo all'argomento della fuga di sicurezza... Non sono totalmente d'accordo con quello che hai detto sul fatto che sia una porta aperta alla fuga di sicurezza. Certamente potrebbe essere una porta aperta, ma tu come programmatore devi impostare i limiti e prenderti cura di possibili situazioni critiche, voglio dire che puoi gestire perfettamente tali situazioni come in PHP, anche su SQL con l'iniezione di codice dove devi analizzare alcuni dati critici possibili in ingresso dagli utenti nel caso in cui abbiano accesso al tuo codice.

Non ho detto che la sicurezza non può essere gestita dal codificatore. Ho detto che Metaquotes NON permetterà che la sicurezza dipenda dai programmatori. Questo non accadrà mai, ti suggerisco di chiedere a loro postando una richiesta al ServiceDesk, so già la risposta.

 
cyberglassed:

sì, dopo aver scritto il mio commento ho notato che non hai usato "else if" e ho cambiato in 3

sì, parto da una stringa, ecco perché la firma della funzione che propongo è:

comunque, come tutti abbiamo analizzato, l'unico workaround che abbiamo fino ad ora è usare più "if" ;)


sì, ma si può anche fare il loop e farlo in una sola riga.

 //string in="MODE_SMA";  //uncheck either one
 //string in="MODE_EMA";
 string in="MODE_SMMA";
 //string in="MODE_LWMA";    

void OnTick()

{
 int out;
 
 for(int i=0;i<=3;i++){ENUM_MA_METHOD mode=i;if(in==EnumToString(mode)){out=i;Print("out: ",out);}} 
}


ma ancora dopo quasi 4 pagine ...whyyyyy haha :)

 
Marco vd Heijden:

Sì, ma si può anche fare un loop e farlo in una sola riga.

ma ancora dopo quasi 4 pagine ...whyyyy haha :)

Laszlo Tormasi:

"Poi in qualche parte vuoi specificare qualche valore di qualche enum in formato stringa".

Non vedo alcun vantaggio di questo. Potresti mostrare un esempio?

Devi conoscere solo il nome della stringa dell'enum in entrambi i casi. Anche il tuo codice è sbagliato questo enum parte da 0.

hahaha Marco e Laszlo scusate, a volte quando si cerca di minificare il problema la curiosità dall'altra parte aumenta :P

Qui avete un esempio molto vicino a quello che voglio ottenere (l'ho minificato un po' per evitare di infastidire tutti voi). Quello che segue è uno script completo e funzionante (copia/incolla/esegui):

string get_price_type() {
        string
                config_url = "http://tempsend.com/D56DA3A9EA/CBB5/config.txt", /* available for 30 days from now */
                cookie = NULL,
                headers,
                ret;
        char
                post[],
                result[];               

        // WebRequest needs the following configuration:
        // 1- check: Tools/Options/Expert Advisors/Allow WebRequest for listed URL
        // 2- add url: http://tempsend.com  [this is the domain name on: config_url]
        int res = WebRequest("GET", config_url, cookie, NULL, 5000,  post, 0, result, headers);
        
        if (res == -1) {
                Print("Error in WebRequest. Error code: ", GetLastError());
                ret = "Error";
        }
        else {
                ret = CharArrayToString(result);
                StringTrimRight(ret);
        }
        return ret;
}

int StringToEnum(string strId) {
        if (false) {}
        else if (strId == "PRICE_CLOSE")     return 1;
        else if (strId == "PRICE_OPEN")      return 2;
        else if (strId == "PRICE_HIGH")      return 3;
        else if (strId == "PRICE_LOW")       return 4;
        else if (strId == "PRICE_MEDIAN")    return 5;
        else if (strId == "PRICE_TYPICAL")   return 6;
        else if (strId == "PRICE_WEIGHTED")  return 7;
        return -1;
}

void OnStart() {
        string price_type = get_price_type();
        int price_type_int = StringToEnum(price_type);
        printf("price_type -> %s: %d", price_type, price_type_int);
        
        ChartSetInteger(0, CHART_SCALE, 3);
        ChartSetInteger(0, CHART_MODE, CHART_CANDLES);

        int handle = iMA("EURUSD", PERIOD_CURRENT, 10, 0, MODE_SMA, price_type_int);
        ChartIndicatorAdd(0, 0, handle);
}

il tipo di prezzo sarà impostato sul file online dato su: "config_url" e il suo contenuto può essere cambiato in qualsiasi momento con uno dei seguenti valori:

{PREZZO_CHIUSO, PREZZO_APERTO, PREZZO_ALTO, PREZZO_BASSO, PREZZO_MEDIO, PREZZO_TIPICO, PREZZO_PESATO}

Il tipo sarà dato in forma leggibile all'uomo, per esempio: PRICE_MEDIAN (non un int).

Laszlo, su mql5 l'offset è 1 e non 0 (diverso da mql4), ho controllato con un semplice script e sono rimasto sorpreso. Ecco perché parlo del problema della manutenzione -> possibili confusioni.
 
Alain Verleyen:

Grazie ma non è proprio quello che ho chiesto. Puoi postare un esempio concreto di codice?

Sono sicuro al 100% che tutti i tuoi punti sulla funzione StringToEnum() provengono da una cattiva pratica di codifica. L'obiettivo di un enum è quello di costruire codice indipendente dal valore intero sottostante, se questo valore viene cambiato non dovrebbe avere alcun impatto sul tuo codice. Inoltre non vedo perché non puoi ricordare un identificatore come MODE_SMA ma puoi con una stringa "MODE_SMA".

Non ho detto che la sicurezza non può essere gestita dal codificatore. Ho detto che Metaquotes NON permetterà che la sicurezza dipenda dai programmatori. Questo non accadrà mai, ti suggerisco di chiedere a loro postando una richiesta al ServiceDesk, so già la risposta.

Mi sbagliavo e so di dover affrontare una situazione in cui avrei bisogno di una funzione StringToEnum() (generica da non codificare per ogni enum). Non è mai troppo tardi per capire, non dovrei mai essere sicuro al 100%

 
Alain Verleyen:

Mi sono sbagliato e so di trovarmi di fronte a una situazione in cui avrei bisogno di una funzione StringToEnum() (generica non da codificare per ogni enum). Non è mai troppo tardi per capire, non dovrei mai essere sicuro al 100%

Ecco una funzione generica StringToEnum():

#define MIN_ENUM_VALUES 0
#define MAX_ENUM_VALUES 255
//+------------------------------------------------------------------+
//| StringToEnum : Convert a string to an ENUM value,                |
//|   it loop between min(0) and max(255), adjustable if needed.     |
//|   Non existing enum value defined as -1. If -1 is used as an     |
//|   enum value, code need to be adjusted to an other default.      |
//| Parameters :                                                     |
//|   in       - string to convert                                   |
//|   out      - ENUM value                                          |
//|   @return  - true if conversion succeed, false otherwise         |
//+------------------------------------------------------------------+
template<typename ENUM>
bool StringToEnum(string in,ENUM &out)
  {
   out=-1;
//---
   for(int i=MIN_ENUM_VALUES;i<=MAX_ENUM_VALUES;i++)
     {
      ENUM enumValue=(ENUM)i;
      if(in==EnumToString(enumValue))
        {
         out=enumValue;
         break;
        }
     }
//---
   return(out!=-1);
  }

Esempio d'uso:

//+------------------------------------------------------------------+
//| testing enums                                                    |
//+------------------------------------------------------------------+
enum ENUM_TEST
  {
   FIRST_CASE=1,
   SECOND_CASE=2

  };
//---
enum ENUM_ANOTHER_TEST
  {
   CASE_ONE,
   CASE_TWO,
   CASE_THREE
  };
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void  OnStart()
  {
   ENUM_TEST which;
   if(!StringToEnum("SECOND_CASE",which)) return;

   ENUM_ANOTHER_TEST which_other;
   if(!StringToEnum("CASE_ONE",which_other)) return;

   ENUM_TEST wrongwhich;
   if(!StringToEnum("blah blah",wrongwhich)) return;

//---
  }
 
Alain Verleyen funzione generica StringToEnum():

Esempio d'uso:

4,5 anni dopo, ma mi sono imbattuto in questo post cercando una soluzione a questo bisogno per me stesso. @Alain Verleyen Sono contento che tu abbia trovato un uso per contrastare le tue risposte iniziali "non vedo perché abbiamo bisogno di questo" e "se hai bisogno di questa funzione, allora il tuo codice è cattivo" 😛

Mi sono imbattuto in una serie di circostanze diverse in cui questo sarebbe utile, ma anche se tu, o io, non avessimo mai trovato un bisogno, c'è la domanda: se non c'è motivo che StringToEnum() esista, perché dovrebbe esserci un motivo che EnumToString() esista? O al contrario, se EnumToString() esiste, allora sicuramente non è irragionevole pensare che ci potrebbero essere delle volte in cui dovremmo convertire un enum in una stringa usando quella funzione, e poi volerlo riconvertire qualche volta? 😉

Inutile dire il mio esempio pratico: ho un EA che opera su più combinazioni di simboli/timeframe, in una sola volta, indipendentemente dal grafico su cui viene eseguito -- senza doverlo eseguire su più grafici contemporaneamente. Ci sono pro e contro di questo approccio, ma nel mio caso i pro superano decisamente i contro.

Quindi... quando piazzo una compravendita voglio vedere nei commenti della compravendita alcuni dettagli che le funzioni Trade Info non forniscono, uno dei quali è il timeframe che è stato usato per determinare la logica per piazzare la compravendita in primo luogo, dato che questa logica (che dipende in parte dal timeframe) a volte influisce su quando modificare (per esempio SL) o chiudere la compravendita. Quindi voglio vedere queste informazioni in una forma leggibile dall'uomo (es. H4, non 14400), ma naturalmente voglio anche che l'EA sia in grado di utilizzare il valore numerico dell'enum quando prende decisioni sulla modifica o la chiusura del trade.

Quindi uso EnumToString(timeframe) per avere una rappresentazione stringa del timeframe nel commento. In seguito posso ottenere il commento dalla negoziazione usandoOrderComment() (o la versione corrispondente di mql5) e posso quindi analizzare la rappresentazione stringa del timeframe dal commento per ottenere ad es. "PERIOD_H4". Una funzione StringToEnum("...") lo riconvertirebbe in valore numerico, che nel caso dei timeframe è il numero di minuti (es. l'enum non è sequenziale da 0 a qualcosa come la maggior parte degli enum, ci sono grandi spazi vuoti, ad esempio tra D1, W1 e MN1). Naturalmente potrei anche includere il valore intero dell'enum nel commento, ma questo è un workaround (che non dovrebbe essere necessario) dell'assenza di StringToEnum().

La tua soluzione sembra essere la migliore al momento, tranne che in questo caso, dovremmo aumentare il valore MAX a43200 per essere abbastanza completi da coprire questo pur rimanendo generici(https://docs.mql4.com/constants/chartconstants/enum_timeframes).

Naturalmente una funzione OrderTimeframe() o OrderPeriod() soddisferebbe questa specifica esigenza, ma come ho detto è solo una delle poche circostanze in cui una funzione StringToEnum() sarebbe utile. A quanto pare ne hai trovata una anche tu 😉

Grazie per aver condiviso la tua soluzione e complimenti a te per la tua umiltà nell'ammettere di aver sbagliato 😊

Mi chiedo se ci sia una lista di tutti i possibili enum e valori enum da qualche parte nella documentazione MQL4/5. C'è questo:https://www.mql5.com/en/docs/constant_indices e la corrispondente versione mql4 di quella pagina, anche se non elenca nessuno dei valori numerici. Suppongo che potrei copiare il testo di quella pagina, analizzarlo in una lista di valori e scrivere una funzione per stampare tutti i possibili valori, ma ovviamente questo è un po' noioso e non tiene conto di eventuali aggiunte future. Almeno mi dirà il massimo valore possibile di ogni enum.

Per risparmiare velocità potrei probabilmente adattare la tua funzione per fare un loop di tutti i valori fino a un massimo di, diciamo, 1440 invece di 256 (per D1 nel caso dei timeframes, e qualsiasi altra cosa nel caso di altri enum), e poi aggiungere due controlli più specifici per W1 e MN1. Aumentare il massimo non aggiungerà alcun overhead a tutti i casi che rientrerebbero ancora nel massimo inferiore, dato che qualsiasi cosa che rientra nel massimo inferiore esce comunque dal loop nello stesso tempo.

Ci sono altri enum con valori numerici che vanno oltre 1440?

Chart Timeframes - Chart Constants - Constants, Enumerations and Structures - MQL4 Reference
Chart Timeframes - Chart Constants - Constants, Enumerations and Structures - MQL4 Reference
  • docs.mql4.com
Chart Timeframes - Chart Constants - Constants, Enumerations and Structures - MQL4 Reference
Motivazione: