Bases de Datos

En posts anteriores hemos visto herramientas muy potentes para realizar nuestro backtesting utilizando diversas fuentes gratuitas: descargas de Yahoo Finance y exportación de series históricas de Visual Chart. PyAlgoTrade también cuenta con conectores a otros servicios gratuitos como Quandl así como de pago tal que Xignite y Ninja Trader.

Sea Flexible

Sin duda hay una correlación entre calidad y coste en las fuentes de información, pero lo que me interesa ahora es otro vector: la maleabilidad. Trabajar en situaciones reales nos va a requerir frecuentemente juntar, separar, añadir, quitar… en una palabra, transformar los datos y compararlos entre sí para poder encontrar las correlaciones en las que basar la estrategia de nuestra operativa de mercado. Así como las factorías necesitan naves industriales para almacenar sus materias primas y productos intermedios, nosotros precisamos de un almacén para nuestros datos (data warehouse).

Hasta la fecha hemos utilizado sencillos archivos de texto separados por comas (CSV). Si bien no hay nada inherentemente malo en ello, la situación se complica enormemente conforme nuestro almacén crece hasta millones de datos sobre miles de compañías a lo largo de décadas y geografías. Perderemos maleabilidad y nuestros resultados se resentirán. Para manejar estas situaciones tendremos que utilizar una base de datos.

La primera ventaja que nos ofrece el uso de un almacén de datos es la capacidad de combinar diferentes orígenes: no nos importa si el dato proviene de Yahoo, de Factset, de Bloomberg, de Twitter o de otra fuente relevante. Al cargarlo dentro de nuestra base de datos se incorporará a nuestro análisis con un formato unificado.  Esto es lo que se conoce en la industria del business intelligence como una rutina ETL (Extract, Transform , Load) si quiere investigar un poco más sobre esa parte.

Obviamente es posible mantener ambos entornos estrictamente separados: realizar las transformaciones dentro una base de datos, exportar a CSV, y posteriormente cargar esos archivos de texto dentro del entorno de backtesting que ya tenemos creado. Pero además de que terminamos con algo bastante ineficiente, más lento y complejo de mantener, lo peor es que carecemos de retroalimentación: en su momento tal vez queremos que los resultados de una ronda de backtests sean los que guíen la siguiente fase de exploración. De nuevo, perdemos maleabilidad.

Warehouse 06-08-07 (26)

Instalación

A efectos de esta demostración voy a utilizar el popular producto de código abierto MySQL, disponible para todos los sistemas operativos. Puede obtener e instalar gratuitamente la versión Community desde esta dirección. Tenga en cuenta que en el mercado hay un amplio rango de sistemas gestores de bases de datos para todos los gustos, sabores y colores, así que me temo que no puedo ahorrarle el esfuerzo de investigar cuál encaja más en sus necesidades y su bolsillo.

Independientemente del producto que elija dispondrá del lenguaje SQL (Structured Query Language) para interactuar con su base de datos. En un futuro puede que sus necesidades de almacenamiento crezcan hasta el punto en que necesite una base de datos  No-SQL, de lo cual nos ocuparemos en otra entrada, pero no se preocupe demasiado: con las capacidades de almacenamiento y procesado de un ordenador moderno debe amasar varios miles de millones de datos antes de encontrarse en esas lides.

Una vez haya terminado con la instalación de MySQL Community Edition también necesitará la correspondiente librería de Python de la sencilla forma a la que pip nos tiene ya habituados.

C:\> pip install mysql

MySQL puede administrarse desde la línea de comandos o mediante el interfaz gráfico MySQLWorkbench incluído en su descarga. Aprender a trabajar con MySQL rebasa los límites de este humilde artículo: a menos que ya lo haya manejado antes le recomiendo que busque un tutorial en la red para familiarizarse con su uso.

Esquema

El esquema de la base datos, es decir, cómo desea estructurar su información, es una decisión muy personal y dependiente de sus necesidades de análisis. Aquí he optado por una convención bastante simple y neutra que puede adaptarse a muchas situaciones: una tabla Dato con los siguientes campos:

  • ID: un identificador secuencial para facilitar las búsquedas, único para cada dato.
  • Activo: el identificador de la empresa. En mi caso utilizaré el código ISIN pero puede usar otras nomenclaturas, como el nombre de la empresa o el ticker.
  • Fecha: a qué día se refiere este dato. En caso de que quiera realizar trabajar con información intradía sólo tiene que reformatear este campo a fecha y hora ya que PyAlgoTrade proporciona soporte interno para dichos datos.
  • Criterio: a qué concepto se refiere este dato, por ejemplo: el precio de apertura de la jornada (OPEN), de cierre (CLOSE), etc. Aquí hay una decisión de arquitectura importante que conviene clarificar: una opción diferente hubiese sido utilizar campos separados para cada uno de los conceptos. Así en lugar de un campo “criterio” tendríamos, por ejemplo, seis: “Open”, “High”, “Low”, “Close”, “Volume” y “AdjClose”. No hay nada erróneo en hacerlo de esta forma. Ahora bien, si quiero añadir un nuevo concepto en el futuro me veo obligado a modificar sobre la marcha la estructura de mi base de datos, una operación complicada y potencialmente peligrosa, mientras que nuestra organización ya se encuentra preparada para esa contingencia. Veremos que eso nos resultará de gran utilidad.
  • Dato: finalmente, el dato para esta empresa en esta fecha para este criterio.

