existe-t-il une fonction "StringToEnum" ou une alternative ? - page 3

 
cyberglassed:

votre code ci-dessus est inutile car il retournera toujours "b = 0".

et l'info "b = 0" à chaque fois ne donne aucune information.

non il renvoie 3.


ou la dernière qu'il rencontre.

je suppose que vous ne m'avez pas compris.

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);
 

est-ce que j'ai bien compris ? vous commencez avec une chaîne ? ?

tu peux aussi l'envelopper ()

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;}
 }

mais il faut s'assurer que la chaîne de caractères est une correspondance exacte pour des raisons évidentes, sinon il faudra plus de code pour s'assurer qu'il n'y a pas de problème.

 
Marco vd Heijden:

Non, elle renvoie 3.

ou le dernier qu'il rencontre.

Je crois que vous m'avez mal compris.

Oui, après avoir écrit mon commentaire, j'ai remarqué que tu n'avais pas utilisé "else if" et j'ai changé pour 3.

Marco vd Heijden:

J'ai bien compris ? Vous commencez avec une chaîne de caractères ? ?

vous pouvez aussi l'envelopper ()

mais tu dois t'assurer que la chaîne de caractères est une correspondance exacte pour des raisons évidentes, sinon il faudra plus de code pour s'assurer que ça ne devient pas funky.

oui, je commence par une chaîne, c'est pourquoi la signature de la fonction que je propose est :

int StringToEnum(string strId);

de toute façon, comme nous l'avons tous analysé, la seule solution que nous avons jusqu'à présent est d'utiliser plusieurs "if" ;)

 

"Ensuite, à un moment donné, vous voulez spécifier la valeur d'un certain enum au format chaîne."

Je ne vois pas d'avantage à cela. Pourriez-vous montrer un exemple ?


Méthode 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)); }

Méthode 2 :

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

Vous ne devez connaître que le nom de l'énumération dans les deux cas. Votre code est également erroné, cette énumération commence à partir de 0.


 
cyberglassed:

Bonjour Alain, je réponds à votre curiosité :P

Imaginez que vous utilisez plusieurs codes mql5 externes, alors vous avez affaire à plusieurs types de données "enum" définis sur eux, et bien sûr, comme un humain, il est préférable pour vous de vous rappeler le nom de la chaîne de chaque valeur de chaque "enum". Ensuite, à un moment donné, si vous voulez spécifier une valeur d'un enum au format chaîne de caractères, vous ne pouvez pas le faire directement, vous devez donc utiliser une solution de contournement comme je l'ai écrit ci-dessus. Cela a deux grands inconvénients : le premier est que vous devez collecter toutes les valeurs de tous les enums concernés et le second est la maintenance. Si vous mettez à jour un code mql5 externe dans lequel le développeur a changé la valeur int associée à une représentation constante, vous pouvez obtenir un comportement inattendu et vous devez continuer à inspecter les mises à jour du code.

Merci mais ce n'est pas vraiment ce que j'ai demandé. Pouvez-vous poster un exemple concret de code ?

Je suis sûr à 100% que toutes vos remarques sur la fonction StringToEnum() proviennent d'une mauvaise pratique de codage. Le but d'un enum est de construire un code indépendant de la valeur entière sous-jacente, si cette valeur est changée cela ne devrait pas avoir d'impact sur votre code en aucune façon. De plus, je ne vois pas pourquoi vous ne pouvez pas vous souvenir d'un identifiant comme MODE_SMA mais que vous pouvez le faire avec une chaîne de caractères "MODE_SMA".

A propos du sujet de la fuite de sécurité... Je ne suis pas totalement d'accord avec ce que vous avez dit sur le fait que c'est une porte ouverte aux fuites de sécurité. Bien sûr, il pourrait être une porte ouverte, mais vous en tant que programmeur doit fixer les limites et de prendre soin des situations critiques possibles, je veux dire que vous pouvez gérer parfaitement de telles situations comme en PHP, même sur SQL avec l'injection de code où vous devez analyser certaines données d'entrée critiques possibles des utilisateurs au cas où ils ont accès à votre code.

Je n'ai pas dit que la sécurité ne peut pas être gérée par le codeur. J'ai dit que Metaquotes ne permettra pas que cette sécurité dépende des programmeurs. Cela n'arrivera jamais, je vous suggère de leur demander en postant votre demande au ServiceDesk, je connais déjà la réponse.

 
cyberglassed:

oui, après avoir écrit mon commentaire, j'ai remarqué que vous n'avez pas utilisé "else if" et j'ai changé pour 3

oui, je commence à partir d'une chaîne, c'est pourquoi la signature de la fonction que je propose est :

de toute façon, comme nous l'avons tous analysé, la seule solution que nous avons jusqu'à présent est d'utiliser plusieurs "if" ;)


oui mais vous pouvez aussi boucler cela et le faire en une seule ligne.

 //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);}} 
}


mais quand même après presque 4 pages...pourquoi ? haha :)

 
Marco vd Heijden:

oui mais vous pouvez aussi boucler cela et le faire en une seule ligne.

mais quand même après presque 4 pages ....pourquoiyyy haha :)

Laszlo Tormasi:

"Puis sur une partie vous voulez spécifier une valeur d'un enum dans un format de chaîne."

Je ne vois pas d'avantage à cela. Pourriez-vous montrer un exemple ?

Vous ne devez connaître que le nom de la chaîne de l'enum dans les deux cas. Votre code est également erroné, cet enum commence à 0.

hahaha Marco et Laszlo désolé, parfois quand on essaie de minimiser le problème la curiosité de l'autre côté augmente :P

Voici un exemple très proche de ce que je veux obtenir (je l'ai un peu réduit pour ne pas vous ennuyer tous). Ce qui suit est un script complet qui fonctionne (copier/coller/exécuter) :

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);
}

le type de prix sera défini sur le fichier en ligne donné sur : "config_url" et son contenu peut être modifié à tout moment avec l'une des valeurs suivantes :

{PRIX_FERMÉ, PRIX_OUVERT, PRIX_HAUT, PRIX_BAS, PRIX_MÉDIAN, PRIX_TYPIQUE, PRIX_PONDÉRÉ}.

Le type sera donné sous une forme lisible par l'homme, par exemple : PRICE_MEDIAN (pas un int).

Laszlo, sur mql5 l'offset est 1 et non 0 (différent de mql4), je l'ai vérifié avec un script simple et j'ai été surpris. C'est pourquoi je parle du problème de maintenance -> confusions possibles.
 
Alain Verleyen:

Merci mais ce n'est pas vraiment ce que j'ai demandé. Pouvez-vous poster un exemple concret de code ?

Je suis sûr à 100% que toutes vos remarques sur la fonction StringToEnum() proviennent d'une mauvaise pratique de codage. Le but d'un enum est de construire un code indépendant de la valeur entière sous-jacente, si cette valeur est changée cela ne devrait pas avoir d'impact sur votre code en aucune façon. De plus, je ne vois pas pourquoi vous ne pouvez pas vous souvenir d'un identifiant comme MODE_SMA mais que vous pouvez le faire avec une chaîne de caractères "MODE_SMA".

Je n'ai pas dit que la sécurité ne peut pas être gérée par le codeur. J'ai dit que Metaquotes ne permettra pas que cette sécurité dépende des programmeurs. Cela n'arrivera jamais, je vous suggère de leur demander en postant votre demande au ServiceDesk, je connais déjà la réponse.

Je me suis trompé et je suis maintenant confronté à une situation où j'aurais besoin d'une fonction StringToEnum() (générique à ne pas coder pour chaque enum). Il n'est jamais trop tard pour comprendre, je ne dois jamais être sûr à 100%.

 
Alain Verleyen:

Je me suis trompé et je suis maintenant confronté à une situation où j'aurais besoin d'une fonction StringToEnum() (générique et non à coder pour chaque enum). Il n'est jamais trop tard pour comprendre, je ne dois jamais être sûr à 100%.

Ok. Voici une fonction générique 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);
  }

Exemple d'utilisation :

//+------------------------------------------------------------------+
//| 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 fonction générique StringToEnum() :

Exemple d'utilisation :

4,5 ans plus tard, mais je suis tombé sur ce post en cherchant une solution à ce besoin pour moi-même. @Alain Verleyen Je suis content que vous ayez trouvé une utilisation pour contrer vos réponses initiales "je ne vois pas pourquoi nous avons besoin de ça" et "si vous avez besoin de cette fonction, alors votre code est mauvais". 😛

