sábado, 17 de agosto de 2013

La Máquina Mágica

Cuando empecé a trabajar con los sistemas automáticos de trading, una de las primeras tareas que me autoasigné fue el desarrollar una metodología de trabajo que me permitiese determinar, de forma cuantitativa y dentro de un cierto intervalo de confianza, si un determinado sistema tiene esperanza matemática positiva, además de identificar cual es la estrategia de gestión del riesgo que mejor se le ajusta, y el tamaño óptimo de las posiciones a abrir. Una vez desarrollada la metodología, me llevé la desagradable sorpresa de que no existía en el marcado ninguna herramienta lo suficientementemente potente como para poder poner en marcha mi nueva metodología.

A partí de ahí, y gracias a mi formación como ingeniero informático, me puse a desarrollar mi propia herramienta de análisis de sistemas de trading. Con el tiempo, la herramienta llegó a un nivel de madurez que me hizo plantearme la posibilidad de venderla como un producto comercial. Como emprendedor sabía que sólo tienen éxito aquellos productos que los clientes necesitan, quieren, y están dispuestos a pagar por ellos. Pero ¿cómo no iban a querer los traders una herramienta que dado un sistema te dice si es o no rentabe, y además te ayuda a maxizar el retorno mientras minimiza el riesgo? Pues no, eso no es lo que quieren los traders. Al menos no es lo que quieren los traders individuales, que es el mercado al que me dirigía.

Efectivamente, la gente lo que quiere es una "Máquina Mágica". Es decir, una maquinita que pulses un botón y automáticamente salga dinero, sin que sea necesario dedicarle tiempo ni esfuerzo. Eso es lo que me estaban demandando. Y cuando le explicaba que dicha máquina no existe, los potenciales clientes no lo entendían, o mejor dicho, no lo querían entender. Algunos incluso se enfadaban, y me decían que el problema era que no quería compartir mis secretos (pero oiga, ha visto usted que tenga un Mercedes aparcado en la puerta de mi casa).

Así que no tuve más remedio que cancelar la versión comercial de Entropycs. Desgraciadamente ser empresario es incompatible con ser trader, ya que ambas son profesiones a tiempo completo, y hay que optar por una u otra. En cualquier caso, sigo mejorando la plataforma para mi uso interno, y seguiré dando cuenta de mis avances en este blog.

martes, 30 de julio de 2013

Indicador Técnico: RSI

El Índice de Fuerza Relativa, o RSI (del inglés Relative Strength Index), es un oscilador diseñado para medir la velocidad con la que varían los precios. El indicador RSI oscila entre los valores 0 y 100 y se calcula de la siguiente manera:

                       100
        RSI = 100 - --------
                     1 + RS

        RS = AG / AL

Donde AG es la ganancia media (del inglés Average Gain), es decir, la media aritmética de las últimas N barras con resultados positivos (y donde N es el periodo de cálculo del indicador), y AL es la pérdida media (del inglés Average Loss), o la media artimética de las pérdidas de las últimas N barras.

Por ejemplo, un RSI calculado sobre 14 barras podría ser el siguiente:


Tradicionalmente se dice que tenemos un mercado en sobrecompra cuando el RSI es superior a 70, y un mercado en sobreventa cuando es inferior a 30. Por tanto, un sencillo sistema de trading podría ser abrir en corto cuando tenemos un mercado en sobrecompra, y abrir en largo cuando está en sobreventa.

En el paquete TTR de R el indicador RSI se calcularía de la siguiente forma:

RSI(price, n = 14, maType)

donde maType es el tipo de media móvil que queremos utilizar para el cálculo del RSI (simple, exponencial, ...). Por ejemplo, el RSI(14) se calcularía como: 
 
data(ttrc)
price <- ttrc[,"Close"]
rsi <- RSI(price, n=14)

Como resultado la variable macd contendría algo similar a:


67.21311 68.33130 68.90238 71.65472 74.12134 74.12134 75.12550 70.69429 ...


martes, 23 de julio de 2013

Bolsa, timos y estadística

Cuando estudiaba matemáticas, en la asignatura de probabilidad y estadística de primero solían poner como ejemplo un sencillo timo en bolsa. El engaño era el siguiente: seleccionamos un gran número de inversores en bolsa (por ejemplo 1024), a continuación a la mitad le enviamos el Lunes una carta donde le decimos que durante la semana la bolsa subirá, y a la otra mitad otra carta donde le decimos que la bolsa bajará; a la semana siguiente, a los 512 inversores para los que hemos acertado les enviamos otra carta, nuevamente a la mitad le decimos que la bolsa subirá y a la otra mitad que bajará; a la semana siguiente, volvemos a hacer lo mismo con los 256 inversores para los que ya hemos acertado dos veces en nuestro pronóstico; al cabo de varias semanas nos quedarán unos 16 inversores para los que siempre hemos acertado; llegados a este punto le enviamos una última carta donde nos presentamos, les decimos cualquier parrafada de lo buenos que son nuestros métidos de predicción, y les ponemos como ejemplo las 6 semanas consecutivas que hemos acertado, y les decimos que si quieren la previsión para la siguiente semana nos tienen que pagar mil euros. Evidentemente, es difícil que alguien caiga en el timo, pero si lo organizamos a gran escala, empezando con 65.536 inversores y parando con 1024, a poco que pique uno de cada diez, tenemos un negocio redondo.

Este timo, que parece tan obvio, es utilizado habitualmente, por ejemplo, por los bancos: si preguntamos en un banco por un fondo de inversión rentable, seguro que nos muestran cuatro o cinco que nunca han perdido dinero; el cómo lo hacen es muy simple, se trata de abrir muchos fondos e ir cerrando aquellos que entren en pérdidas, de tal manera que los que queden tienen una rentabilidad continuada. También es un método utilizado por los gurús de la bolsa, en este caso el método consiste en hacer muchas predicciones cada día, y al día siguiente sólo recordad aquellas en las que han acertado.

Pero también se utiliza, y esto no es tan evidente, para el caso de los robots, o expert advisors, de trading automático. Ya que existen miles de robots funcionando, por pura estadística, algunos de ellos debe necesariamente ser rentables. Los vendedores nos muestran la rentabilidad pasada de dichos robots, y nos repiten una y otra vez que no se trata de "backtesting" o de rentabilidades en cuentas demo, sino de rentabilidades en real, como garantía de la eficacia del robot. Pero al igual que pasaba con nuestro timador de las cartas, lo normal es que estos robots, tarde o temprano, acaben abandonando la lista de robots con rentabilidades sostenidas en el tiempo, momento en el cual serán sustituidos por otros.

El que un robot haya tendio una rentabilidad sostenible en el pasado no quiere decir absolutamente nada, y por tanto, no debemos jugarnos nuestro dinero con ellos. Si queréis comprar un robot, seleccionar hoy un grupo de robots prometedores, seguir sus rentabilidades durante un tiempo prudencial, por ejemplo un año (el tiempo requerido depende de la frecuencia de las inversiones), y después decidir la compra.

lunes, 1 de julio de 2013

Indicador Técnico: MACD

El indicador técnico MACD, o Media Móvil Convergente/Divergente (del inglés Moving Average Convergence / Divergence)  es un oscilador que se basa en la diferencia de dos medias móviles, una media móvil lenta, y una media móvil rápida. El MACD se desglosa en tres componentes:
  • Línea MACD: media móvil rápida - media móvil lenta
  • Línea de Señal: media móvil aplicada sobre la Línea MACD
  • Histograma MACD: Línea MACD - Línea de Señal
