¿Alguien sabe cómo desarrollar un indicador multidivisa?

 
¿Alguien sabe cómo desarrollar un indicador multidivisa?

Quiero elegir ENTRE 1 y 10 monedas diferentes y 5 barras para cada moneda.

Pero no sé cómo hacer esto.

 

En un indicador estándar, usted construiría las matrices del buffer con los datos de los parámetros enviados a través de la función de evento OnCalulate( ... ). Pero, para la multidivisa y/o el marco de tiempo múltiple, usted tendrá que utilizar una de dos soluciones:

  • Utilizar el método antiguo de las variaciones de "iFunction", como iTime(), iVolume, iOpen, iClose, etc. pero con un símbolo diferente como "EURUSD", "JPYUSD", etc. en lugar del _Symbol o Symbol() por defecto.
  • Utilizando el método más nuevo de la primera variante de la función ArrayCopyRates() junto con los punteros de los arrays de MqlRates. Los arrays "copiados", en realidad no ocuparán ningún espacio y sólo serán punteros a los datos existentes de los distintos símbolos y time-frames.

Sin embargo, para que esto funcione, una de las dos condiciones tiene que existir para que el multisímbolo y/o el multitramo de tiempo funcionen:

  • O bien los gráficos respectivos para los símbolos y los marcos temporales ya están abiertos, para que no se genere ningún error,
  • o obtendrás un error 4066 (ERR_HISTORY_WILL_UPDATED) la primera vez que solicites los datos, y tendrás que codificar un bucle sleep & retry, para esperar a que se descarguen los datos y volver a solicitarlos.

Mi solución personal sugerida, que encuentro como la manera más eficiente y fácil de manejar el error 4066, es el método ArrayCopyRates() y MqlRates .

Hay más información sobre esto en la documentación y archivos de ayuda de MQL4.

P.D. ¡NB! Cuando acceda a las funciones incorporadas de los indicadores, como iMA(), iATR(), etc. para los distintos símbolos y marcos temporales, recuerde implementar también los bucles de reposo y reintento para no obtener tampoco el error 4066. Aquí hay una cita de la documentación de MQL4:

Any indicator can be calculated on the data of not only current chart, but also on the data of any available symbol/period. If data (symbol name and/or timeframe differ from the current ones) are requested from another chart, the situation is possible that the corresponding chart was not opened in the client terminal and the necessary data must be requested from the server. In this case, error ERR_HISTORY_WILL_UPDATED (4066 - the requested history data are under updating) will be placed in the last_error variable, and one will has to re-request (see example of ArrayCopySeries())
 
Recuerda que el OP está preguntando por un indicador. Sleep() se ignora en los indicadores
 
GumRai:
Recuerde, el OP está preguntando acerca de un indicador. Sleep() se ignora en los indicadores

Lo siento, no lo sabía. Yo uso este método bastante en EA's pero no en Indicadores, así que no sabía de la desventaja del sueño.

En ese caso, tendrá que construir un bucle de reintento en torno a las llamadas sucesivas en cada llamada a la función OnCalculate() (donde el uso de ArrayCopyRates() es la mejor solución).

Alternativamente, si funciona en la función OnInit (), podría ser el método preferido para preparar los datos para el indicador, con un conteo de reintentos muy largo (sin el sleep) para este caso.

 
FMIC:

...

  • o obtendrá un error 4066 (ERR_HISTORY_WILL_UPDATED) la primera vez que solicite los datos, y tendrá que codificar un bucle sleep & retry, para esperar a que se descarguen los datos y volver a solicitarlos.

P.D. ¡NB! Cuando acceda a las funciones incorporadas de los indicadores, como iMA(), iATR(), etc. para los distintos símbolos y marcos temporales, recuerde implementar también los bucles de reposo y reintento para no obtener tampoco el error 4066. Aquí hay una cita de la documentación de MQL4:


A menos que hayan cambiado algo recientemente, obtendrá el error 4066 cada vez que la primera llamada a la función (y sólo de esta primera llamada), independientemente de las condiciones o el progreso de actualización de la historia. No tiene ninguna utilidad práctica.
 
