Los principios de la transformación del tiempo en el trading intradía

kamal | 15 marzo, 2016

Introducción


La uniformidad estadística del seguimiento del mercado juega siempre un papel importante en el análisis de los movimientos anteriores del precio. Cuando se produce esta uniformidad, es posible estudiar en profundidad las propiedades del proceso que identifica los patrones que contribuyen a la construcción de un sistema de trading. Sin embargo, se sabe muy bien y se va demostrar más adelante que el proceso del tipo de cambio no es uniforme incluso en la primera aproximación, es decir, hay una heterogeneidad relacionada con la actividad de diferentes sesiones de trading: América, Europa, Asia y la alternancia entre ellas.

Me atrevo a decir que algunos de los nuevos desarrolladores de sistemas y hasta algunos "expertos", piensan que incluso los indicadores más sencillos del tipo promedio móvil, sujetos al tiempo, son en realidad unidades distintas en distintos intervalos del día. Existen sin duda sistemas formulados en función del precio y no del tiempo. Un ejemplo típico; los sistemas basados en los métodos de Renko y Kagi, pero son muy pocos. Pero repito, los sistemas están sujetos en su mayoría al tiempo, y a veces indirectamente, mediante los indicadores.

Obviamente, todo lo anterior se aplica únicamente a los sistemas intradía. Pero no es evidente en los períodos de tiempo mayores, aunque haya estacionalidad. Y esto es extremadamente importante en el trading intradía y lleva a menudo al hecho de que el sistema muestre distintas rentabilidades en distintos momentos. Vamos a abordar los factores que causan estás diferencias y la manera de evitarlas.

Teoría


Desde el punto de vista estadístico de los procesos aleatorios, en una primera aproximación, se trata el proceso de cambio del precio en general como un tipo determinado de difusión, es decir, la transferencia de una materia o energía de una zona de alta concentración hacia una zona de baja concentración. Se sabe muy bien que la transformación del tiempo conlleva martingalas continuas a un movimiento browniano con una disposición relativamente sencilla.

Sin entrar en la cuestión de si el proceso de cambio del precio es una difusión o una martingala, quiero subrayar que nada impide pasar del mismo modo del proceso de transformación del tiempo a algo dispuesto de manera más sencilla, a saber, un proceso estadísticamente uniforme en el tiempo. Para ello, sería lógico usar barras sin división temporal, pero simplemente con un número fijo de ticks, por ejemplo una barra contiene 1000 ticks en lugar de 60 minutos.

En teoría, este tiempo se llama el tiempo de funcionamiento y es el proceso lógico de la transformación del tiempo. En este caso, el proceso tiene una desviación media estadísticamente constante, que permite detectar con mayor claridad el ambiente que se crea en los mercados y los aísla de manera eficiente contra las fluctuaciones aleatorias. Y tenga en cuenta que el uso de los indicadores comunes además de ser posible será mucho más uniforme. Pero desafortunadamente, MetaTrader 4 aún no dispone de esta opción. Así que vamos a recurrir a otro método; reestructurar el sistema en base al tiempo. A continuación veremos ejemplos de indicadores modificados. Pero primero, vamos a analizar la heterogeneidad en cuestión.

Datos estadísticos

El gráfico de pares de divisas exóticos muestra claramente que la actividad en el mercado ha disminuido durante un intervalo determinado del día. Por ejemplo:





Por otro lado, se observan los mismos efectos en los pares más comunes. Esto despierta el interés para examinar con más detalle el comportamiento de los volúmenes y la volatilidad. Está claro que para entender mejor las fluctuaciones de la volatilidad intradía, es de suma importancia el comportamiento de los volúmenes, es decir, los ticks en una barra. Sin embargo, el volumen en sí es un valor aleatorio, por lo que tenemos que referirnos al promedio histórico. Dicha referencia puede parecer poco legítima, si el comportamiento estadístico de la "materia prima" es "erróneo".