Por ejemplo, el MACD con una media móvil lenta de 26, una media móvil rápida de 12, y una media móvil de señal de 9 tendría el siguiente aspecto:


El indicador MACD combina lo mejor de dos mundos: los indicadores de tendencia y los osciladores. Sin embargo, dado que el indicador no se encuentra acotado dentro de un rango predefinido, es difícil utilizarlo para detectar niveles de sobrecompra o sobreventa.

Un sistema sencillo basado en el indicador MACD podría ser el siguiente: cuando la Línea MACD cruza al alza a la Línea de Señal abrimos en largo, y cuando la Línea MACD cruza a la baja a la Línea de señal abrimos en corto.

En el paquete TTR de R el indicador MACD se calcularía de la siguiente forma:

MACD(x, nFast = 12, nSlow = 26, nSig = 9, maType)

donde maType es el tipo de media móvil que queremos utilizar para el cálculo del MACD (simple, exponencial, ...). Por ejemplo, el MACD(12, 26, 9) se calcularía como:

data(ttrc)
macd <- MACD( ttrc[,"Close"], 12, 26, 9, maType="EMA" )

Como resultado la variable macd contendría algo similar a:


           macd    signal
 [1,] 1.6680643 2.1294258
 [2,] 1.6230876 2.0281582
 [3,] 1.6606279 1.9546521
 [4,] 1.5104438 1.8658105
 [5,] 1.3984768 1.7723437


sábado, 15 de junio de 2013

Indicador Técnico: Rango Verdadero Medio

El Rango Verdadero Medio, o ATR (del inglés Average True Range), es un indicador técnico que mide la volatilidad de un símbolo. El ATR se basa en los rangos (diferencia entre los precios máximo y mínimo) de las velas, con algunas modificaciones para tener en cuenta la existencia de huecos. Definimos el rango verdadero como:

rango_verdadero = máx[(máximo-mínimo), abs(máximo-cierre_prev), abs(mínimo-cierre_prev)]

Y a continuación, el rango medio de las útimas N barras es la media simple, o exponencial, de los últimos N rangos verdaderos.

Por ejemplo, un ATR de 14 barras sería el sigiente:


Generalmente, el ATR no se utiliza por sí mismo con un criterio de apertura en un sistema, en lugar de eso, se suele utilizar en combinación con otros indicadores técnicos, o simplemente como un filtro de órdenes. Por ejemplo, podemos crear un sistema basado en el cruce de dos medias móviles, y utilizar el indicador ATR para situar nuestros niveles de stop loss: si el símbolo va más allá de N veces el ATR en la dirección contraria a nuestra orden, podríamos decir que el movimiento no puede explicarse por las fluctuaciones debidas al ruido del mercado, sino que seguramente se trate de un cambio de tendencia, y por tanto, deberíamos cerrar la orden.

En el lenguaje Entropys el ATR se calcula como:

ATR(VECTOR, n)

Donde VECTOR es una serie temporal de precios, como por ejemplo aquella dada por la variable del sistema SYMBOL, y n es la longitud utilizada para calcular el ATR.

Para calcular un ATR de longitud 14 sobre el símbolo actual utilizaríamos algo como:

ind <- ATR(SYMBOL, 14)

Como resultado, la variable ind contendría algo similar a lo siguiente:

                    tr     atr          trueHigh trueLow
2011-01-03 03:30:00 0.0000 0.0004642857 1.3283   1.3283
2011-01-03 03:45:00 0.0006 0.0004739796 1.3282   1.3276
2011-01-03 04:00:00 0.0002 0.0004544096 1.3282   1.3280
2011-01-03 04:15:00 0.0009 0.0004862375 1.3291   1.3282


sábado, 1 de junio de 2013

Programación Genética vs Gramáticas Evolutivas

Una de las principales problemas que se encuentran aquellos que descargan la plataforma Entropycs por primera vez es que el concepto de gramática evolutiva es difícil de entender. Y más concretamente, son muchos los que confunden las gramáticas evolutivas con la programación genética, y no es lo mismo. En esta entrada de blog intentaré explicar las diferencias entre ambas técnicas de optimización y búsqueda.

Quizás nos ayude a entender la diferencia si utilizamos el símil bioquímico de cómo se produce la evolución en la naturaleza. La información que nos permite "construir" un organismo vivo viene almacenada en una cadena de pares de bases denominada ADN, que a su vez se desliga en una cadena de ARN, que es interpretada generando secuencias de aminoácidos, que finalmente se convierten en las proteínas que son necesarias para el desarrollo de la vida. Cuando dos individuos se aparean, su descendencia herada una recombinación del ADN de los padres.

Tanto la programación genética como las gramaticas evolutivas se basan en mismo concepto de recombinación de la información de los padres; pero mientras las gramáticas evolutivas lo que recombinan son las cadenas de ADN (al igual que sucede en la naturaleza), la programación genética lo que recombina son las propias protenias finales. Traladado esto al mundo de la informática y de los lenguajes de programación, tenemos que las gramáticas evolutivas combinan cadenas de ADN que son interpretadas (por las gramáticas) para producir programas, y la programación genética lo que recombina son los propios programas.

En mi opinión, al añadir un nuevo nivel de abstracción introduciendo el concepto de gramática, se gana mucha flexibilidad, y se eliminan algunos de los principales problemas que nos encontramos con la programación genética.

Por ejemplo, las gramáticas evolutivas se basan en algoritmos genéticos para realizar la búsqueda de aquellos programas que mejor se adaptan a nuestras necesidades, pero nada nos impede utilizar otras técnicas de búsqueda, como son los enjambres de partículas, o evolución diferencial.

Por otro lado, con la programación genética el principal problema que nos encontramos es cómo garantizar que los programas que resultan de una recombinación son sintácitcamente correctos. Con las gramáticas evolutivas este problema simplemente desaparece, ya que la derivación de los programas, al estar basada en una gramática, por definición, son sintácticamente correctos.

Espero que con esta entrada haya quedado algo más clara la diferencia entre una optimización mediante gramáticas evolutivas y otra mediante programación genética.

sábado, 25 de mayo de 2013

¿Cómo saber si un sistema es rentable? (3)

Seguimos con la tercera entrada de nuestra metodología de desarrollo y análisis de sistemas de trading.

Una vez se tenga claramente definida la estrategia a seguir (como vimos en nuestra entrada anterior), se deberá proceder a implementar la estrategia mediante alguno de los lenguajes de programación existentes en las distintas plataformas de trading. Este tarea se compone de dos pasos:
1.- Desarrollo

Durante la fase de desarrollo sólo se espera que el código compile y que genere señales de entrada y salida en el mercado aproximadamente correctas (pueden contener errores e imprecisiones), y que no den ningún tipo de mensajes de error. El código fuente debe seguir los estándares de calidad que hayan sido marcados (indentación, comentarios, etc), e idealmente debería estar basado en plantillas de desarrollo ya existentes.
2.- Depuración

En este apartado se deberán comprobar las entradas y salidas individuales generadas por el sistema, así como los cálculos intermedios realizados. El objetivo es determinar si la implementación que se ha realizado de la estrategia es correcta. Para ello se deberá realizar una simulación histórica de la misma. El tamaño de la muestra para la simulación debe lo suficientemente grande para que se produzcan varias entradas en el mercado para cada una de las posibles combinaciones de reglas del sistema, filtros aplicables, gestión del riesgo y gestión monetaria. Durante la simulación se deberán utilizar valores “razonables” para los distintos parámetros de configuración, ya que en este paso lo importante es comprobar que las reglas funcionan correctamente, y no tanto evaluar la rentabilidad del sistema. A continuación se deberán analizar, barra a barra, las distintas entradas y salidas del mercado que se han producido, y comprobar que se ajustan a lo esperado.

Ejemplo: Cruce de dos Medias Móviles

Desarrollo

La estrategia ha sido programada mediante el lenguaje mql4 y la plataforma MetaTrader 4. El análisis de los datos ha sido realizado utilizando el lenguaje de programación R. Para los datos históricos, se utilizarán los datos en barras de 1 minuto proporcionados por el broker XTB, y que serán agrupados en barras de distintas longitudes (5m, 15m, 30m, etc).

Si alguien tiene interés en conseguir una copia del código, puede ponerse directamente en contacto conmigo y se la haré llegar por correo electrónico.

Depuración

Se ha comprobado el comportamiento correcto del sistema en los siguientes supuestos:
  • Entradas en largo y en corto
  • Re-entradas correctas después de una salida debido a un stop loss

Para las pruebas se ha utilizado una media móvil corta de 5 barras (una semana), una media móvil intermedia de 11 barras (medio mes), y una media móvil larga de 22 barras (aproximadamente un mes). El sistema se prueba sobre barras diarias para el símbolo EURUSD, durante los años 2010 y 2011. Nótese que cada vez que se ha encontrado un error, y se ha procedido a su corrección, la totalidad de los casos de prueba han sido repetidos (regression testing).

Los supuestos de prueba han sido articulados según los siguientes casos:

  • Entradas en largo
  • Entradas en corto
  • Re-entrada después de SL
  • Entrada incial
A modo de ejemplo, se muestran los resultados de las pruebas correspondientes al caso de entradas en largo:

Caso 1: Entrada en largo

El caso 1 se centra en la comprobación de las entradas en largo.

Objetivo: Comprobar que cuando la media móvil corta cruza al alza a la media larga se abre una nueva posición en largo, con el stop loss adecuado, y se cierra la posición en corto si la hubiera.

Resultado Esperado: Cierre y apertura de una nueva posición.

Resultado Obtenido: En el gráfico se puede observar que el cruce de la media móvil corta al alza sobre la media móvil larga se produce el 17/6/10. En este momento se cierra la posición que teníamos abierta en corto, y se abre una nueva posición en largo, con el correspondiente SL situado en la media móvil intermedia.






martes, 21 de mayo de 2013

¿Cómo saber si un sistema es rentable? (2)

-->
Continuamos con esta serie de entradas en la que explicamos nuestra metodología, basada en los trabajos de Robert Pardo, para decidir a priori si un sistema es o no rentable.

Formulación

El primer paso en la definición de un sistema de trading es especificar de forma clara y concisa cual es la idea de inversión subyacente. Una vez especificada la idea que se pretende implementar, se deben detallar la lista de indicadores técnicos que se utilizarán en su implementación, indicando cual es la función de cada uno dentro de la idea global del sistema. Así mismo se deberán especificar claramente, y sin ambigüedades, cuales son las reglas de entrada y salida del marcado, idealmente mediante pseudocódigo. A continuación se describirán los filtros, si es que existen, que serán aplicados a dichas reglas de entrada y de salida, y cual es el efecto esperado de cada uno. Finalmente se deberá detallar la política de gestión del riesgo (stop loss o similar) y de gestión monteraria (tamaño de las posiciones, recogida de beneficios, etc.) que serán utilizados como parte del sistema.

Por tanto, una correcta formulación del sistema se debe cubrir los siguientes aspectos:

  • Entradas y salidas
  • Gestión de riesgo
  • Gestión monetaria

Ejemplo: Cruce de Dos Medias Móviles

El sistema Cruce de Dos Medias Móviles (abreviado como CDMM) es un sistema de seguimiento de tendencia basado en el cruce de dos medias móviles: una media móvil corta y una media móvil larga. Cuando la media móvil corta cruza al alza a la media móvil larga, nos ponemos en largo, y cuando vuelve a cruzar a la baja, cerramos la posición. Igualmente, pero a la inversa, sucede para el caso de las posiciones en corto.

Indicadores Técnicos

El sistema CDMM se basa en el uso de dos indicadores técnicos:

  • Media móvil de corta duración
  • Media móvil de larga duración

El objetivo de la media móvil corta es seguir estrechamente los movimientos del símbolo, pero proporcionando una señal atenuada que facilite el análisis de su comportamiento. La media móvil corta nos evita, por tanto, falsas señales de entrada y salida en el mercado debido a los movimientos bruscos y de corta duración que suceden en los mercados.

El objetivo de la media móvil larga es determinar la tendencia del mercado: bajista o alcista. Para que sea efectiva debe tener una longitud relativamente larga, para que pueda coger las tendencias en su totalidad, y no se salga del mercado en los retrocesos.

Existen multitud de tipos de medias móviles que pueden ser utilizadas en el sistema CDMM: medias móviles simples, medias móviles exponenciales, medias móviles con ponderación lineal, etc. Sin embargo, según la literatura existente, no está claro que al variar el tipo de media móvil se pueda obtener una mejora significativa de los resultados del sistema. Por tanto, y para no aumentar innecesariamente el número de parámetros a optimizar, el tipo de media móvil a utilizar será fijado en medias móviles simples.

El cálculo de la media móvil se puede aplicar a distintos tipos de precios: cierre, alto, bajo, apertura, media, típico y ponderado. Según qué mercados, aplicar el indicador sobre un tipo de precio u otro puede variar significativamente el resultado del sistema. Por ejemplo, en los mercados regulados de acciones el precio de cierre de la sesión es un dato muy importante a tener en cuenta (subasta final). Sin embargo, en el mercado de divisas, al ser un mercado continuo, el precio de cierre de una barra pierde parte de ese significado especial. Por tanto, las medias móviles de este sistema serán calculadas sobre el precio medio de cada barra (la suma de los precios máximo y mínimo dividida por dos) al entender que este valor es el que mayor información proporciona sobre el contenido de dicha barra.

Reglas

Sea M(i) el valor de la media móvil larga en la barra i, y m(i) el valor de la media móvil corta en la barra i. El sistema CDMM se basa en las siguientes reglas:

  • Si m(i) >= M(i) y no tenemos ninguna posición abierta, entonces podemos abrir en largo.
  • Si m(i) >= M(i) y estamos en corto, entonces podemos cerrar la posición.
  • Si m(i) < M(i) y no tenemos ninguna posición abierta, entonces podemos abrir en corto.
  • Si m(i)< M(i) y estamos en largo, entonces podemos cerrar la posición.
  • El sistema no entrará en el mercado hasta que no se produzca el primer cruce de medias. Igual sucede con las re-entradas después de que una posición haya sido cerrada por un stop loss.

Stop Loss y Take Profit

Siguiendo la máxima de cortar las pérdidas cuanto antes, y dejar correr los beneficios, se utilizará un Stop Loss ajustado, pero suficientemente amplio para no salirse de las posiciones debido a los movimientos aleatorios del mercado. Para el cálculo del stop loss se utilizará una tercera media móvil de longitud intermedia, es decir, mayor que la media móvil corta, pero menor que la media móvil larga. Habitualmente en estos casos se utiliza un stop loss basado en algún indicador de volatilidad como el ATR. Pero en el sistema CDMM este tipo de indicadores serían rendundantes ya que el objetivo de la media móvil corta es precisamente filtrar la volatilidad que pudiera tener el símbolo. Nótese que cuando se cierra una posición debido al salto de un stop loss no se podrá volver a abrir una nueva posición hasta que se produzca un nuevo cruce de las medias móviles.