Ovo:
A menos que hayan cambiado algo recientemente, obtendrá el error 4066 cada vez desde la primera llamada a la función (y sólo desde esta primera llamada), independientemente de las condiciones o del progreso de la actualización del historial. No tiene ninguna utilidad práctica.
Este no ha sido mi caso. Cuando los datos ya están totalmente disponibles, no obtengo el error 4066. Sin embargo, si no está disponible directamente, entonces sí que obtengo el error sólo en la primera llamada de cualquier función para ese símbolo y time.frame en particular. Después de eso, cualquier otra función que solicite esos datos, ya no da el error.
 

FMIC:

En ese caso, tendrá que construir un bucle de reintento en torno a las sucesivas llamadas en cada tick a la función OnCalculate() (donde el uso de ArrayCopyRates() es la mejor solución).

Alternativamente, si funciona en la función OnInit(), podría ser el método preferido para preparar los datos para el indicador, con un conteo de reintentos muy largo (sin el sleep) para este caso.

  1. Un bucle (largo o no) en el indicador no funcionará. Mientras el indicador se está ejecutando no puede ocurrir nada más en la terminal. Por eso Sleep no puede funcionar en los indicadores. Y por qué ArrayCopyRates es asíncrono (para los indicadores.)
  2. Habilite la matriz de tasas en init. Pruébelo en OnTick, y maneje los reintentos allí. También recuerde que diferentes gráficos crean nuevas barras en diferentes momentos.
    string pairs[] = {"EURUSD", "GBPUSD" ...}
    MqlRates pair0[], pair1[], ...
    bool initial;
    OnInit(){ initial=true;
       ArrayCopyRates(pair0, pairs[0], _Period);   
       ArrayCopyRates(pair1, pairs[1], _Period);
       :
    }
    OnCalculate( ... ){
       int count = IndicatorCounted();
       if(initial){
          if(pair1[0].time == 0) return;
          if(pair2[0].time == 0) return;
          :
          initial=false; count = 0; // process all bars
       }
       for(int i = Bars - 1 - MathMax(lookback, count); i >= 0; --i){
          int shift0 = iBarsShift(pairs[0], _Period, Time[i]);
          int shift1 = iBarsShift(pairs[1], _Period, Time[i]);
          buffer[i] = pair0[shift0].close - pair1[shift1].close;

  3. Si no quieres usar ArrayCopyRates no tienes que hacerlo, pero aún así debes cargar los otros pares reemplazando [en el if(initial)] el parN[0].time con iTime().
 
   if(pair1[0].time == 0) return;

Esto nunca será cierto.

Si hay algún historial cargado para el símbolo y el marco temporal, la función recuperará el valor más reciente.

Si no hay ningún historial cargado, obtendrá un error de Array out of range.

Lo mismo con iTime, etc.

 
GumRai:

Esto nunca será cierto.

Si hay algún historial cargado para el símbolo y el marco temporal, la función recuperará el valor más reciente.

Si no hay ningún historial cargado, obtendrá un error de Array out of range.

Lo mismo con iTime, etc.

Estoy de acuerdo.

Personalmente, sólo compruebo el valor de retorno de "ArrayCopyRates()" y después me limito a controlar el tamaño del array antes de acceder a los datos del mismo.

Con respecto a "iTime()" y otras funciones similares, siempre compruebo primero "iBars()".

 
GumRai:

Esto nunca será cierto.

  if(pair1[0].time == 0) return;

Si hay algún historial cargado para el símbolo y el marco temporal, la función recuperará el valor más reciente.

Si no hay ningún historial cargado, obtendrá un error de Array out of range.

Lo mismo con iTime, etc.

Hay muchos ejemplos históricos (antes de la construcción de 600) para mirar un ACR. No hay otra forma de hacerlo. Las llamadas posteriores a ACR o iTime NO devolverán 4066, así que cómo se puede saber si los datos se han descargado.

iTime siempre ha devuelto cero en caso de error.

 
WHRoeder:

Hay muchos ejemplos históricos (pre-build 600) de mirar un ACR. No hay otra forma de hacerlo. Las llamadas posteriores a ACR o iTime NO devolverán el 4066, así que cómo se puede saber si los datos han sido descargados.

iTime siempre ha devuelto cero en un error.

¿Qué quieres decir con que "no hay otra forma de hacerlo"?

Comprobar el recuento de retornos de "ArrayCopyRates", y comprobar el tamaño del array, parece ser un método más robusto de comprobación, que hacer "pair1[0].time == 0" que puede devolver fácilmente unerror "Array index is out of range".

EDIT: He eliminado algunas de mis afirmaciones después de releer tu mensaje con más atención.