Por comprobar estas hipótesis, vamos a escribir un indicador sencillo, ExpectedVolume, que averiguará el volumen histórico de ticks por hora, histSteps son los pasos hacia atrás, cada paso es el span (rango en días). Los valores típicos de estos parámetros son 100 y 1 respectivamente. Se lleva a cabo la prueba en el período de tiempo H1, hay que cambiar los parámetros para otros períodos de tiempo intradía. Este es el código del indicador:

//+------------------------------------------------------------------+
//|                                             Expected Volumes.mq4 |
//|                                     Copyright © 2007, Amir Aliev |
//|                                       http://finmat.blogspot.com/ |
//+------------------------------------------------------------------+
#property  copyright "Copyright © 2007, Amir Aliev"
#property  link      "http://finmat.blogspot.com/"
//---- 
#property indicator_separate_window
#property indicator_buffers 1
#property indicator_color1 Blue
//---- input parameters
extern int hist_steps = 100;      // Number of observations
extern int span = 1;              // Days to step back each time 
//---- buffers
double ExtMapBuffer1[];
int sum;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init()
  {
   string short_name;
//---- indicators
   SetIndexStyle(0, DRAW_HISTOGRAM);
   SetIndexBuffer(0,ExtMapBuffer1);
//----
   short_name = "Expected volumes(" + hist_steps + ")";
   IndicatorShortName(short_name);
   SetIndexLabel(0, short_name);
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
int deinit()
  {
//----
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int start()
  {
   int counted_bars = IndicatorCounted();
   int rest = Bars - counted_bars;
   int j, k, u;
//----     
   while(rest >= 0)
     {
      if(Bars - rest < span * 23 * hist_steps) 
        {
         ExtMapBuffer1[rest] = 0;     
         rest--; 
         continue;                                   
        }
      sum = 0;
      j = 0;
      k = 0;
      u = 0;
      while(j < hist_steps && k < Bars) 
        {
         if(TimeHour(Time[rest+k]) == TimeHour(Time[rest]))
           {
            u++;
            if(u == span)
              {
               u = 0;
               j++;
               sum += Volume[rest + k]; 
              }
            k += 23;
           }
         k++;
        }
      ExtMapBuffer1[rest] = sum / hist_steps;     
      rest--;                                    
     }
//----
   return(0);
  }
//+------------------------------------------------------------------+

Aunque sea para comprobar la uniformidad estadística, hay que hacer seguimientos independientes, por ejemplo, repartidos entre los días de la semana. Para ello, establecemos span=5. Obtenemos la siguiente figura:




Los picos limítrofes son casi idénticos. Esto significa que la volatilidad que medimos por hora es estadísticamente uniforme. Se puede ver claramente la estructura de esta volatilidad a partir de las siguientes figuras (la izquierda; EURUSD, la derecha; USDJPY):



Se ven claramente tres picos de la actividad de las sesiones de trading; Asia, Europa y América. Hay que tener en cuenta que usar únicamente estas sesiones de trading no es muy común; a veces se destacan otras sesiones. En principio podemos observar algunas características, como el carácter de la actividad durante la sesión americana (se repite en ambos gráficos).

Modificación de los indicadores


Al modificar los indicadores, es muy importante entender el tiempo exacto que incluyen. Esto es muy fácil con los indicadores sencillos como el Promedio móvil (Moving Average), pero es bastante complicado cambiar, por ejemplo, un Aligator.

En última instancia, lo más razonable sería introducir un período de tiempo "de funcionamiento". Pero de momento vamos a tratar de cambiar algunos indicadores sencillos. Los más básicos ajustan los volúmenes; se dividen los volúmenes reales por los previstos. Por lo tanto, la desviación en una dirección u otra de este indicador refleja un aumento o disminución de la actividad en el mercado. El código es muy sencillo. Está incluido en un archivo adjunto a este artículo.

El siguiente ejemplo es el Promedio. De hecho, sólo tenemos que ponderar la barra en la que se construye el promedio (por ejemplo, "open"), por el número de ticks dentro de la barra. El número resultante no es exactamente igual a la suma de los valores del precio en todos los ticks. Para una evaluación más precisa, tenemos que procurar no coger el valor de la barra "open", sino un promedio ponderado en la barra. El indicador se construye por fuerza bruta y por eso requiere un considerable coste computacional que es realmente innecesario. Por este motivo se ha añadido otro parámetro, el número de barras anteriores que va a dibujar el indicador, el valor por defecto es 500. Asimismo, se establece el período promedio en número de ticks, no en barras. Este es el código:

//+------------------------------------------------------------------+
//|                                                Corrected SMA.mq4 |
//|                                     Copyright © 2007, Amir Aliev |
//|                                    http://finmat.blogspot.com/   |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2007, Amir Aliev"
#property link      "http://finmat.blogspot.com/"
//----
#property indicator_chart_window
#property indicator_color1 Red
//---- input parameters
extern int MA_Ticks = 10000;
extern int MA_Shift = 0;
extern int MA_Start = 500;
//---- indicator buffers
double ExtMapBuffer[];
double ExpVolBuffer[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init()
  {
//----
   SetIndexStyle(0, DRAW_LINE);
   SetIndexShift(0, MA_Shift);
   IndicatorBuffers(2);
//---- indicator buffers mapping
   SetIndexBuffer(0, ExtMapBuffer);
   SetIndexBuffer(1, ExpVolBuffer);
   SetIndexDrawBegin(0, 0);  
//---- initialization done
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int start()
  {
   int counted_bars = IndicatorCounted();
   int rest  = Bars - counted_bars;
   int restt = Bars - counted_bars;
   double sum;                               
   int ts;                                   
   int evol;                                 
   int volsum;
   int j;
//----
   while(restt >= 0)
     {
       volsum = 0;
       for(int k = 0; k < 30; k++) 
           volsum += iVolume(NULL, 0, restt + k*24); 
       ExpVolBuffer[restt] = volsum / 30;
       restt--;
     }
//----
   while(ExpVolBuffer[rest] == 0 && rest >= 0) 
       rest--;
   rest -= MA_Ticks / 200;
   if(rest > MA_Start) 
       rest = MA_Start;  
//----
   while(rest >= 0)
     {
       sum = 0;
       ts = 0;
       j = rest;
       while(ts < MA_Ticks)
         {
           evol = ExpVolBuffer[j];
           Print("Evol = ", evol);
           if(ts + evol < MA_Ticks)
             {
               sum += evol * Open[j];
               ts += evol;
             }
           else
             {
               sum += (MA_Ticks - ts) * Open[j];
               ts = MA_Ticks;
             }
           j++;
         }
       ExtMapBuffer[rest] = sum / MA_Ticks;
       rest--;
     }   
//----
   return(0);
  }
//+------------------------------------------------------------------+

Una vez escritos los indicadores sencillos, no será difícil cambiar otros más complejos. En el ejemplo del código del indicador MACD, hay que utilizar un promedio móvil corregido en lugar del sencillo. Se adjunta también el código correspondiente.

Hay que tener en cuenta que para un cálculo rápido del promedio corregido, hay que calcular los promedios empíricos de los ticks por hora una vez y no sobre la marcha, para evitar nuevos cálculos. Se ha omitido en este caso, pero si llevamos a cabo una prueba/optimización a gran escala en el historial, el rendimiento empieza a destacar. También hay partidarios de un enfoque distinto para implementar la corrección en función del promedio de los volúmenes y que debería abordarse por separado.

Parecería absurdo promediar volúmenes de períodos anteriores: el uso de los volúmenes disponibles como coeficientes es suficiente para el cálculo del promedio. Este es un ejemplo del código. Pero tenga en cuenta que por razones técnicas es mejor utilizar este promedio con períodos de tiempo pequeños, tales como M1-M5.

//+------------------------------------------------------------------+
//|                                             Corrected SMA II.mq4 |
//|                                     Copyright © 2007, Amir Aliev |
//|                                      http://finmat.blogspot.com/ |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2007, Amir Aliev"
#property link      "http://finmat.blogspot.com/"
 
#property indicator_chart_window
#property indicator_color1 Red
//---- input parameters
extern int MA_Ticks = 1000;
//---- indicator buffers
double sum = 0;                               
int ticks = 0;
bool collected = false;
bool started = false;
int fbar = 0;
double ExtMapBuffer[];
int oldRange = 0;
int lbarVol = 0;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init()
  {
//----
   SetIndexStyle(0, DRAW_LINE);
//---- indicator buffers mapping
   SetIndexBuffer(0, ExtMapBuffer);
//---- initialization done
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int start()
  {
   int rest = Bars - IndicatorCounted();
   if(! rest) 
       return (0);
   Print("Ticks = ", ticks);
   Print("Rest = ", rest);
   Print("fbar = ", fbar);  
   rest--;
   fbar += rest;
   while(!collected && (rest >= 0))
     {
      if(ticks + Volume[rest] < MA_Ticks)
        {
         ticks += Volume[rest];
         sum += Volume[rest] * Open[rest];
         if(!started)
           {
            fbar = rest;
            started = true;
           }
         rest--;
         continue;
        } 
      collected = true;
     }
   if(! collected) 
       return (0);
 
   ticks += (Volume[rest] - lbarVol);
   sum += (Volume[rest] - lbarVol) * Open[rest];
   lbarVol = Volume[rest];
   while(ticks > MA_Ticks)
     {
       Print("fbar-- because bar ticks reaches 1000");
       ticks -= Volume[fbar];
       sum -= Volume[fbar] * Open[fbar];
       fbar--;
     }
   ExtMapBuffer[rest] = sum / ticks;
   rest--;
   while(rest >= 0)
     {
      ticks += Volume[rest];
      sum += Volume[rest] * Open[rest];
      lbarVol = Volume[rest];
      while(ticks > MA_Ticks)
        {
         Print("fbar-- because of new bar ");
         ticks -= Volume[fbar];
         sum -= Volume[fbar] * Open[fbar];
         fbar--;
        }
      ExtMapBuffer[rest] = sum / ticks;
      rest--;
     } 
//----
   return(0);
  }
//+------------------------------------------------------------------+

Sin embargo, el autor del artículo cree que el uso de este indicador puede ser útil en algunos casos y que en general tiene un significado distinto al que se describe en este artículo. La idea de tener en cuenta los valores del precio por los que hubo una gran "lucha" en el mercado, es algo artificial, y no menos importante debido a las pequeñas desviaciones que pueden ser causadas por factores técnicos del mercado o ajenos a él. Por otro lado, parece razonable tener en cuenta los cambios en la volatilidad (y se trata de eso).

Se puede modificar cada uno de estos indicadores para una tarea concreta, como por ejemplo cambiar el promedio para contabilizar la suma de los valores dentro de una barra o cambiar los parámetros para el cálculo de un promedio. Recuerde que hemos hecho los cálculos en base a las barras "open", lo que crea visualmente una sensación de desfase; la volatilidad en el concepto de la transformación en el tiempo puede tener unas interpretaciones muy amplias, incluyendo aquellas que no se han planteado en este artículo, como la volatilidad estacional.


Conclusión


Cabe señalar que mientras el promedio del precio es muy inestable y difícil de predecir, la volatilidad, que es el segundo momento del incremento, es desde el punto de vista estadístico mucho más "agradable" y tiene numerosas características bien conocidas, como las propiedades del cluster, el efecto palanca en los mercados de valores entre otros.

Es por ello que el concepto del tiempo de funcionamiento en sí es de gran utilidad y lógico desde el punto de vista del análisis técnico. Está claro que una noticia clave sobre la situación económica en un momento determinado puede deshacer completamente la uniformidad y tiene difícil "remedio". Pero en la mayoría de los casos, el uso de la transformación del tiempo permite obtener resultados más estables e incrementar la rentabilidad de una estrategia de trading.