No se accederá al recurso de recoger beneficios con un Take Profit.

Filtros Aplicables

No se utilizarán filtros adicionales en esta estrategia.

jueves, 16 de mayo de 2013

¿Cómo saber si un sistema es rentable? (1)

-->
El principal problema al que se enfrenta el desarrollador de sistemas de trading quantitativo es el de determinar a priori si un sistema de trading es rentable o no lo es. Para ello, el desarrollador cuenta con la herramienta de las simulaciones históricas, es decir, comprobar si el sistema hubiera proporcionado beneficios de haberse utilizado en algún periodo de tiempo pasado. Sin embargo, aunque el sistema demuestre ser rentable en periodos de tiempo pasados, siempre nos quedará la duda de si lo que hemos encontrado es precisamente eso, un sistema capaz de describir a la perfección el pasado, pero con habilidad nula para predecir el futuro. Este riesgo es aun mayor si hemos utilizado algún tipo de optimización en el desarrollo de nuestro sistema, ya que existe el riesgo de caer en una sobre-optimización del mismo. Y precisamente, evitar las sobre-optimizaciones, es una de las tareas más difíciles a las que se enfrentan los desarrolladores de sistemas.

Al día de hoy, la mejor metodología para desarrollar un sistema, y determinar a priori si será o no rentable en la operativa real con cierto grado de confianza, es la metodología propuesta por Robert Pardo en su libro “The Evaluation and Optimization of Trading Strategies”. Sin embargo son muchos más los detractores de la metodología de Pardo que sus seguidores, y son muchas las críticas que ha recibido. A mi entender la mayoría de las críticas se deben a una incorrecta interpretación de las ideas que plantea Pardo. El problema es que el libro tiene importantes carencias: está sobre-escrito, los contenidos están algo desorganizados, y se hecha de menos algunos ejemplos concretos de desarrollo de estrategias que clarifiquen los conceptos. Esto obliga a que sea necesario releer el libro varias veces (en mi caso llevo ya 6), antes de comprender bien las ideas de Pardo.

