¿hay alguna función "StringToEnum" o una alternativa? - página 3

 
cyberglassed:

tu código de arriba es inútil porque siempre devolverá "b = 0"

y la información "b = 0" cada vez no da ninguna información.

no, devuelve 3.


o la última que encuentra.

creo que no me has entendido.

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

¿he entendido bien? ¿empiezas con una cadena?

también puedes envolverla ()

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

pero tienes que asegurarte de que la cadena es una coincidencia exacta por razones obvias, o necesitarás más código para asegurarte de que no se estropea.

 
Marco vd Heijden:

no devuelve 3.

o el último que encuentre.

Creo que me has entendido mal.

sí, después de escribir mi comentario me he dado cuenta de que no usabas "else if" y he cambiado a 3

Marco vd Heijden:

¿lo he entendido bien? ¿empiezas con una cadena?

también puedes envolverla ()

pero tienes que asegurarte de que la cadena es una coincidencia exacta por razones obvias, o necesitará más código para asegurarse de que no va funky.

sí, parto de una cadena, por eso la firma de la función que propongo es

int StringToEnum(string strId);

de todas formas, como todos hemos analizado, la única solución que tenemos hasta ahora es usar múltiples "if" ;)

 

"Entonces en alguna parte quieres especificar algún valor de algún enum en formato de cadena".

No veo ninguna ventaja de esto. ¿Podría mostrar un ejemplo?


Método 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étodo 2:

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

En cualquiera de los dos casos sólo tienes que saber el nombre de la cadena del enum. Además tu código es erróneo este enum empieza desde 0.


 
cyberglassed:

Hola Alain, satisfago tu curiosidad :P

Imagina que estás usando múltiples códigos externos mql5, entonces estás tratando con múltiples tipos de datos "enum" definidos en ellos, y por supuesto, como un humano, es mejor para ti recordar el nombre de cadena de cada valor de cada "enum". Entonces en alguna parte quieres especificar algún valor de algún "enum" en formato de cadena, entonces no puedes hacerlo directamente, así que tienes que usar alguna solución como la que escribí arriba. Esto tiene dos grandes desventajas, la primera es que tienes que recoger todos los valores de todos los enums involucrados y la segunda desventaja es el mantenimiento, por lo que si actualizas algún código mql5 externo donde el desarrollador cambió el valor int asociado a alguna representación constante, entonces podrías obtener un comportamiento inesperado, por lo que tienes que seguir inspeccionando las actualizaciones en el código.

Gracias pero no es realmente lo que pedí. ¿Puedes poner un ejemplo de código concreto?

Estoy 100% seguro de que todo lo que dices sobre la función StringToEnum() proviene de una mala práctica de codificación. El objetivo de un enum es construir código independiente del valor entero subyacente, si este valor se cambia no debería afectar a tu código de ninguna manera. Además no veo por qué no puedes recordar un identificador como MODE_SMA pero sí puedes con una cadena "MODE_SMA".

Sobre el tema de las fugas de seguridad... No estoy totalmente de acuerdo con lo que dices de que es una puerta abierta a las fugas de seguridad. Por supuesto que puede ser una puerta abierta, pero tú como programador tienes que establecer los límites y cuidar de posibles situaciones críticas, quiero decir que puedes manejar perfectamente tales situaciones como en PHP, incluso en SQL con inyección de código donde tienes que analizar algunos posibles datos de entrada críticos de los usuarios en caso de que tengan acceso a tu código.

No he dicho que la seguridad no pueda ser gestionada por el codificador. He dicho que Metaquotes no permitirá que esa seguridad dependa de los programadores. Eso nunca ocurrirá, te sugiero que se lo preguntes a ellos publicando tu solicitud en el ServiceDesk, yo ya sé la respuesta.

 
cyberglassed:

sí, después de escribir mi comentario me di cuenta de que no usabas "else if" y lo cambié por 3

sí, parto de una cadena, por eso la firma de la función que propongo es:

de todas formas, como todos hemos analizado, la única solución que tenemos hasta ahora es usar múltiples "if" ;)


si pero también se puede hacer un bucle y hacerlo en una sola línea.

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


pero aun asi despues de casi 4 paginas ...por queyyy jaja :)

 
Marco vd Heijden:

si pero tambien puedes hacer un bucle y hacerlo en una sola linea.

pero aun asi despues de casi 4 paginas ...por queyyy jaja :)

Laszlo Tormasi:

"Entonces en alguna parte quieres especificar algún valor de algún enum en formato de cadena."

No veo ninguna ventaja de esto. ¿Podrías mostrar un ejemplo?

En cualquiera de los dos casos sólo tienes que saber el nombre de la cadena del enum. Además tu código es erróneo este enum empieza desde 0.

jajaja Marco y Laszlo lo siento, a veces al intentar minificar el problema la curiosidad del otro lado aumenta :P

aquí tenéis un ejemplo muy cercano a lo que quiero conseguir (lo he minificado un poco para no molestaros a todos). El siguiente es un script completo que funciona (copiar/pegar/ejecutar):

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

el tipo de precio se establecerá en el archivo online dado en: "config_url" y su contenido puede ser cambiado en cualquier momento con uno de los siguientes valores:

{PRECIO_CERRADO, PRECIO_ABIERTO, PRECIO_ALTO, PRECIO_BAJO, PRECIO_MEDIANO, PRECIO_TÍPICO, PRECIO_PONDERADO}

El tipo se indicará en forma legible, por ejemplo PRICE_MEDIAN (no un int).

Laszlo, en mql5 el offset es 1 y no 0 (diferente a mql4), lo he comprobado con un simple script y me he sorprendido. Por eso hablo del problema del mantenimiento -> posibles confusiones.
 
Alain Verleyen:

Gracias pero no es realmente lo que pedí. ¿Puedes poner un ejemplo de código concreto?

Estoy 100% seguro de que todo lo que dices sobre la función StringToEnum() proviene de una mala práctica de codificación. El objetivo de un enum es construir código independiente del valor entero subyacente, si este valor se cambia no debería afectar a tu código de ninguna manera. Además no veo por qué no puedes recordar un identificador como MODE_SMA pero sí puedes con una cadena "MODE_SMA".

No he dicho que la seguridad no pueda ser gestionada por el codificador. He dicho que Metaquotes no permitirá que esa seguridad dependa de los programadores. Eso nunca ocurrirá, te sugiero que se lo preguntes a ellos publicando tu solicitud en el ServiceDesk, yo ya sé la respuesta.

Me equivoqué y sé que me encuentro ante una situación en la que necesitaría una función StringToEnum() (genérica para no ser codificada para cada enum). Nunca es tarde para entender, nunca debo estar 100% seguro

 
Alain Verleyen:

Me equivoqué y sé que me enfrento a una situación en la que necesitaría una función StringToEnum() (genérica para no ser codificada para cada enum). Nunca es tarde para entender, nunca debo estar 100% seguro

Ok. Aquí hay una función genérica 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);
  }

Ejemplo de 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 función genérica StringToEnum() :

Ejemplo de uso :

4,5 años después, pero me encontré con este post buscando una solución a esta necesidad para mí. @Alain Verleyen Me alegro de que hayas encontrado un uso para contrarrestar tus respuestas iniciales de "no veo por qué necesitamos esto" y "si necesitas esta función, entonces tu código es malo" 😛 .

Me he encontrado con un número de circunstancias diferentes en las que esto sería útil, pero incluso si tú, o yo, nunca hubiéramos encontrado una necesidad, está la pregunta: si no hay ninguna razón para que StringToEnum() exista, ¿por qué debería haber alguna razón para que EnumToString() exista? O a la inversa, si existe EnumToString(), entonces seguramente no es descabellado pensar que haya veces que convirtamos un enum a una cadena usando esa función, y que luego queramos volver a convertirlo alguna vez 😉 .

Ni que decir tiene que mi ejemplo práctico: tengo un EA que opera en múltiples combinaciones de símbolo/marco de tiempo, a la vez, independientemente del gráfico en el que se esté ejecutando -- sin tener que ejecutarlo en múltiples gráficos a la vez. Hay pros y contras en este enfoque, pero en mi caso los pros superan definitivamente a los contras.

Así que... cuando coloco una operación quiero ver en los comentarios de la operación algunos detalles sobre ella que las funciones de Información de la Operación no proporcionan, uno de los cuales es el marco de tiempo que se utilizó para determinar la lógica de si colocar la operación en primer lugar, ya que esa lógica (algunos de los cuales dependen del marco de tiempo) a veces afectará a cuándo modificar (por ejemplo, SL) o cerrar la operación. Así que quiero ver esa información en una forma legible para el ser humano (por ejemplo, H4, no 14400), pero, por supuesto, también quiero que el EA sea capaz de hacer uso del valor numérico del enum al tomar decisiones sobre la modificación o el cierre de la operación.

Así que uso EnumToString(timeframe) para tener una representación de cadena del timeframe en el comentario. Más tarde puedo obtener el comentario de la operación utilizandoOrderComment() (o la versión correspondiente de mql5) y puedo analizar la representación de la cadena de tiempo del comentario para obtener, por ejemplo, "PERIOD_H4". Una función StringToEnum("...") convertiría esto de nuevo en el valor numérico, que en el caso de los marcos de tiempo es el número de minutos (es decir. el enum no es secuencial de 0 a algo como la mayoría de los enums, hay grandes espacios, por ejemplo, entre D1, W1 y MN1). Por supuesto, también podría incluir el valor entero del enum en el comentario, pero eso es una solución (que debería ser innecesaria) de la ausencia de StringToEnum().

Tu solución parece ser lo mejor que se puede hacer por el momento, excepto que en este caso, tendríamos que aumentar el valor MAX a43200 para ser lo suficientemente amplio como para cubrir eso sin dejar de ser genérico(https://docs.mql4.com/constants/chartconstants/enum_timeframes).

Por supuesto que una función OrderTimeframe() o OrderPeriod() cubriría esa necesidad concreta, pero como digo es una de las pocas circunstancias en las que una función StringToEnum() sería útil. Por lo visto tú también has encontrado una 😉 .

Gracias por compartir tu solución, y felicidades por tu humildad al admitir que estabas equivocado 😊.

Me pregunto si hay alguna lista de todos los posibles enums y valores de enum en algún lugar de la documentación de MQL4/5. Hay esto:https://www.mql5.com/en/docs/constant_indices y la correspondiente versión mql4 de esa página, aunque no lista ninguno de los valores numéricos. Supongo que podría copiar el texto de esa página, parsearlo todo en una lista de valores, y escribir una función que imprima todos los valores posibles. Pero claro, eso es un poco tedioso, además de que no tiene en cuenta cualquier adición futura. Al menos me dirá el máximo valor posible de cualquier enum.

Para ahorrar velocidad probablemente podría adaptar tu función para recorrer todos los valores hasta un máximo de, digamos, 1440 en lugar de 256 (para D1 en el caso de los timeframes, y lo que sea en el caso de otros enums), y luego añadir dos comprobaciones más específicas para W1 y MN1. Aumentar el máximo no añadirá ninguna sobrecarga a todos los casos que todavía encajan en el máximo inferior, ya que cualquier cosa que encaje bajo el máximo inferior sale del bucle en el mismo tiempo de cualquier manera.

¿Hay otros enums con valores numéricos superiores a 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