Encontrar los valores máximo y mínimo de una serie temporal

Entre el grupo de funciones para trabajar con series temporales de cotizaciones, hay dos que proporcionan el tratamiento agregado más sencillo: la búsqueda de los valores máximo y mínimo de la serie en un intervalo determinado, respectivamente iHighest y iLowest.

int iHighest(const string symbol, ENUM_TIMEFRAMES timeframe, ENUM_SERIESMODE type, int count = WHOLE_ARRAY, int offset = 0)

int iLowest(const string symbol, ENUM_TIMEFRAMES timeframe, ENUM_SERIESMODE type, int count = WHOLE_ARRAY, int offset = 0)

Las funciones devuelven el índice del valor mayor o menor para un tipo específico de serie temporal, que se especifica mediante un par de parámetros symbol/timeframe, así como el elemento de enumeración ENUM_SERIESMODE (describe los campos de cotización que ya nos son familiares).

Identificador

Descripción

MODE_OPEN

Precio de apertura

MODE_LOW

Precio alto

MODE_HIGH

Precio bajo

MODE_CLOSE

Precio de cierre

MODE_VOLUME

Volumen de ticks

MODE_REAL_VOLUME

Volumen real

MODE_SPREAD

Diferencial

El parámetro offset especifica el índice en el que se inicia la búsqueda. La numeración se realiza como en una serie temporal, es decir, el aumento de offset da lugar a un desplazamiento hacia el pasado, y el índice 0-ésimo indica la barra actual (éste es el valor por defecto). El número de barras analizadas se especifica en el parámetro count (WHOLE_ARRAY por defecto).

En caso de error, las funciones devuelven -1. Utilice GetLastError para buscar el código de error.

Para demostrar cómo funciona una de estas funciones (iHighest) vamos a modificar el ejemplo del apartado anterior sobre la estimación de los tamaños reales de los diferenciales por barras y a comparar los resultados. Por supuesto, deben coincidir. La nueva versión del script se adjunta en el archivo SeriesSpreadHighest.mq5.

Los cambios han afectado a la estructura SpreadPerBar y al ciclo de trabajo dentro de OnStart.

Se han añadido campos a la estructura que permiten comprender cómo funciona la nueva función. Debido a la naturaleza del algoritmo, no son obligatorios.

struct SpreadPerBar
{
   datetime time;
   int spread;
   int max// through index of the M1 bar with a spread, the value of which is maximum
            // among all M1-bars within the current bar of the higher timeframe
   int num// number of M1 bars in the current bar of the higher timeframe
   int pos// initial index of the M1 bar within the current bar of the higher timeframe
};

Las principales transformaciones han afectado a OnStart, pero están localizadas dentro del bucle (todos los demás fragmentos de código han permanecido inalterados).

   for(int i = 0i < BarCount; ++i)
   {
      const datetime next = iTime(WorkSymbolTimeFramei);
      const datetime prev = iTime(WorkSymbolTimeFramei + 1);
      ...

Los bordes de la barra actual, prev y next, se definen como antes. No obstante, en lugar de copiar los elementos de la serie temporal entre estas etiquetas en su propio array spreads, y la posterior llamada de ArrayMaximum para ello, determinamos los índices y el número de barras M1 que forman la barra actual del marco temporal superior. Esto se hace de la siguiente manera.

La función iBarShift permite conocer el desplazamiento (variable p) en el histórico de M1, donde se encuentra el borde derecho de la barra con el tiempo next - 1. La función bars calcula el número de barras M1 (variable n) comprendidas entre prev y next - 1. Estos dos valores se convierten en parámetros en la llamada a la función iHighest realizada para buscar el valor máximo de tipo MODE_SPREAD, entre las barras n M1, a partir del índice p. Si se encuentra el máximo sin problemas (m > -1), nos queda tomar el valor correspondiente mediante iSpread y colocarlo en una estructura.

      const int p = iBarShift(WorkSymbolPERIOD_M1next - 1);
      const int n = Bars(WorkSymbolPERIOD_M1prevnext - 1);
      const int m = iHighest(WorkSymbolPERIOD_M1MODE_SPREADnp);
      if(m > -1)
      {
         peaks[i].spread = iSpread(WorkSymbolPERIOD_M1m);
         peaks[i].time = prev;
         peaks[i].max = m;
         peaks[i].num = n;
         peaks[i].pos = p;
      }
   }

