viernes, 22 de febrero de 2013

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


El entorno R es extremadamente rápido analizando datos siempre y cuando estos quepan en la memoria de nuestro ordenador, pero si esto no es así, el rendimiento de R se puede degradar hasta niveles inaceptables. Existen múltiples soluciones a este problema (que en algún momento analizaremos en este blog), pero para el caso del análisis de datos Forex la que a mi particularmente más me convence es utilizar una base de datos externa, como por ejemplo SQLite, en la que almacenamos la totalidad de los datos, y a continuación, desde R, los vamos consultando según los vayamos necesitando para nuestro análisis.

Iniciamos aquí una serie de entregas en la que vamos a aprender cómo se pueden analizar grandes volúmenes de datos desde R con la ayuda de SQLite. Esto nos será de gran ayuda a la hora de analizar y optimizar estrategias de trading.

SQLite es un sistema gestor de bases de datos relacionales muy popular y ampliamente utilizado (de hecho, Bloomberg es uno de sus patrocinadores). SQLite es una librería que se distribuye de manera gratuita, y cuyo código fuente está disponible para su integración en otros programas (y que evidentemente, está integrada en la plataforma Entropycs). SQLite no necesita de ningún tipo de configuración o de mantenimiento, y actualmente está siendo utilizada para gestionar bases de datos de varios gigabytes (suficiente para trabajar con barras de 1 minuto, aunque quizás se quede algo corta para trabajar con datos tick a tick).

Creando una Tabla de Datos

Lo primero que vamos a hacer es crear una tabla que permita almacenar los datos históricos, en barras de un minuto, para el símbolo EURUSD. Esta tabla almacena la fecha y hora de cada barra en formato texto (campo date), y los valores que se han dado en esa barra (apertura, máximo, mínimo y cierre) como números con decimales. También contiene el capo unix, que es la misma fecha que contiene el campo date, pero en formato tiempo de unix (que cuenta el número de segundos que han transcurrido desde el 1 de Enero de 1970). El campo unix, desde un punto de vista formal, es redundante y debería ser eliminado. Sin embargo, y como veremos más adelante, nos va a venir muy bien para mejorar el rendimiento de nuestras consultas.

Utilizando el editor de comandos de sqlite creamos un fichero de datos para el símbolo EURUSD:

sqlite3 eurusd.db

y a continuación creamos la tabla con:

CREATE TABLE eurusd (
    date TEXT NOT NULL PRIMARY KEY,
    unix INTEGER NOT NULL,
    open REAL NOT NULL,
    high REAL NOT NULL,
    low REAL NOT NULL,
    close REAL NOT NULL
);

Nuevamente, desde un punto de vista formal hubiera sido más correcto crear una única tabla para almacenar los datos de todos los símbolos, pero por cuestiones de rendimiento, hemos optado por crear un único fichero que contiene una única tabla para cada uno de los símbolos.

Importar un fichero de datos

Para los datos históricos vamos a utilizar los datos proporcionados por Forex Tester. Estos datos tienen una calidad más que suficiente para nuestros análisis. De hecho, tienen una calidad mucho mayor que los datos proporcionados por la mayoría de los brokers ;-)

Si abrimos el fichero (una vez descomprimido) vemos que el formato en el que vienen los datos de las barras es el siguiente:

<TICKER>,<DTYYYYMMDD>,<TIME>,<OPEN>,<HIGH>,<LOW>,<CLOSE>,<VOL>
EURUSD,20010102,230100,0.9507,0.9507,0.9507,0.9507,4
EURUSD,20010102,230200,0.9506,0.9506,0.9505,0.9505,4
EURUSD,20010102,230300,0.9505,0.9507,0.9505,0.9506,4
...

Este formato no es el que SQLite espera, por lo que hay que hacer un pre-procesamiento del mismo. Aquí nos encontramos con el problema de que necesitamos un editor de textos que sea lo suficientemente potente como para poder cargar este fichero de datos en memoria, y que sea lo suficientemente versátil para permitir hacer cambios complejos en el mismo. En el mundo Linux tenemos el editor vi que cumple ambas funciones (existe una versión para Windows de este editor de textos llamada Vim). Alternativamente, aquellos que tengan conocimientos de programación pueden escribir un pequeño script en Perl, Python, TCL o similar, que haga la tarea.

Así que editamos el fichero con vi, borramos la primera línea y escribimos el siguiente galimatías:

:1,$s/\w\{6},\(\d\{4}\)\(\d\{2}\)\(\d\{2}\),\(\d\{2}\)\(\d\{2}\)\(\d\{2}\),\(.*\),\d$/\1-\2-\3 \4:\5,0,\7/

Grabamos el resultado como EURUSD.cvs, y comprobamos que el fichero tiene ahora el formato deseado (el indicado por la tabla que hemos creado):

2001-01-02 23:01,0,0.9507,0.9507,0.9507,0.9507
2001-01-02 23:02,0,0.9506,0.9506,0.9505,0.9505
2001-01-02 23:03,0,0.9505,0.9507,0.9505,0.9506

A continuación abrimos SQLite y escribimos:

.mode csv
.import EURUSD.csv eurusd

Esto nos importa la totalidad de los datos de las barras en nuestra tabla. Tan sólo nos quedaría corregir el campo de tiempo en formato unix, y para ello escribimos:

UPDATE eurusd SET unix = CAST(STRFTIME('%s', date) AS INTEGER);

Y con esto ya tendríamos completamente cargados los datos en la base de datos.

2 comentarios:

  1. Para aquellos que trabajen con MetaTrader, se puede seguir un procedimiento similar. Nos vamos al "centro de historiales" y exportamos los datos con granularidad de 1 minuto del símbolo que queramos y en formato CSV (valores separados por comas). El fichero exportado tendrá el siguiente formato:

    1971.01.27,00:00,0.5386,0.5386,0.5386,0.5386,1

    y para convertirlo con el editor vi escribimos:

    :1,$s/\(\d\{4}\)\.\(\d\{2}\)\.\(\d\{2}\),\(\d\{2}:\d\{2}\),\(.*\),\d\{1,3}$/\1-\2-\3 \4,0,\5/

    ResponderEliminar
  2. Me encanta tu blog, con tanta basura por la web esto es un diamante en bruto, das respuesta a muchos de mis problemas y aprendo mucho con tus análisis muchas gracias. Desde ya tienes un nuevo seguidor.
    Un saludo.

    ResponderEliminar