J'ai rencontré un certain nombre de circonstances différentes où cela serait utile, mais même si vous, ni moi, n'avions jamais trouvé de besoin, la question se pose : s'il n'y a aucune raison pour que StringToEnum() existe, pourquoi devrait-il y avoir une raison pour que EnumToString() existe ? Ou inversement, si EnumToString() existe, alors il n'est sûrement pas déraisonnable de penser qu'il pourrait y avoir des moments où nous convertirions un enum en chaîne de caractères à l'aide de cette fonction, et où nous voudrions ensuite le reconvertir de temps en temps... 😉 .

Inutile de dire que mon exemple pratique : j'ai un EA qui fonctionne sur plusieurs combinaisons de symboles/trames temporelles, à la fois, indépendamment du graphique sur lequel il s'exécute -- sans avoir à l'exécuter sur plusieurs graphiques à la fois. Il y a des avantages et des inconvénients à cette approche, mais dans mon cas, les avantages l'emportent nettement sur les inconvénients.

Ainsi... lorsque je place une transaction, je veux voir dans les commentaires de la transaction quelques détails que les fonctions d'information sur les transactions ne fournissent pas, l'un d'entre eux étant l'horizon temporel utilisé pour déterminer la logique de placement de la transaction en premier lieu, car cette logique (dont une partie dépend de l'horizon temporel) affectera parfois le moment de modifier (par exemple, le SL) ou de fermer la transaction. Je veux donc voir cette information sous une forme lisible par l'homme (par exemple H4, et non 14400), mais bien sûr je veux aussi que l'EA soit capable d'utiliser la valeur numérique de l'enum lorsqu'il prend la décision de modifier ou de fermer la transaction.

J'utilise donc EnumToString(timeframe) pour avoir une représentation sous forme de chaîne de caractères de l'horizon temporel dans le commentaire. Plus tard, je peux obtenir le commentaire de la transaction à l'aide de lafonction OrderComment() (ou de la version mql5 correspondante), puis analyser la représentation sous forme de chaîne de l'horizon temporel à partir du commentaire pour obtenir, par exemple, "PERIOD_H4". Une fonction StringToEnum("...") reconvertirait cette valeur en valeur numérique, qui, dans le cas des horizons temporels, correspond au nombre de minutes (c'est-à-dire que l'enum n'est pas séquentiel à partir de l'horizon temporel).Bien sûr, je pourrais aussi inclure la valeur entière de l'énumération dans le commentaire, mais c'est un contournement (qui devrait être inutile) de l'absence de StringToEnum().

Votre solution semble être aussi bonne que possible pour le moment, sauf que dans ce cas, nous devrions augmenter la valeur MAX à43200 pour être assez complet pour couvrir cela tout en restant générique(https://docs.mql4.com/constants/chartconstants/enum_timeframes).

Bien sûr, une fonction OrderTimeframe() ou OrderPeriod() répondrait à ce besoin spécifique, mais comme je le dis, ce n'est qu'une des quelques circonstances où une fonction StringToEnum() serait utile. Apparemment, vous en avez aussi trouvé une 😉 .

Merci d'avoir partagé votre solution, et bravo à vous pour votre humilité à admettre que vous aviez tort. 😊

Je me demande s'il n'y a pas une liste de tous les enums et valeurs d'enum possibles quelque part dans la documentation de MQL4/5. Il y a ceci: https://www.mql5.com/en/docs/constant_indices et la version mql4 correspondante de cette page, bien qu'elle ne liste aucune des valeurs numériques. Je suppose que je pourrais copier le texte de cette page, l'analyser pour en faire une liste de valeurs, et écrire une fonction pour imprimer toutes les valeurs possibles. Mais bien sûr, c'est un peu fastidieux, et cela ne tient pas compte des ajouts futurs. Au moins, cela me donnera la valeur maximale possible de chaque enum.

Pour gagner en rapidité, je pourrais probablement adapter votre fonction pour qu'elle boucle sur toutes les valeurs jusqu'à un maximum de, disons, 1440 au lieu de 256 (pour D1 dans le cas des délais, et n'importe quoi d'autre dans le cas des autres enums), et ensuite ajouter deux vérifications plus spécifiques pour W1 et MN1. Augmenter le maximum n'ajoutera pas de surcharge à tous les cas qui entreraient encore dans le maximum inférieur, puisque tout ce qui entre dans le maximum inférieur sort de la boucle en même temps, de toute façon.

Existe-t-il d'autres enums dont les valeurs numériques sont supérieures à 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
Raison: