¿Alguien sabe cómo desarrollar un indicador multidivisa? - página 4

 

Bueno chicos, la primera parte está hecha ( lectura de todas las tarifas de los pares ).

Ahora necesito utilizar las tasas de todos los paris copiados con la función ArrayCopyRates para potenciar algunos indicadores gráficos como un RSI... como dibujo en la imagen de abajo:

En mi pregunta inicial pretendo saber como hacer esto... y no sobre la lectura de tasas. No creo que sea necesario copiar las tasas antes de dibujarlas, pero era bueno saber cómo hacerlo... ahora sólo necesito descubrir una manera de dividir el área del indicador para trazar todos los pares...

 
Comprender. Entonces todos los elementos deben ser dibujados como objetos.
 

Este es un indicador que recogí en algún lugar, nunca traté de descifrarlo. Muestra una representación de 3 marcos de tiempo del gráfico actual. Lo loco es que las velas se dibujan con Histogramas. Bastante limpio, pero no es lo que estoy en este momento.

Saludos cordiales

Archivos adjuntos:
 
Bien, gracias. Estoy de viaje en el trabajo y cuando vuelva lo probaré.
 
Fernando Carreiro:

¡Una actualización para aquellos que siguen este hilo!

He estado ayudando al OP vía PM a arreglar su código ya que tiene dificultades con el inglés y ambos hablamos portugués. En nuestras pruebas nos encontramos con otra "gracia" que está sucediendo con la función "ArrayCopyRates()". Cuando se utiliza un array de MqlRates con "ArrayCopyRates()" en un EA, el array de datos es uno virtual que siempre informa del estado actual de las cosas, por lo que los datos son siempre frescos.

Sin embargo, en un Indicador, este no parece ser el caso. El array no es una copia virtual sino una copia estática fijada en el tiempo en el momento en que se llamó a"ArrayCopyRates()". Los datos no se actualizan cuando el Símbolo es diferente al símbolo del gráfico. Cuando es el mismo símbolo del gráfico, entonces los datos del array están "vivos" y se actualizan como se espera, pero cuando es de otro símbolo, es una copia estática.

Por lo tanto, para que funcione en un indicador, uno debe llamar a la función "ArrayCopyRates()" en cada llamada al evento OnCalculate() si se necesitan datos frescos.

Sólo para ampliar tus conclusiones Fernando - incluso si el símbolo es el mismo que el del gráfico, si el marco temporal es diferente entonces el array es estático.

Así que para tener una copia virtual, en un indicador, debe ser el mismo símbolo Y el mismo marco temporal. Cualquier otra cosa es estática.

 
honest_knave: Sólo para ampliar sus conclusiones Fernando - incluso si el símbolo es el mismo que el símbolo del gráfico, si el marco de tiempo es diferente, entonces la matriz es estática. Así que para tener una copia virtual, en un indicador, debe ser el mismo símbolo Y el mismo marco temporal. Cualquier otra cosa es estática.
¡Gracias por la actualización!
 
Hola,

He estado buscando por todas partes una solución para este problema y me gustaría agradecer a todos en este hilo por esta discusión.

Este es mi primer mensaje en el foro, así que por favor, hágame saber si me perdí algún protocolo y estaré encantado de corregir en el próximo mensaje.

Estoy tratando de desarrollar un indicador muy simple, pero mi lógica parece sensible a que el gráfico esté totalmente actualizado, por eso me interesa tanto esta discusión.

Mi indicador busca dibujar un fib en el rango del día anterior (del máximo al mínimo del día o del mínimo al máximo del día) y en el día actual dibujar líneas en el máximo, el mínimo y el 50% del fib. Si el indicador se utiliza en un corredor GMT (vela diaria del domingo) el usuario puede establecer un parámetro de entrada para elegir si el lunes utiliza sólo el rango del viernes o del domingo, o el viernes + el domingo. En un broker con cierre en NY (GMT+2) esto no supone ninguna diferencia dado que no hay velas de domingo.

Otra característica de este indicador es permitir al usuario mover el fib y las líneas (alta, 50% y baja) en el día actual se ajustarán al nuevo rango establecido por el fib. Esto permitirá al usuario ajustar el rango en caso de que el rango se contraiga.

El indicador se utilizará sobre todo en gráficos de 1 hora, pero el usuario debería poder cambiar de marco temporal sin perder los cambios realizados en el fib.

Para dibujar el fib necesito encontrar no sólo el máximo y el mínimo del día anterior, sino también la hora de estos puntos.

La idea es simple, pero me encuentro con algunos desafíos.

Asumiendo que es mitad de semana para encontrar el máximo y el mínimo del día anterior simplemente uso:

       Hi = iHigh(NULL, PERIOD_D1, 1);
       Lo = iLow(NULL, PERIOD_D1, 1);

