STMT: Lógica difusa (1)

En entradas anteriores se habló algo sobre la parte teórica, aquí vamos a detallar cómo usar STMT para implementar código con lógica difusa.

La lógica difusa puede ser muy útil, por ejemplo, en la búsqueda de activos que cumplan algún patrón. Si queremos seleccionar activos con mucho volumen, hay que saber lo que es mucho volumen. No es lo mismo el volumen del IBEX que el del futuro del DAX.

También puede usarse en una estrategia con un solo valor. Si una de las condiciones/filtros de nuestra estrategia es que tenga mucho volumen, no es lo mismo el volumen en el año 2000 que en el 2004 o 2008.

El planteamiento de STMT para trabajar con lógica difusa consiste en recopilar datos previos y cercanos a una fecha. Por ejemplo, para el caso del volumen, si el sistema está trabajando en el día 23/04/2005, mucho volumen es un concepto que puede concretarse observando el volumen de los días previos. Podemos seleccionar, por ejemplo, los 20 días anteriores al actual.

Recopilamos los datos de volumen cada 5 minutos (si estamos trabajando en barras de 5 minutos) desde el día 3/04/2005 hasta el día 22/04/2005. Con esta información, STMT puede obtener el valor de cualquier percentil y saber que es mucho y poco volumen independientemente del activo sobre el que se esté trabajando y de la fecha.

Volumen y volatilidad

Las imágenes siguientes muestran gráficos en compresión de 1 minuto del futuro del DAX. Debajo, el volumen y una media con periodo 20. Se muestra con un degradado en rojo la zona donde el volumen es cada vez más grande. Colores cercanos al blanco son zonas con poco volumen y colores cercanos al rojo, con mucho.

fuzzy1fuzzy2

Si observamos las imágenes, podemos apreciar el resultado de aplicar lógica difusa para clasificar el volumen: En septiembre de 2000, 100 contratos es mucho volumen mientras que en 2008 llegan a superarse los 1000 contratos. Es obvio que fijar un valor para el volumen no funciona en el largo plazo. Sin embargo, observar los valores alcanzados en periodos recientes para determinar lo que es mucho y poco sí que clasifica bien las muestras.

Además del volumen, el gráfico muestra en color verde las velas en las que la volatilidad es grande, concretamente aquellas velas que tienen tanto su altura total (máximo – mínimo) como la de su cuerpo en valores altos. De nuevo, valores altos dependen del contexto y no son el mismo número de puntos en 2000 que en 2004.

Código fuente

Veamos cómo conseguir resultados como los vistos anteriormente utilizando STMT. En ambos casos se utiliza la clase PercentileLine que es la encargada de generar la clasificación de los valores.

Para el caso del volumen, creamos un histórico con los 20 días anteriores al día en el que estamos trabajando. Estos 20 días son el periodo de prueba que se utiliza para hacer la posterior clasificación. Se pueden usar más o menos días, a criterio del usuario.

Los valores del volumen de estos 20 días se le pasan a la línea y ya podemos consultar el percentil de cualquier volumen y en que percentil está un volumen dado.

HistoricSerie historic = new HistoricSerie(
   this._visualChart,
   this.Symbol,
   CompressionType.Minutes,
   1,
   this.StartDate.Date.PreviousLaborable(this.TrainingDays),
   this.StartDate.Date.PreviousLaborable().EndOfDay(),
   updType,
   Paths.GetDataPath());

El código anterior es bastante explícito: se crea un histórico del símbolo indicado en compresión de 1 minuto. La fecha inicial es la de TrainingDays anteriores a la fecha del día actual (StartDate) y la fecha final, las 23:59:59 del día anterior. PreviousLaborable omite fines de semana por lo que 20 días generalmente serán 20 días excepto días festivos de bolsa, una muestra aceptable para el propósito perseguido.

PercentileLine historicPerc = new PercentileLine("Historic Volume %");

Line line = historic.Volume;
int startIndex = line.Dates.NearIndexOf(startDate, -1);
int endIndex = line.Dates.NearIndexOf(endDate, 1);
for (int i = startIndex; i <= endIndex; i++)
{
   historicPerc.AddValue(line.Dates[i], line[i]);
}

Con las líneas anteriores, STMT obtiene todos los datos de volumen en compresión de 1 minuto de los TrainingDays cargados previamente. Recordemos que NearIndexOf devuelve el primer valor mayor o igual que el indicado cuando se especifica -1 como segundo parámetro y el anterior valor menor o igual que el indicado cuando se especifica 1. Es decir, se escogen los índices del intervalo “startDate, endDate“, sin salirse del mismo.

this._chart.PlotHistoric(historic);
Series serie = this._chart.Series[0];

double fuzzyVolume = historicPerc[0.8];
for (int i = 0; i < serie.Points.Count; i++)
{
   DataPoint point = serie.Points[i];
   DateTime date = DateTime.FromOADate(point.XValue);
   int index = historic.Dates.NearIndexOf(date, -1);

   double height = historic.Max[index] - historic.Min[index];
   double body = Math.Abs(historic.Close[index] - historic.Open[index]);
   double volume = historic.Volume[index];
   if (height >= fuzzyHeight && body >= fuzzyBody)
   {
      if (volume > fuzzyVolume)
      {
         serie.Points[i].Color = Color.LawnGreen;
         serie.Points[i].BorderColor = Color.LawnGreen;
      }

      if (index < historic.Dates.Count - 1)
      {
         double percentile = this.GetVolumeValuePercentile(volume);
         Color color = Util.GradientColor(
            Color.White, Color.Red, percentile);

         DateTime startDate = historic.Dates[index];
         DateTime endDate = historic.Dates[index + 1];

         ChartRectangle rect = ChartRectangle.CreateVerticalRect(
            this._chart, startDate, endDate);
         rect.Color = Color.FromArgb(10, color);
         this._chart.Objects.Add(rect);
      }
   }
}

Con PlotHistoric graficamos el histórico y a continuación obtenemos la serie del gráfico, que recorremos en el bucle.

La variable fuzzyVolume representa el valor del volumen que deja el 80% de los volúmenes de la muestra por debajo de él, es decir, solo hay un 20% de volúmenes mayores que fuzzyVolume en los TrainingDays usados como muestra.

En el bucle se obtiene, para cada vela, su altura y la de su cuerpo y también el volumen. Si las alturas están por encima de lo considerado como valor alto y también el volumen, se pinta la vela de color verde.

A continuación, se obtiene en que percentil está el volumen de la vela actual y en función de eso se pinta el gradiente usando objetos ChartRectangle.

Para pintar el volumen y su media en un área distinta (debajo del gráfico):

    this._chart.AddChartArea("Volume");
    this._chart.PlotLine(historic.Volume, 1);

    Average volAvg = new Average(historic.VisualChart, historic.Volume, 20);
    volAvg.Load();
    this._chart.PlotLine(volAvg.MainLine, 1);
    Series serie = this._chart.GetLineSerie(volAvg.MainLine);
    serie.Color = Color.Red;

Si se procesa un periodo grande de días hay que recalcular los valores de la muestra usados por la lógica difusa. Puede hacerse cada día o cada pocos días pero debe hacerse con frecuencia para adaptarse a los cambios del mercado.

Aquí se han expuesto solo unos casos muy concretos de aplicación de la lógica difusa pero la lista de posibilidades es tan grande como nuestra imaginación. Podemos clasificar pendientes, canales, valores de indicadores, spreads, volúmenes de oferta y demanda…

Y, como se ha comentado previamente, al no ser necesarios valores fijos (tipo 200 de volumen o 20 puntos de altura) se puede aplicar un mismo estudio/investigación/estrategia a distintos valores sin tener que adaptar mínimos movimientos, volúmenes… de los distintos valores y las distintas fechas.

Anuncios
Galería | Esta entrada fue publicada en Programación, STMT. Guarda el enlace permanente.

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s