A fin de mantener la integridad de la base de datos también nos interesa crear dos índices complementarios para facilitar nuestro trabajo:

  • Unico: este índice asegura que cada combinación de activo, criterio y fecha es única, es decir, nos ayuda a evitar duplicados.
  • Sesion: ya que la mayoría de consultas que realicemos serán sobre series temporales, esté indice sobre las fechas nos permitirá trabajar con mucha más rapidez.

Expresado en la jerga de MySQL:

CREATE TABLE IF NOT EXISTS dato ( id INT UNSIGNED NOT NULL AUTO_INCREMENT, activo CHAR(15) NOT NULL, criterio CHAR(50) NOT NULL, fecha DATE NOT NULL, valor DECIMAL(25,10) NOT NULL, PRIMARY KEY (id), UNIQUE INDEX unico (activo, criterio, fecha), INDEX sesion (fecha) ) ENGINE = InnoDB DEFAULT CHARSET=utf8;

Descargue desde aquí un archivo SQL con 1000 datos de mercado como ejemplo para realizar sus propias pruebas. Lo puede importar a través de MySQLWorkbench  y le creará automáticamente una base de datos “almacen” con todo el esquema que hemos mencionado arriba.

Screen Shot 2016-07-21 at 6.51.51 AM
Importando a través de MySQLWorkbench

Integración

PyAlgoTrade dispone en barfeed\dbfeed.py de un ejemplo en SQLite que podemos adaptar a nuestras necesidades.

En primer lugar crearemos una clase (Database) para manejar nuestra interacción con la base de datos. En ella los métodos más importantes serán:

  • start: para iniciar la conexión con la base de datos
  • getBars: para obtener toda la serie histórica de datos de un activo en concreto
  • stop: para cerrar la conexión con la base de datos

Una vez la complejidad de interactuar con la base de datos quede contenida en dicha clase, crear el Feed (DbMemFeed) que va a alimentar nuestra base de datos será tan sencillo como heredar de la clase membf.BarFeed que proporciona PyAlgoTrade y especificar como tenemos que cargar las barras secuencialmente para todos los activos que contemplemos mediante loadBars.

def loadBars(self, instrument, timezone=None, fromDateTime=None, toDateTime=None):
    self.__db.start()
    bars = self.__db.getBars(instrument, self.getFrequency(), timezone, fromDateTime, toDateTime)
    self.addBarsFromSequence(instrument, bars)
    self.__db.stop()

Fíjese que podemos especificar una fecha de inicio y fin a nuestro análisis, para segmentar nuestra base de datos, o bien tomar toda la serie temporal.

Pondremos nuestro código en una librería dbfeed.py y lo incluiremos dentro de la carpeta pyalgoext que ya hemos utilizado en nuestras entradas anteriores a fin de poder reutilizarlo en múltiples análisis. Tiene el código completo en este archivo.

Finalmente implementaremos la estrategia sobre la cual queremos realizar un backtest. En este caso solamente nos aseguraremos de que somos capaces de acceder a los datos. lo cual va a precisar que proporcionemos:

  • Los datos de configuración de la conexión con MySQL, principalmente una dirección de servidor (localhost, la máquina local), un nombre de usuario (root por defecto), una contraseña (vacía por defecto) y una base de datos (almacen en nuestro caso).
  • La lista de activos sobre los que queremos realizar el análisis.
Screen Shot 2016-07-21 at 7.50.55 AM
Serie de precios en pantalla

En este archivo puede descargarse el modelo de estrategia y adaptarla a sus necesidades. Si todo ha funcionado bien, cuando lo ejecute podrá ver en pantalla la serie temporal de precios para los instrumentos solicitados conforme pasan por su motor de backtesting. ¡Felicidades!

Siguientes Pasos

En esta entrada nos hemos ocupado de los entresijos necesarios para poner en marcha su almacén de datos, pero apenas nos hemos dedicado a explotar las nuevas capacidades. Para visualizar más allá de la punta del iceberg sin perecer en las profundidades hemos de aprender a bucear paulatinamente mediante inmersiones progresivas.

Por ejemplo, sólo hemos utilizado el precio de cierre de sesión (llamado “PRICE” en nuestro ejemplo) pero nada nos impide utilizar los precios de apertura, cenit y nadir así como el volumen: de hecho el objeto bar.BasicBar que instanciamos en nuestras series ya se encuentra listo para contener esos valores con lo cual estamos efectivamente desaprovechando capacidad. ¿Se atreve a practicar expandiendo el ejemplo de arriba en esa dirección? ¡Adelante!

De manera más genérica hemos comentado que nuestro esquema está diseñado para dar cabida no sólo a esos datos de precio, sino a cualquier concepto. ¿Qué otros conceptos podemos utilizar más allá del precio? Me temo que responder eso es menester de la próxima entrada, pero ya que le dejos con las dudas, también le adelanto con una sonrisa de complicidad, de que se trata de una pregunta fundamental.

Anuncios

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