Eso está bien, pero ahora necesito encontrar el día anterior a qué hora fue el máximo y el mínimo. Decidí aproximar el tiempo a la vela de 1h en el alto y el bajo usando iHighest y iLowest. Y ahí empezaron los problemas.


Para usar iHighest y iLowest necesito especificar la primera vela de 1h y el tamaño del rango, por lo tanto en mi caso eso será la primera vela de 1h y la última de 1h del día anterior. Así que utilicé la apertura de la vela diaria anterior para el comienzo del día anterior y la apertura de la vela diaria del día actual -1, para encontrar el final del día anterior:

       PrevDayBegin = iBarShift(NULL, PERIOD_H1, iTime(NULL, PERIOD_D1, 1));                
       PrevDayEnd = iBarShift(NULL, PERIOD_H1, iTime(NULL, PERIOD_D1, 0)-1);

Y eso funciona muy bien si sólo estás usando el indicador en divisas (de nuevo asumiendo que es a mitad de semana) porque PrevDayBegin será el índice de la vela de las 0:00 1h y PrevDayEnd será el índice de la vela de las 23:00 1h. El problema está en los futuros (índices, oro, crudo, etc). La apertura de la vela diaria es siempre a las 0:00, pero la primera vela en los futuros es la 1 de la madrugada en los corredores GMT+2, por lo que la línea de código anterior que calcula PrevDayBegin devuelve la vela de 1h de las 23:00 del día anterior.

Entonces decidí incluir un trozo de código para acomodar esta situación y mover el PrevDayBegin hasta que esté en el mismo día de la semana que el PrevDayEnd:

       if(TimeDayOfWeek(iTime(NULL, PERIOD_H1, PrevDayBegin)) != TimeDayOfWeek(iTime(NULL, PERIOD_H1, PrevDayEnd)))
         PrevDayBegin--;  

Y toda esa lógica funciona muy bien si tienes todas las velas de 1h actualizadas, pero echa un vistazo al registro de abajo que muestra algunas impresiones de lo que pasó hoy. Sólo como referencia, cerré MT4 el día anterior por la noche y lo volví a abrir hoy por la mañana (alrededor de las 7 am del Reino Unido), por lo que sólo faltaban unas pocas horas de datos en los gráficos.

2017.02.09 06:56:20.613 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: == OTRO DÍA DE LA SEMANA ==
2017.02.09 06:56:20.613 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR PrevDayEnd = 1 (2017.02.08 19:00)
2017.02.09 06:56:20.613 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR PrevDayBegin = 20 (2017.02.08 00:00)

Mirando el registro parece que la vela más actualizada en el gráfico de 1h fue 2017.02.08 20:00 (índice 0), por lo tanto iBarShift(NULL, PERIOD_H1, iTime(NULL, PERIOD_D1, 0)-1) está aproximando eso a (índice 1) 2017.02.08 19:00. En consecuencia, todos los cálculos para el indicador se mezclan, porque iHighest y iLowest estarán utilizando el rango equivocado.

Basado en las discusiones anteriores he intentado y utilizado algunas de las soluciones sugeridas para esperar a que todas las velas se carguen antes de hacer los cálculos, pero aparentemente sigue sin funcionar.

Por ejemplo, en OnInit() incluí las siguientes líneas de código para desencadenar la actualización de los gráficos en el 1h, Daily y el marco de tiempo actual (por si acaso la plataforma estaba cerrada cuando el gráfico estaba abierto en un marco de tiempo diferente):

   // Triggers history update
   MqlRates mqlrates_array_d1[];
   MqlRates mqlrates_array_h1[];
   MqlRates mqlrates_array[];
  
   ArrayCopyRates(mqlrates_array_d1,NULL,PERIOD_D1);
   ArrayCopyRates(mqlrates_array_h1,NULL,PERIOD_H1);
   ArrayCopyRates(mqlrates_array,NULL,0);  
Otra cosa que noté es que parece que MT4 actualiza la vela más reciente Time[0] en el timeframe que está abierto en el gráfico antes de cargar todo el historial que falta, por lo tanto decidí probar si Time[1] era también un precio válido.

Ese código fue insertado en OnCalculate() y se basó en los códigos de @whroeder1(aquí) y @Fernando Carreiro& @Wemerson Guimaraes(aquí):

bool isHistoryLoading;

OnInit();
:
isHistoryLoading = true;
:

OnCalculate( ... )
:
      MqlRates mqlrates_array_d1[];
      MqlRates mqlrates_array_h1[];
      MqlRates mqlrates_array[];
      
      if(isHistoryLoading)
        {      
         ResetLastError();        
        
         if(ArrayCopyRates(mqlrates_array_d1,NULL,PERIOD_D1)>0)
           {
            if(GetLastError() == 0)
              {
               if((iTime(NULL,PERIOD_D1,0) > 0) && (iTime(NULL,PERIOD_D1,1) > 0))
                 {
                  ResetLastError();
  
                  if(ArrayCopyRates(mqlrates_array_h1,NULL,PERIOD_H1)>0)
                    {
                     if(GetLastError() == 0)
                       {
                        if((iTime(NULL,PERIOD_H1,0) > 0) && (iTime(NULL,PERIOD_H1,1) > 0))
                          {
                           ResetLastError();
      
                           if(ArrayCopyRates(mqlrates_array,NULL,0)>0)
                             {
                              if(GetLastError() == 0)
                                {
                                 if((iTime(NULL,0,0) > 0) && (iTime(NULL,0,1) > 0))                            
                                   {
                                    isHistoryLoading = false;
                                
                                    if(DebugLog)
                                      Print("Chart up-to-date!");        
                                    }
                                }
                             }
                          }
                       }
                    }                      
                 }
              }
           }
        }
        
      if(isHistoryLoading)
        {
         if(DebugLog)
           Print("Waiting for chart to update!");
         return(rates_total);
        }    

:

Y este es el log cuando se abrió la plataforma y se cargó el indicador por primera vez:

2017.02.09 06:56:18.492 Indicador personalizado Prev_Day_Range_LRT_50_v0.6 SPX500,H1: cargado con éxito
2017.02.09 06:56:18.630 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: inicializado
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: ¡Gráfico actualizado!
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: ¡El indicador no existe! Creándolo.
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: == OTRO DÍA DE LA SEMANA ==
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR PrevDayEnd = 20 (2017.02.07 23:00)
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR PrevDayBegin = 42 (2017.02.07 00:00)
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR CurrDayBegin = (2017.02.08 00:00)
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR PERIOD_D1 [0] = (2017.02.08 00:00)
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR PERIOD_D1 [1] = (2017.02.07 00:00)
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR PERIOD_D1 [2] = (2017.02.06 00:00)
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR Día de la semana = 3
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR iHighest (Candle = 28) (Price = 2299.33) (Time = 2017.02.07 14:00:001)
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR iLowest (Vela = 20) (Precio = 2287.88) (Hora = 2017.02.07 23:00:001)
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Fib desde Time1=2017.02.07 14:00 Price1=2299.33 hasta Time2=2017.02.07 23:00 Price2=2287.88
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Línea de tendencia 'PDRTrend1 131296489639296384' desde Time1=2017.02.08 00:00 Price1=2299.33 hasta Time2=2017.02.09 00:00 Price2=2299.33
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Línea de tendencia 'PDRTrend2 131296489639296384' desde Time1=2017.02.08 00:00 Price1=2293.605 hasta Time2=2017.02.09 00:00 Price2=2293.605
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Línea de tendencia 'PDRTrend3 131296489639296384' desde Time1=2017.02.08 00:00 Price1=2287.88 hasta Time2=2017.02.09 00:00 Price2=2287.88

Parece que cualquier referencia a las velas 0 y 1 o la función ArrayCopyRates sólo están accediendo a la información que ya está cargada en los gráficos, por lo que ArrayCopyRates parece estar devolviendo un número válido de elementos copiados y iTime(..., 0) e iTime(..., 1) están devolviendo un precio válido para las 2 últimas velas almacenadas cuando la plataforma se cerró el día anterior.

Eso significa que el indicador fue trazado como si fuera ayer (PERIOD_D1 [0] = (2017.02.08 00:00)).

El indicador está construido de manera que las líneas alta, 50% y baja siempre se trazan en el día actual, incluso si el usuario mueve el fib (estas son las 3 líneas de tendencia que se muestran en el registro anterior). Por lo tanto, tengo un trozo de código en OnCalculate() que prueba si la línea de tendencia media se traza en el día actual (el usuario tiene una opción de entrada para desactivar la línea superior e inferior, por lo que la única línea que siempre se traza es la media).

OnCalculate( ... )
:

      if(ObjectFind(Trend2Name) != -1)                // Check whether mid range line exists
        {
            
         if((TimeDay(ObjectGetInteger(0,Trend2Name,OBJPROP_TIME,0))==TimeDay(TimeCurrent()))
           && (TimeMonth(ObjectGetInteger(0,Trend2Name,OBJPROP_TIME,0))==TimeMonth(TimeCurrent()))
           && (TimeYear(ObjectGetInteger(0,Trend2Name,OBJPROP_TIME,0))==TimeYear(TimeCurrent()))) // Indicator has already been ploted today        
           {
            return(rates_total);
           }
         else     // Indicator exists but in a past date, so delete it and plot it on current day
           {
            if(DebugLog)
               Print("Indicator in a past date! Deleting it and creating it today!");
              
            if(ObjectFind(FibName) != -1)
              FiboLevelsDelete(0,FibName);              
            // Indicator will be created by the OnChartEvent() when it detects the fib was deleted.
           }
        }
      else        // Indicator doesn't exist, so create it
        {
         if(DebugLog)
            Print("Indicator doesn't exist! Creating it.");
         CreateIndicator();
        }
