Quant500 Academy

3. De un CSV a una base de datos: cuándo hace falta y cuándo es postureo

Nivel 5: Guardar, actualizar y escalar

Hay un momento en todo proyecto en que alguien dice que esto ya pide una base de datos de verdad. A veces tiene razón. Muchas más veces está describiendo un problema que no tiene, y el precio de montarla se paga en horas de mantenimiento que salen del presupuesto de investigar estrategias. Este módulo es el criterio para decidirlo sin quedar mal en ninguna de las dos direcciones.

Qué hace una base de datos que los ficheros no hacen

Una base de datos no es un sitio donde guardar tablas; los ficheros ya son eso. Lo que aporta es un conjunto de garantías que en ficheros tendrías que programar tú:

Las señales reales de que los ficheros ya no bastan

Ninguna de estas señales es el tamaño del dato, y ese es el malentendido más caro:

Ahora el reverso. Si eres un usuario, con datos diarios de unos miles de valores, un proceso que se ejecuta una vez al día y un almacén de decenas de megabytes, no tienes ninguna de esas señales. Tienes ficheros bien organizados, y eso es una arquitectura correcta, no una fase provisional.

SQL sin base de datos: el punto medio que casi nadie usa

El argumento que más se oye a favor de la base de datos es que SQL es más expresivo que encadenar operaciones de pandas. Es verdad, y no implica lo que la gente cree que implica, porque existen motores analíticos embebidos que ejecutan SQL directamente sobre tus ficheros columnares, sin servidor, sin usuarios y sin proceso que mantener.

import duckdb

con = duckdb.connect()   # en memoria: no hay servidor ni fichero de base de datos

top = con.execute("""
    SELECT simbolo, avg(volumen) AS vol_medio, count(*) AS sesiones
    FROM read_parquet('almacen/precios/**/*.parquet', hive_partitioning = true)
    WHERE anio BETWEEN 2023 AND 2024 AND volumen > 0
    GROUP BY simbolo
    HAVING count(*) > 400
    ORDER BY vol_medio DESC
    LIMIT 10
""").df()

Fíjate en lo que hace ese SELECT: el filtro sobre anio se empuja hasta la capa de ficheros y solo se abren las carpetas de 2023 y 2024, y de las columnas solo se leen las tres que aparecen en la consulta. Tienes la expresividad de SQL sobre el almacén del módulo uno, sin haber instalado un servidor. Para la inmensa mayoría de proyectos personales, aquí se acaba la conversación.

Series temporales o relacional: qué cambia de verdad

Si de verdad hace falta una base de datos, la siguiente elección tampoco es de moda:

import sqlite3

con = sqlite3.connect("almacen/precios.db")
con.execute("""
    CREATE TABLE IF NOT EXISTS precios (
        simbolo TEXT NOT NULL,
        fecha   TEXT NOT NULL,
        cierre  REAL NOT NULL,
        volumen INTEGER NOT NULL,
        descargado_en TEXT NOT NULL,
        PRIMARY KEY (simbolo, fecha)
    )
""")

# La clausula ON CONFLICT necesita que exista esa clave o un indice unico:
# sin la PRIMARY KEY de arriba, esta sentencia no se ejecuta, falla
con.executemany("""
    INSERT INTO precios (simbolo, fecha, cierre, volumen, descargado_en)
    VALUES (?, ?, ?, ?, ?)
    ON CONFLICT(simbolo, fecha) DO UPDATE SET
        cierre = excluded.cierre,
        volumen = excluded.volumen,
        descargado_en = excluded.descargado_en
""", filas)
con.commit()

Caso: el proyecto que se montó un servidor para nada

Un caso típico y perfectamente reconocible. Un solo usuario, 500 valores, datos diarios, veinticinco años: 3,1 millones de filas, decenas de megabytes en columnar. El proceso se lanza una vez al día y tarda un par de minutos. Montar un servidor de base de datos ahí añade un servicio que hay que arrancar, actualizar, respaldar y vigilar, y una capa de conexión que puede caerse a las tres de la mañana.

¿Qué se gana a cambio? Con un solo escritor, ninguna garantía de concurrencia que te haga falta. Con consultas conocidas y lanzadas desde tu propio guion, ningún planificador que te salve. Con un solo usuario, ningún control de acceso.

El criterio honesto es este: la mayoría de los proyectos personales nunca necesitan más que ficheros bien organizados más un motor SQL embebido cuando llega una consulta rara. El día que aparezcan dos escritores, una segunda persona o un requisito de integridad, migras, y para entonces sabrás exactamente qué tabla y qué restricciones necesitas. Migrar tarde cuesta un rato; migrar pronto cuesta todo el proyecto.

El resto de Quant500

Lo que estás aprendiendo, aplicado al índice todos los días:

La cartera del modelo, cada semana en tu correo

Cada sábado, su semana en un minuto: cómo fue, lo mejor y lo peor, y qué directivos compraron con su dinero. Y el día que el modelo se rehace, qué entra y qué sale. Es una simulación, no un consejo. Como mucho un correo a la semana, sin publicidad y sin cuenta; te das de baja con un clic. Lo hace una persona: Pol Gracia.

Cartera modelo con resultados simulados, no una recomendación personalizada. Tu correo se usa solo para esto: privacidad.

Detrás de la Academia y del resto de Quant500 hay una sola persona: Pol Gracia Serrahima.