Para intentar corregir este problema, en esta serie de entradas voy a describir la metodología de Robert Pardo (con algunas mejoras de mi propia cosecha), paso a paso, y con un ejemplo concreto, para que no quede ningún tipo de dudas sobre qué es lo que hay que hacer exactamente. Evidentemente, nuestra plataforma Entropycs [http://www.entropycs.com] (de la que en breve daremos noticias) proporciona todas aquellas herramientas que son necesarias para poner en práctica esta metodología.

La estrategia que vamos a utilizar como ejemplo es una estrategia muy simple basada en el cruce de dos medias móviles. Y como buen punto de partida de nuestro documento de descripción y análisis de la estrategia, recomiendo empezar escribiendo una pequeña introducción donde se explique brevemente cual es la idea subyacente a la estrategia. Allá vamos.

Introducción

El sistema Cruce de Dos Medias Móviles (abreviado como CDMM) es un sistema de seguimiento de tendencia basado en el cruce de dos medias móviles: una media móvil corta y una media móvil larga. Cuando la media móvil corta cruza al alza a la media móvil larga es una señal de que nos encontramos ante una tendencia al alza, como muestra la siguiente figura:


Y cuando la media móvil corta cruza a la baja a la media móvil larga, probablemente nos indique el inicio de una tendencia a la baja:


Los sistemas basados en el cruce de medias móviles son ampliamente conocidos entre los desarrolladores, pero ello no significa necesariamente que no puedan ser rentables cuando son configurados correctamente.

La principal desventaja de los sistemas de trading basados en el cruce de medias móviles es que cuando el mercado está lateral se producen muchas falsas señales de entrada que causan importantes pérdidas. El sistema CDMM intenta corregir este problema aplicando la máxima del trading de cortar cuanto antes las pérdidas y dejar correr los beneficios, con el objetivo de que los beneficios recogidos en las tendencias compensen ampliamente las pérdidas producidas durante los periodos de mercado lateral.


Actualmente existen innumerables extensiones y mejoras que pueden ser aplicadas a los sistemas basados en el cruce de medias móviles (triples medias, varios tipos de caracterizaciones, combinación con otros indicadores, etc.), pero dichas extensiones no serán analizadas en el presente documento, al entender que la mayoría de ellas aportan poco, o muy poco, al rendimiento del sistema básico.

miércoles, 24 de abril de 2013

¿Cúantos Sistemas de Trading Existen?

-->
En una entrada anterior de este blog vimos cómo mediante el uso de gramáticas se podían generar automáticamente sistemas de trading. Evidentemente la siguiente pregunta está clara, de entre todos estos posibles sistemas, ¿cómo buscamos aquellos que son rentables? Existen muchas alternativas para la búsqueda, desde el uso de algoritmos genéticos (de ahí lo de gramáticas evolutivas), hasta las nubes de partículas, pasando por la amplia colección de técnicas de optimización que existen (y de las que algún día hablaremos en este blog). Sin embargo, en esta entrada de blog vamos a plantearnos otra opción, que aunque en un principio parece una locura, quizás no lo sea tanto. La pregunta es: ¿podríamos evaluar TODOS los sistemas de trading existentes?

Imaginemos que queremos trabajar con sistemas de trading basados en la combinación de indicadores técnicos. En el paquete TTR de R tenemos una colección de más de 30 indicadores. ¿De cuantas maneras posibles se podrían combinar? Empecemos el caso más básico, consistente en comparar un indicador técnico con un número entero; si es superior a dicho entero, nos ponemos en corto, y si es inferior, nos ponemos en largo:

SI (“indicador” op_bol “entero”) largo SINO corto

Por ejemplo,

SI (RSI(14) < 10) largo SINO corto

Evidentemente, la mayoría de los sistemas así desarrollados no tendrían ningún sentido, y darían pérdidas, pero si queremos buscar sistemas nuevos que no hayan sido antes explorados, no deberíamos descartar ninguna idea a priori.

¿Cuantos sistemas existen basados en este formato? Pues si contamos con 33 posibles indicadores técnicos, con un conjunto de 30 posibles enteros a evaluar para cada indicador (de 0 a 9, de 10 a 90 con incrementos de 10, y de 100 a 900 con incrementos de 100), y dos operadores boleanos ('>' y '<') hacen un total de 59.400 sistemas. Ahora bien, ¿cuanto se tarda en evaluar cada sistema? Según la metodología que utilizamos en Entropycs (pruebas multiperiodo y multimercado) tardamos 30 minutos en evaluar cada uno, por lo que evaluarlos todos nos llevaría algo más de 3 años. Evidentemente parece que la idea no es del todo viable. Pero existe mucho margen para la optimización: mejoras en el propio código R de evaluación, el uso de procesadores multinúcleo, el uso de clusters de PCs, o la paralelización mediante tarjetas gráficas (GPUs). En Entropycs estamos convencidos de que con relativamente poco esfuerzo podríamos evaluar un sistema en menos de 10 segundos, lo que reduciría el tiempo de evaluación de todos los sistemas a tan sólo una semana, que es algo más que asumible.

Para el caso de combinaciones de 2 indicadores mediante la fórmula:

<indicador> <op_rel> <indicador>

Nos llevaría a los 2 millones de sistemas, que a 10 segundos, tardaríamos casi un año en su evaluación. Y a más indicadores, el número de sistemas posibles se dispara. Para los sistemas de la forma:

<indicador> <op_rel> <indicador> <op_bol> <indicador> <op_rel> <indicador>

nos vamos a los 7 billones de sistemas (billones de los europeos). Y para los sistemas de tipo:

<indicador> <op_art> <indicador> <op_rel> <indicador> <op_bol> <indicador> <op_art> <indicador> <op_rel> <indicador>

ya nos vamos a 31*10^18 sistemas. Imposible de evaluar, ¿no?

Bueno, quizás no tanto. Pensemos en el caso del ajedrez, donde existen 2*10^116 partidas posibles, y los programas de ajedrez no lo hacen tan mal (de hecho, hace años que ningún humano es capaz de ganarle al mejor de los programas). La supercomputadora de ajedrez Deep Blue era capaz de evaluar 200 millones de jugadas por segundo (y de aquello hace 15 años). Utilizando estos números, sería cuestión de horas evaluar los sistemas con 4 indicadores, y los de cinco empezaría a dejar de ser una utopía (del orden de 4 años).

Y, sobre todo, recordemos lo que dice la sabiduría popular del trading: “si con 5 indicadores tu sistema no es rentable, nunca lo será por muchos más indicadores que añadas”.

jueves, 18 de abril de 2013

Buscando Huecos en los Datos

-->
En una serie de entradas de este blog vimos cómo cargar los datos históricos de forex en una base de datos relacional, y cómo disponer los datos en este formato tenía ciertas ventajas a la hora de proceder a su análisis. En esta ocasión vamos a ver otra de las ventajas de las bases de datos, en concreto, cómo nos pueden ayudar a la hora de buscar huecos en los datos históricos.

Todos los ficheros de datos históricos tienen huecos. A veces, incluso, nos podemos encontrar con saltos que comprenden varios días, y que pueden llegar a resultar muy peligrosos, porque pueden distorsionar de forma importante nuestro análisis. Por tanto, es importante conocer la calidad de los datos que estamos utilizando en nuestros back tests.

Una vez tengamos los datos en la base de datos en el formato en el que habíamos propuesto en las entradas anteriores de nuestro blog, podemos proceder a su análisis.

Si queremos conocer el número de huecos de una determinada longitud que existen en el histórico de datos, escribiremos:

SELECT count(*),
    ((SELECT MIN(e2.unix) FROM eurusd e2 
        WHERE e2.unix > e1.unix) - e1.unix - 60) / 60 as minutes
FROM eurusd e1 WHERE minutes = 1

donde 'minutes' es la longitud en minutos del hueco que estamos analizando. También podríamos ver concretamente en qué fecha y hora se producen dichos huecos, para ello escribiríamos:

SELECT DATETIME(e1.date, '+1 minutes') AS start_date,
     DATETIME((SELECT MIN(e2.date) FROM eurusd e2 WHERE e2.date > e1.date), '-1 minutes') AS end_date,
     ((SELECT MIN(e2.unix) FROM eurusd e2 WHERE e2.unix > e1.unix) - e1.unix - 60) / 60 as minutes
FROM eurusd e1 WHERE minutes = 1

o si lo que queremos es sacar una tabla que nos indique para cada longitud de hueco el número de ellos que hay, escribiríamos:

SELECT count(*),
    ((SELECT MIN(e2.unix) FROM eurusd e2 WHERE e2.unix > e1.unix) - e1.unix - 60) / 60 as minutes
FROM eurusd e1 GROUP BY minutes

Finalmente, a modo de ejemplo voy a mostrar los resultados de un análisis comparativo realizado sobre dos históricos de datos, uno de ellos descargado desde la página web de Forex Tester, y el segundo utilizando el Centro de Historiales de la herramienta MetaTrader y a través del broker XTB.

El siguiente gráfico muestra para cada longitud de hueco desde 1 a 30 minutos el número de huecos encontrados:


Como se puede observar, el número de huecos de longitudes 1, 2, 3 y 4 es tremendamente grande, del orden de 3 huecos al día para XTB, y de 4 para Forex Tester. Este hecho debería ser tenido en cuenta por todos aquellos que utilizan sistemas automáticos que trabajan sobre barras de un minuto, sobre todo si se basan en optimizaciones y backtests de los mismos.

martes, 16 de abril de 2013

Evolución Gramatical, Sistemas de Trading y R (2/2)

-->
En una entrada anterior de este blog vimos lo que era una gramática, y cómo se podían utilizar las gramáticas para crear automáticamente sistemas de trading. En esta entrada vamos a ver cómo se puede implementar todo esto con R. Aunque el código es lo suficientemente genérico para poder utilizar cualquier gramática, vamos a seguir con nuestro ejemplo de gramática para la generación de números enteros, para no complicar demasiado la cosa.

Lo primero que tenemos es que definir nuestra gramática. Para ello utilizamos una lista de R con las reglas de producción. Cada elemento de la lista es una regla, y dentro de cada regla, las distintas opciones van como elementos en un vector. Seguimos el convenio de encerrar los símbolos no terminales entre '<' y '>', y dentro de una misma regla de producción separamos los diferentes tokens mediante espacios (si no lo hiciésemos así, tendríamos que recurrir a un analizador léxico, y eso lo complicaría todo). A continuación declaramos el símbolo inicial, y finalmente dentro de un bucle while() aplicamos las reglas de producción iterativamente a los símbolos no terminales hasta que todos los símbolos que queden en la cadena sean terminales.

En este caso hemos utilizado la función sample() para seleccionar aleatoriamente qué regla de producción tenemos que aplicar. En un entorno de producción real deberíamos reemplazar esta regla por algún método de búsqueda inteligente, tipo algoritmo genético o enjambre de partículas. Pero este es tema para una futura entrada del blog.

# Definición de la gramática
nt <- list(
    entero = c("<entero> <digito>", "<digito>"),
    digito = c("1", "2", "3", "4", "5", "6", "7", "8", "9", "0")
)

# Símbolo inicial
programa <- c("<entero>")

fin <- FALSE

while (!fin) {

    fin <- TRUE
    nprograma <- c()

    for(i in 1:length(programa)) {

        token <- programa[i]

        if( grepl("<.+>", token) ) {

            # Se trata de un símbolo no terminal, hay que parsearlo

            # Quitamos los marcadores < y >
            token <- substr(token, 2, nchar(token)-1)

            # Seleccionamos la regla adecuada
            regla <- nt[names(nt)==token][[1]]

            # Seleccionamos aleatoriamente una producción
            prod <- sample(regla, 1)

            # Parseamos la producción a aplicar y la añadimos
            nprograma <- c(nprograma, unlist(strsplit(prod, " ")))

            # Tenemos que hacer otra iteración
            fin <- FALSE

        } else {

            # Se trata de un símbolo terminal, lo añadimos tal cual
            nprograma <- c(nprograma, token)

        }

    }

    programa <- nprograma

}

# Programa final
sistema <- paste(programa, collapse="")

print(sistema)

jueves, 11 de abril de 2013

Evolución Gramatical, Sistemas de Trading y R (1/2)

-->
En una entrada reciente de este blog describí un sistema para la generación automática de sistemas de trading. Este sistema giraba en torno al concepto de “Evolución Gramatical”, optimizadores avanzados, y el lenguaje de análisis estadístico R. Degraciadamente R no dispone de ningún paquete específicamente diseñado para la optimización de sistemas basado en evoluciones gramaticales. Sin embargo, implementar los fundamentos de este sistema no es complicado. En esta serie de entradas vamos a revisar brevemente qué es eso de la evolución gramatical, cómo puede ser implementada en R, y qué tiene que ver con los sistemas de trading.

Las gramáticas son una herramienta muy conocida en el mundo de la ingeniería informática, y más concretamente, en el área de compiladores. Las gramáticas nos permiten definir de manera rigurosa los lenguajes de programación (como por ejemplo C++ o java), y por tanto, nos permite determinar si un determinado código fuente está correctamente escrito según el estándar del lenguaje. Además, las gramáticas también son útiles a la hora de compilar los programas, es decir, de transformar el código fuente de un programa en código máquina entendido por el ordenador.

Sin embargo, en el caso que nos ocupa, la generación de estrategias de trading, le vamos a dar la vuelta a la tortilla. Es decir, no utilizamos las gramáticas para decidir si una estrategia es (léxica y sintácticamente) correcta, sino para generar automáticamente el código de dicha estrategia. Podríamos, por ejemplo, definir una gramática que nos permita generar estrategias basadas en el cruce de medias móviles, y dejar que sea el propio ordenador el que “pruebe” distintas formas de combinar las medias móviles en una estrategia. Por ejemplo, el sistema que utilizamos en Entropycs generaría sistemas como los siguientes:

* SMA(simbolo,6)>SMA(simbolo,4+1) 
  | SMA(simbolo,92)>SMA(simbolo,90)

* SMA(simbolo,10)>SMA(simbolo,30)
  & SMA(simbolo,2)>SMA(simbolo,36)

* SMA(simbolo,116)>SMA(simbolo,99)

Evidentemente la mayoría de los sistemas así creados no tienen mucho sentido, pero si pensamos que el ordenador genera y evalúa varios centenares de sistemas por segundo, podemos hacernos una idea del potencial de este método.

Para describir las gramáticas se utiliza la denominada la notación Backus-Naur (BNF). Técnicamente la gramática se compone de un conjunto de símbolos terminales, un conjunto de símbolos no terminales, unas reglas de producción, y un símbolo inicial. Aunque suene muy complejo, la idea es muy sencilla. Veamos un ejemplo. Supongamos que queremos definir una gramática que genere números enteros de cualquier longitud. Un número se compone de uno o más dígitos, y los dígitos son los números de 0 a 9. Por tanto, la gramática sería

<número> := <número><dígito> | <dígito>
<dígito> := 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9

Los símbolos no terminales son <número> y <dígito>; los símbolos terminales sería de 0 al 9, y el símbolo inicial sería <número>. Las reglas de producción son las vistas más arriba y transforman un símbolo no terminal, a la izquierda del :=, por cualquiera de los símbolos (terminales o no) de la derecha, que vienen separados por '|'. Notese que en la generación de sistemas de trading seleccionaríamos al azar (o según nuestro algoritmo de búsqueda) el símbolo de la derecha a utilizar.

Por ejemplo, una posible evolución de la gramática sería:

Paso 1: <número>
Paso 2: <número><dígito>
Paso 3: <número><dígito>5
Paso 4: <dígito>35
Paso 5: 135

Y al ser todos los símbolos ya terminales, acabaría el proceso. Dejo propuesto al lector como ejercicio crear una gramática que sume dos números enteros.

¿Y cómo se hace esto en R? Pues eso es el tema del que tratará nuestra siguiente entrada de blog.

domingo, 7 de abril de 2013

Modificador de Relevancia Estadística

-->
Uno de los principales inconvenientes con los que nos encontramos a la hora de evaluar a priori la rentabilidad de un sistema de trading es el de la relevancia estadística de los resultados. De sobra es conocido que para que se pueda realizar un análisis estadístico sobre un conjunto de datos es necesario que dicho conjunto tenga un tamaño mínimo. Es difícil decir exactamente que se entiende por “tamaño mínimo”, pero parece que el valor más aceptado es el de 30 muestras (o el de 5 por celda en el caso de trabajar con tablas de contingencia). Si lo que estamos trabajando es con un sistema de seguimiento de tendencia basado en el cruce de dos medias móviles, y nuestro backtest se realiza sobre barras diarias en un periodo de 6 años, es posible que no lleguemos a ese número mínimo de 30 operaciones (entrada + salida), sobre todo si las medias móviles se calculan sobre periodos de tiempo muy largos.

En estos casos lo que se hace es evaluar a mano el número de operaciones realizadas, y si según nuestro criterio personal decidimos que es muy bajo, se descarta el análisis por no ser relevante. Pero si lo que estamos utilizando es una plataforma de optimización automática de sistemas, la cosa se complica un poco. Porque, ¿qué hacemos en este caso? ¿simplemente descartamos aquellas iteraciones que produzcan menos de 30 entradas? ¿no deberían ser tenidas en cuenta también aquellas con 29 entradas? ¿y 28? ¿y 27? ...

Para solucionar este problema propongo utilizar una especie de modificador de relevancia estadística, que pondere nuestro indicador de bondad de la estrategia según la relevancia estadística de los resultados. Este modificador debería poder ser aplicado indistintamente al indicador de bondad que habitualmente utilicemos, ya sea beneficio neto, drawdown máximo, ratio de Sharpe, SQN, etc. Desconozco si en la literatura estadística, o sobre trading cuantitativo, se ha propuesto alguna solución similar a la aquí planteada. Si es así, le rogaría a los lectores escriban un comentario a esta entrada de blog con la correspondiente referencia.

A priori, lo natural sería utilizar como modificador de relevancia alguna variación del error estándar utilizado en los propios análisis estadísticos. A saber, multiplicar nuestro indicador por 1-1/sqtr(n) (si lo que andamos buscando es maximizar el indicador). El problema de esta solución es que con muy pocas operaciones, ya se considera que el indicador es bastante confiable. Por ejemplo, con 5 operaciones ya tendríamos una ponderación del 55% sobre el indicador. Véase la siguiente figura:

Un modificador más adecuado podría estar basado en una tangente hiperbólica, o en la función logística. Yo me inclino más por la función logística, y en concreto, por la función 1/(1+exp((-n/5)+6)). El valor 6 viene del hecho de que la función logística sólo es interesante en el intervalo [-6,6], ya que para valores mayores de 6 es prácticamente 1, y para valores menores de 6 es prácticamente 0. El valor de 5 se escoge para centrar la función en el valor 30 (5*6) del que antes habíamos hablado. Así el indicador es progresivamente más relevante de 20 a 40 operaciones, para valores menores de 20 se degrada muy rápidamente, y para valores mayores de 40 el modificador apenas si tiene impacto. Justo lo que buscamos. Véase la figura:


Evidentemente, comentarios, opiniones, y modificadores alternativos, son bienvenidos.

sábado, 30 de marzo de 2013

Plan de Trabajo

En esta ocasión me gustaría compartir con vosotros el plan de trabajo que me mantendrá ocupado durante las siguientes semanas (y de cuyos avances iré dando cuenta en este blog). Básicamente lo que pretendo crear es un sistema para el desarrollo automático de sistemas de trading, así como para su puesta en marcha, seguimiento y evolución. Evidentemente, el desarrollo estará basado en R.

Las principales elementos en los que se basa el diseño del sistema son:
  • Aunque el sistema global pueda ser particularmente complejo, las estrategias de trading que finalmente se pongan en operativa real deben ser muy simples.
  • A la hora de buscar las estrategias de trading óptimas lo que prima es la robustez de las mismas, y la maximización de los beneficios se deberá alcanzar con la gestión monetaria.
La solución a desarrollar se compone de tres módulos:
  • Módulo de Búsqueda de Estrategias: tiene por objetivo realizar una búsqueda inteligente sobre un amplio espacio de posibles estrategias, seleccionando un conjunto de estrategias candidatas.
  • Módulo de Selección de Estrategias: partiendo de las estrategias candidatas generadas en el módulo anterior selecciona aquellas que son robustas.
  • Módulo de Operativa Real: partiendo de las estrategias robustas, a las que se le añade un sistema de gestión monetaria, realiza trading real. También es responsable del seguimiento y evolución de las estrategias.

Búsqueda de Estrategias
El módulo de Búsqueda de Estrategias a su vez se compone de los siguientes submódulos:
  • Algoritmo de Búsqueda: es el responsable de realizar una búsqueda inteligente por el espacio de soluciones. Se utilizará un algoritmo basado en enjambres de partículas (particle swarm) dado que lo que nos interesa es encontrar un conjunto de óptimos locales, y no el óptimo global.
  • Generador de Candidatos: para la generación de candidatos de estrategias de trading se utilizará una evolución gramatical (gramatical evolution), basada en un conjunto de gramáticas BNF específicamente diseñadas para el caso. Se utilizan gramáticas por su versatilidad a la hora de definir la forma que queremos que adopten las estrategias de trading (tendencial, pares, cointegración, ...).
  • Evaluación Rápida: como función objetivo durante la búsqueda se utilizará un procedimiento rápido de evaluación de estrategias, basado en una versión simplificada del método de Robert Pardo (sin análisis walk-forward). Se utiliza el método de Robert Pardo por su orientación hacia conseguir sistemas robustos.
En el caso de ser necesario se utilizarán técnicas de paralelización basadas en GPUs.

Selección de Estrategias
El módulo de Selección de Estrategias parte del conjunto de estrategias candidatas al que se ha llegado en el apartado anterior, y sobre ellas aplica el método Robert Pardo en su totalidad para filtrar aquellas estrategias que son robustas y presentan una esperanza matemática positiva. Al igual que en caso anterior, en caso de ser necesario se utilizarán técnicas de paralelización basadas en GPUs.

Operativa Real
El módulo de Operativa Real toma las estrategias seleccionadas en el módulo anterior y las pone a operar en una cuenta real de manera automática. Este módulo a su vez se compone de los siguientes submódulos:
  • Gestión Monetaria: se encarga de añadir la parte de gestión monetaria a las estrategias de trading. La estrategia a utilizar se basará en los trabajos de Ralph Vince.
  • Trading: módulo encargado de enviar las señales al mercado. Como broker se utilzará Interactive Brokers ya que dispone de un interfaz para operativa automática con R.
  • Re-optimización: se encarga de la re-optimización periódica de las estrategias, según la periodicidad óptima resultante del análisis walk-forward.
  • Evaluación: se encarga de la evaluación de los resultados obtenidos en real con la operativa de trading, y realimenta al submódulo de gestión monetaria. 

jueves, 14 de marzo de 2013

Integración de MetaTrader y R


Ya hemos hablado en entradas anteriores de las limitaciones que plataformas como MetaTrader presentan a la hora de hacer un análisis cuantitativo de las estrategias de trading, y de cómo con R se podrían cubrir esas limitaciones. En esta ocasión vamos a ver cómo se podría integrar MetaTrader y R para que cada uno haga aquella función que mejor sabe hacer, es decir, con MetaTrader desarrollamos una estrategia y la probamos con datos históricos, y con R analizamos los resultados, optimizamos la estrategia, y realizamos un análisis walk-forward.

Existen varias alternativas para integrar MetaTrader y R. A continuación revisamos brevemente algunas:

MT4 API nos permite acceder a la mayoría de las funciones de MetaTrader (tales como abrir o cerrar órdenes, calcular indicadores técnicos, recuperar el estado de una cuenta, etc) desde un programa en C externo, que a su vez, podría ser llamado desde R. Esta solución es la que mejor nos permitiría integrar MetaTrader con R. Desde R controlaríamos casi todo el proceso, desde definición de la estrategia, testing, optimización, análisis, trading real, etc., y MetaTrader lo utilizaríamos básicamente para abrir y cerrar órdenes (control de stop loss y demás), y llevar el control de la cuenta. El mayor inconveniente es que se trata de una solución cerrada y de pago ($450).

Con R for MetaTrader le daríamos la vuelta al calcetín, es decir, desde MetaTrader podríamos invocar funciones escritas en R. En este caso, el control lo llevaría MetaTrader, lo cual tiene sus limitaciones, ya que el análisis y la optimización de estrategias seguiría siendo la de MetaTrader, y carecemos de walk forward. Esta solución es interesante si queremos desarrollar estrategias de trading avanzadas, por ejemplo, podríamos desarrollar una estrategia basada en Self Organized Maps utilizando R, que se invocaría desde MetaTrader. Además, este producto es libre y gratuito.

La última solución sería procesar los ficheros HTML de resultados generados por MetaTrader e importar los datos en R. Esta es la solución más sencilla, ya que no requiere software adicional, aunque requeriría de algo de programación para hacer una automatización completa del proceso de análisis de una estrategia. Dada su sencillez, en el resto de esta entrada de blog vamos a ver un ejemplo de cómo podemos importar los resultados de MetaTrader en R. Nótese que cuando hablo de resultados me refiero a todo tipo de resultados que se puedan grabar como ficheros tipo HTML, desde el testing de una estrategia, los resultados de una optimización, o los resultados de la operativa real.

Lo primero que tendríamos que hacer es importar (e instalar si no lo hemos hecho ya) el paquete XML de R. Este paquete contiene multitud de utilidades para crear y trabajar con ficheros XML, y sus derivados, como HTML.

library('XML')

A continuación vamos a importar los datos correspondientes a un informe de testing (Strategy Tester Report) generado por MetaTrader sobre una estrategia concreta. Lo que vamos a importar es el listado de entradas que se han producido en el mercado, y la información relativa a las mismas (tipo, número de orden, volumen, precio, S/L, T/P, beneficios y balance). Para ello escribimos la orden:

mitabla = readHTMLTable("C:/Users/Rafael/src/R/CDMM.htm", header=T, colClasses=c("integer", "character", "character", "integer", "numeric", "numeric", "numeric", "numeric", "numeric"), which=2)

El primer argumento es el nombre del fichero HTML generado por metatrader. En el segundo le indicamos que la tabla que contiene los datos dispone de una cabecera, que a su vez será utilizada por R. El tercer parámetro es una lista de tipos de datos, que ayudará a R a interpretar correctamente los valores que va a leer. Y por último, con el parámetro “which” le indicamos a R que lo que queremos importar es la segunda tabla del fichero (la primera corresponde a la tabla resumen).

En este momento tenemos en R una variable llamada “mitabla” a la que le podemos aplicar toda la potencia de análisis de R. Por ejemplo podríamos empezar por

summary(table$Beneficios)

y ya tendríamos más información sobre nuestra estrategia que la que nos proporciona MetaTrader.

martes, 12 de marzo de 2013

Trabajar con Datos de Forex con R y SQLite (5/5)


En esta ultima entrega de esta serie vamos a ver cómo podemos acceder a los datos almacenados en nuestras bases de datos SQLite desde R. Para ello vamos a utilizar el paquete DBI de R. DBI es un paquete que permite acceder de manera unificada a diferentes bases de datos, entre ellas Oracle, MySQL, y SQLite. Cada base de datos cuenta con su propia librería que debe ser previamente cargada en R:

library(“DBI”)
library(“RSQLite”)

A continuación abrimos una conexión con la base de datos. Para ello primero tenemos que crear un driver que nos gestione la conexión, y después abrir la conexión propiamente dicha con el fichero donde se encuentre la base de datos:

drv <- dbDriver(“SQLite”)
db <- dbConnect(drv, “eurusd.db”)

En este momento podemos enviar nuestras consultas SQL a la base de datos, como por ejemplo:

rs <- dbSendQuery(db, “SELECT MAX(high) AS High, MIN(low) as Low, date as Date
    FROM eurusd
    WHERE date > '2010-01-01' AND date < '2011-01-01'
    GROUP BY round(unix / (8 * 60))
    “)

Para recuperar los datos tenemos que utilizar la función fetch(), a la que le debemos indicar cuantas barras queremos recuperar, o -1 para recuperar la totalidad:

EURUSD <- fetch(rs, n=25)

En este momento la variable EURUSD contiene los datos listos para ser analizados.

Cuando no necesitemos recuperar más datos de la consulta, debemos liberar esta con:

dbClearResult(rs)

Y finalmente, para cerrar la conexión con la base de datos hacemos:

dbDisconnect(db)

Y con esto damos por cerrada esta serie de entradas sobre cómo trabajar con datos de Forex desde R y SQLite.

sábado, 9 de marzo de 2013

Gestión Monetaria: El Juego de las Caras


Generalmente, en los cursos de trading nos explican que tener éxito invirtiendo no sólo depende de que utilicemos una estrategia con esperanza positiva, sino que igual de importantes son la gestión monetaria y el control de las emociones, las famosas tres Ms (Mind, Method, Money) de las que habla Alexander Elder en su libro Vivir del Trading. Sin embargo, y por mucho que nos lo repitan, al final acabamos poniendo todos nuestros esfuerzos en encontrar la mejor estrategia, y nos olvidamos de las otras dos componentes del éxito.

Para poner de relieve la importancia de la gestión monetaria y del control de las emociones, me gustaría hablar en esta ocasión de un juego que se celebra todos los Viernes Santo en la pequeña localidad de Calzada de Calatrava (Ciudad Real). El llamado “Juego de las Caras”. Las Caras es un juego de azar en el que los ciudadanos se juegan dinero de verdad (y mucho). La gente que quiere participar en el juego se coloca alrededor de un corro, y en el centro del mismo se coloca una persona que actúa como “banca”. Cada persona alrededor del corro apuesta una determinada cantidad de dinero que la banca debe cubrir. A continuación se lanzan dos monedas. Si salen dos cruces ganan los apostantes; si salen dos caras gana la banca; y si sale cara y cruz, se repite el lanzamiento. Como se puede observar la probabilidad de ganar en este juego es del 50%, y no existe ninguna estrategia que pueda mejorar este porcentaje. Y sin embargo, a la larga gana la banca. ¿Cómo es posible esto?


El primer problema es que la gente suele gestionar mal el dinero. Si dispongo de 50 euros, los apuesto en su totalidad, y salen caras, pierdo todo el dinero y el juego se acabó para mi. Pero aunque sepa gestionar mejor el dinero y apueste de 10 en 10 euros da igual, a poco que tenga una racha bajista (no tienen por que ser las 5 perdidas consecutivas necesariamente, sino un drawdown de 5) lo he perdido todo. Es decir, el que tiene más dinero, tiene más posibilidades de ganar. Y la banca suele tener mucho más dinero que cualquier jugador individual (en la práctica juntan su dinero varias personas para actuar de banca).

El segundo es que la gente no controla sus emociones: ambición y miedo. Son muchos los que después de tres ganancias consecutivas se creen que están en “racha” y quintuplican su apuesta de golpe, perdiendo todo lo que había ganado, y más. Y más difícil de controlar es la contraria, el miedo. Después de tres pérdidas consecutivas la gente decide darse un “descanso” para comprobar con desesperación cómo en las tres siguientes tandas salen cruces. Nótese que la banca no tiene este problema, porque está obligada a cubrir todas las apuestas, luego no puede verse influida por la ambición y el miedo.

Y finalmente está el tema de la diversificación. Nosotros como jugadores individuales no tenemos posibilidad de diversificar nuestras apuestas. Sin embargo la banca está jugando contra jugadores que tiene poco dinero y jugadores que tienen algo más, jugadores que saben gestionar sus apuestas y jugadores que no, y jugadores que a veces se dejan guiar por la ambición y el miedo y a veces no. La banca sí que está diversificando sus apuestas de manera efectiva.

Mi recomendación, por si alguien quiere ser banca este Viernes Santo, es estimar el número medio de jugadores de un corro y la apuesta media por jugador, multiplicar ambos valores y el resultado volverlo a multiplicar por 150. Y si disponéis de ese capital, ¡negocio seguro!

Nos vemos en Las Caras.

martes, 5 de marzo de 2013

Trabajar con Datos de Forex con R y SQLite (4/5)


En la entrada anterior de este blog vimos como crear barras de cualquier longitud utilizando SQLite. Sin embargo, nos encontramos con el problema de que el tiempo de respuesta de las consultas era demasiado elevado. Esto nos puede crear ciertos problemas en operativa real para estrategias que trabajen en barras muy cortas (por ejemplo de un minuto), y sobre todo, supone un gran problema cuando queremos realizar análisis de tipo walk forward, ya que este tipo de análisis requiere de múltiples consultas.

Pero aquí es donde entra en juego las optimizaciones que permite SQLite, y sobre todo, ese misterioso atributo unix que hemos añadido a nuestra tabla.

Utilizando el Tiempo Unix

Para poder mejorar el rendimiento utilizando el atributo unix, lo primero que tenemos que hacer es crear un índice sobre esta columna:

CREATE INDEX unix_index ON eurusd (unix);

Y a continuación veamos cómo podemos consultar el máximo y el mínimo en barras de 8 minutos utilizando este nuevo campo:

SELECT MAX(high) AS High, MIN(low) as Low, date as Date
FROM eurusd
WHERE date > '2010-01-01' AND date < '2011-01-01'
GROUP BY round(unix / (8 * 60));

Y de igual manera se podrían consultar los precios de apertura y de cierre.

Consulta Final

En este momento ya tenemos todo lo que necesitamos para crear barras de cualquier longitud, para cualquier periodo de tiempo, y de una manera eficiente. La consulta final para barras de 8 minutos (8*60=480) sería:

SELECT STRFTIME('%Y-%m-%d %H %M', MIN(date)) AS Date,
    (SELECT open FROM eurusd e2
         WHERE e2.unix >= e1.unix / 480 * 480
         ORDER BY e2.unix ASC LIMIT 1) AS Open,
    MAX(high) as High,
    MIN(low) as Low,
    (SELECT close FROM eurusd e3
         WHERE e3.unix < (e1.unix / 480 + 1) * 480
         ORDER BY e3.unix DESC LIMIT 1) AS Close
FROM eurusd e1
WHERE date > '2010-01-01' AND date < '2011-01-01'
GROUP BY e1.unix / 480;

Otras optimizaciones

Estas consultas se pueden optimizar aun más, pero para ello habría que entrar a programar directamente en el API C de SQLite, un API que nos permite extender la funcionalidad del lenguaje SQL. SQLite dispone de las funciones agregadas MAX y MIN que nos permiten calcular el máximo y el mínimo alcanzado en una barra, pero no dispone de nada equivalente para calcular los precios de apertura y cierre de dicha barra. Es por ello que tenemos que realizar complejas sub-queries que nos retrasan mucho todo el proceso. Este problema se podría solucionar creando nuestras propias funciones agregadas OPEN y CLOSE utilizando el mencionado API de SQLite. Pero esto es un tema demasiado complejo, y que a menos que los lectores demuestren interés, no lo cubriré en este blog.