:

Después de unos pocos ticks los datos se cargan parcialmente y el trozo de código anterior detectará que las líneas han sido trazadas en un día anterior, borrará el fib y activará un recálculo de los rangos y redibujará los objetos (es decir, fib, líneas de tendencia, etc).


2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: ¡Indicador en una fecha pasada! ¡Borrarlo y crearlo hoy!
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: ¡PDRFibo 131296489639296384 borrado!
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Borrando PDRRectangle 1312964839296384
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Borrando PDRTrend1 1312964839296384
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Borrando PDRTrend2 1312964839296384
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Borrando PDRTrend3 1312964839296384

Y volvemos al problema que mencionaba al principio de este mensaje. La prueba que he implementado arriba vuelve a no hacer que el indicador espere a que se cargue completamente el historial y por tanto los rangos se calculan mal en base a datos parciales.

Esta es una versión más completa del registro mostrado al principio del mensaje que muestra que no sólo PrevDayEnd está siendo mal calculado como la segunda vela (índice 1) en el gráfico de 1h es (2017.02.07 21:00) pero también CurrDayBegin que se supone que es la primera vela del día actual en el gráfico de 1h está siendo aproximado por iBarShift a (2017.02.08 06:00).

CurrDayBegin = iTime(NULL, PERIOD_D1, 0);
      
while(TimeDayOfWeek(iTime(NULL, PERIOD_H1, iBarShift(NULL, PERIOD_H1, CurrDayBegin))) != TimeDayOfWeek(TimeCurrent()))

     // If iBarShift can't find the 0am candle and returns the 11pm candle of prev day.

  CurrDayBegin = CurrDayBegin + 3600;        // Move 1h until you find the 1st candle of today.                                        

2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: == OTRO DÍA DE LA SEMANA ==
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR PrevDayEnd = 1 (2017.02.07 21:00)
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR PrevDayBegin = 22 (2017.02.07 00:00)
2017.02.08 06:53:252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR CurrDayBegin = (2017.02.08 06:00)
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR PERIOD_D1 [0] = (2017.02.08 00:00)
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR PERIOD_D1 [1] = (2017.02.07 00:00)
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR PERIOD_D1 [2] = (2017.02.06 00:00)
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR Día de la semana = 3
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR iHighest (Candle = 8) (Price = 2299.33) (Time = 2017.02.07 14:00:001)
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR iLowest (Vela = 19) (Precio = 2288.57) (Hora = 2017.02.07 03:00:001)
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Fib desde Time1=2017.02.07 03:00 Price1=2288.57 hasta Time2=2017.02.07 14:00 Price2=2299.33
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Línea de tendencia 'PDRTrend1 131296489639296384' desde Time1=2017.02.08 06:00 Price1=2288.57 hasta Time2=2017.02.09 06:00 Price2=2288.57
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Línea de tendencia 'PDRTrend2 131296489639296384' desde Time1=2017.02.08 06:00 Price1=2293.95 hasta Time2=2017.02.09 06:00 Price2=2293.95
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Línea de tendencia 'PDRTrend3 131296489639296384' desde Time1=2017.02.08 06:00 Price1=2299.33 hasta Time2=2017.02.09 06:00 Price2=2299.33

Así que, en resumen, ¿hay un por qué para probar si toda la histoira se ha cargado en un gráfico? ¿O me falta algo en mi código?

Gracias por tener paciencia con este mensaje tan largo.

Por favor, dime si quieres ver el código completo y el registro. Prefiero no adjuntar el código aquí, pero estaría encantado de enviarlo por privado.

Estas son capturas de pantalla del indicador:

(1) Calculado usando un historial incompleto (por favor, fíjate en que las líneas horizontales no empiezan al principio del día)

Indicador calculado con un historial incompleto

(2) Recalculado usando el historial completo (las líneas horizontales comienzan al principio del día)

Indicador recalculado con el historial completo

Problems with ERR_HISTORY_WILL_UPDATED (4066 ) & weekends
Problems with ERR_HISTORY_WILL_UPDATED (4066 ) & weekends
  • www.mql5.com
Hi i m building a custom indicator and got problems with the 4066 Error...