Al enviar el array con los resultados al registro, ahora veremos adicionalmente los índices de las barras M1, donde «comienza» la barra del marco temporal superior y donde se encontró en ella el diferencial máximo. La palabra «comienza» está entre comillas porque, a medida que lleguen nuevas barras M1, estos índices aumentarán, y el «comienzo» virtual de cada una se desplazará, aunque las horas de apertura de las barras históricas, por supuesto, permanecen constantes.

Maximal speeds per intraday bar
Processed 100 bars on EURUSD PERIOD_H1
               [time] [spread] [max] [num] [pos]
[ 0] 2021.10.12 15:00        0     7    60     7
[ 1] 2021.10.12 14:00        1    89    60    67
[ 2] 2021.10.12 13:00        1   181    60   127
[ 3] 2021.10.12 12:00        1   213    60   187
[ 4] 2021.10.12 11:00        1   248    60   247
[ 5] 2021.10.12 10:00        0   307    60   307
[ 6] 2021.10.12 09:00        1   385    60   367
[ 7] 2021.10.12 08:00        2   469    60   427
[ 8] 2021.10.12 07:00        2   497    60   487
[ 9] 2021.10.12 06:00        1   550    60   547
[10] 2021.10.12 05:00        1   616    60   607
[11] 2021.10.12 04:00        1   678    60   667
[12] 2021.10.12 03:00        1   727    60   727
[13] 2021.10.12 02:00        4   820    60   787
[14] 2021.10.12 01:00       16   906    60   847
[15] 2021.10.12 00:00       65   956    60   907
[16] 2021.10.11 23:00       15   967    60   967
[17] 2021.10.11 22:00        2  1039    60  1027
[18] 2021.10.11 21:00        1  1090    60  1087
[19] 2021.10.11 20:00        1  1148    60  1147
[20] 2021.10.11 19:00        2  1210    60  1207
[21] 2021.10.11 18:00        1  1313    60  1267
[22] 2021.10.11 17:00        1  1345    60  1327
[23] 2021.10.11 16:00        1  1411    60  1387
[24] 2021.10.11 15:00        2  1461    60  1447
[25] 2021.10.11 14:00        1  1526    60  1507
...

Por ejemplo, en el momento de lanzar el script, la barra con la etiqueta 2021.10.12 14:00 partía de la barra 67 M1 (es decir, se abrió hace 67 minutos), y la barra M1 con el diferencial máximo dentro de esta barra H1 se encontró bajo el índice 89. Obviamente, este índice debe ser menor que el número de la barra M1 donde comenzó la barra H1 anterior: 2021.10.12 13:00 - se marcó hace 127 minutos. En esta barra H1, a su vez, se encontró el máximo diferencial para el índice 181. Y esto es menor que el índice 187 para una barra aún más antigua 2021.10.12 12:00.

Los índices de las columnas pos y max aumentan constantemente porque recorremos las barras en orden del presente al pasado. La columna num casi tendrá 60, ya que la mayoría de las barras H1 están formadas por 60 barras M1, pero no siempre es así. Por ejemplo, a continuación se muestran barras horarias incompletas, compuestas por menos minutos: esto puede ser consecuencia de un cierre más temprano del mercado debido al calendario de vacaciones, o de lagunas reales en la actividad comercial (falta de liquidez).

...
[38] 2021.10.11 01:00       20  2346    60  2287
[39] 2021.10.11 00:00       85  2404    58  2347
[40] 2021.10.08 23:00       15  2406    55  2405
[41] 2021.10.08 22:00        2  2463    60  2460
...