Desarrollo & IA

Cómo Crear un Gestor de Portafolios de Inversión Privado y Autoalojado

5 de enero de 2026
8 min

finanze es un gestor de portafolios privado y autoalojado que centraliza datos financieros de múltiples bancos y plataformas de inversión en una sola ...

Javier Santos

Especialista en IA & Machine Learning

finanze: Arquitectura y retos de un gestor de portafolios privado y autoalojado

En los últimos años, la gestión de activos financieros se ha vuelto cada vez más compleja. Muchos de nosotros tenemos cuentas y productos dispersos entre bancos tradicionales, brokers, plataformas de crowdfunding, wallets de criptomonedas, y más. Las soluciones existentes suelen ser SaaS de terceros, con poca flexibilidad, problemas de privacidad y escasa personalización.

Esta necesidad fue el punto de partida de finanze, un gestor de portafolios privado, autoalojado y extensible, que centraliza tus datos financieros en una única interfaz segura, acercando la visión global y el control total sobre tus activos. En este post, repaso las decisiones arquitectónicas, los principales retos técnicos y aprendizajes clave tras su desarrollo.


¿Por qué crear finanze?

La motivación fue doble:

  1. Centralización y visibilidad: Los dashboards bancarios y de inversión suelen ser verticales y limitados a sus propios productos. La visión global de patrimonio requiere extraer, transformar y agrupar datos dispersos en múltiples fuentes.
  2. Privacidad y control: No quería depender de servicios externos que almacenan mis datos financieros sensibles en la nube. Buscaba una solución autoalojada y cifrada localmente.

Además, necesitaba soportar activos poco convencionales (crowdfunding inmobiliario, cripto, commodities), multi-moneda, y una API flexible para importar/exportar datos.


Arquitectura: Decisiones y enfoque

Stack tecnológico

El stack elegido tenía que ser:

  • Full-stack TypeScript: para robustez tipada de frontend a backend
  • Python: para módulos de integración y scraping financiero, gracias a su ecosistema de librerías (Requests, BeautifulSoup, Pandas)
  • Docker: para facilitar el despliegue autoalojado y la portabilidad
  • CSS/HTML/JS: para una interfaz web moderna y responsiva
  • Shell scripting: para tareas de automatización y backups

Repositorio: github.com/ESJavadex/finanze

Arquitectura general

La arquitectura sigue una aproximación modular y desacoplada. Los principales componentes son:

  1. Frontend SPA (Single Page Application)

- Desarrollado en TypeScript con React y Vite.

- Proporciona la interfaz de usuario para visualizar dashboards, KPIs, activos, movimientos y simulaciones.

- Gestiona autenticación local y mantiene la sesión cifrada en el navegador.

  1. API backend

- Node.js + TypeScript, expuesto como servidor Express.

- Expone endpoints RESTful para operaciones CRUD sobre activos, movimientos y entidades financieras.

- Interactúa con la base de datos local cifrada.

  1. Motor de integración financiera (Python)

- Módulos independientes para scraping, fetching de APIs y normalización de datos desde bancos, brokers, exchanges y otras fuentes.

- Se ejecutan como scripts programados (cron/pm2) y comunican los datos al backend vía API interna o archivos temporales.

  1. Base de datos cifrada local (SQLite + SQLCipher)

- Almacenamiento seguro de todas las transacciones, configuraciones y credenciales de integraciones.

- Solo accesible localmente, con clave maestra para descifrado.

  1. Infraestructura y despliegue (Docker)

- Imagen única que orquesta frontend, backend y servicios auxiliares.

- Volúmenes persistentes para la base de datos y configuraciones.

Diagrama de alto nivel

code
1+-----------+ +-------------+ +------------------+ +---------------------+
2| Frontend |<---->| Backend |<---->| DB cifrada | | Integradores Python |
3| (React) | | (Node/TS) | | (SQLite+SQLCipher)|<--->| (APIs, Scraping) |
4+-----------+ +-------------+ +------------------+ +---------------------+
5 ^ ^ ^ ^
6 | | | |
7 Usuario REST API/WS Acceso SQL Cron jobs/scripts


Componentes clave y decisiones técnicas

1. Multi-fuente y multi-activo: Normalización flexible

Los datos financieros provienen en formatos y estructuras radicalmente distintos. Para abstraer fuentes heterogéneas (APIs bancarias, CSV de brokers, web scraping, etc.), diseñé un schema intermedio con estos principios:

  • Entidades financieras (bancos, brokers, exchanges)
  • Cuentas y productos: acciones, fondos, cuentas, cripto, inmuebles, préstamos, etc.
  • Movimientos/Transacciones: ingresos, gastos, aportaciones, dividendos, compras/ventas
  • Atributos flexibles: custom fields para soportar activos no convencionales

Esto permitió diseñar integradores independientes en Python que mapean cualquier fuente al modelo común antes de persistir en la base de datos.

Ejemplo de parser para movimientos bancarios:

python
1def parse_bank_statement(csv_file):
2 df = pd.read_csv(csv_file)
3 transactions = []
4 for _, row in df.iterrows():
5 tx = {
6 "date": row['Fecha'],
7 "amount": float(row['Importe']),
8 "currency": row['Moneda'],
9 "entity": "MiBanco",
10 "type": "income" if row['Importe'] > 0 else "expense",
11 "description": row['Concepto'],
12 }
13 transactions.append(tx)
14 return transactions
Este script convierte un extracto bancario en el formato universal de finanze.


2. Seguridad y privacidad: cifrado local, no cloud

Uno de los mayores retos fue asegurar la privacidad total:

  • Base de datos cifrada (SQLCipher): Todos los datos se almacenan cifrados en disco, y sólo se descifran en memoria durante la sesión autenticada.
  • Sin llamadas a servidores externos: Salvo integraciones explícitas (ej: APIs de cotizaciones), el sistema nunca envía datos fuera de la máquina local.
  • Autenticación local fuerte: Login protegido por contraseña (hash+salt), con posibilidad de añadir 2FA.

Configuración de SQLCipher en Node.js:

typescript
1import sqlite3 from 'sqlite3';
2const db = new sqlite3.Database('finanze.db');
3db.run("PRAGMA key = 'mi_clave_secreta_robusta';");


3. Multi-moneda y tipos de cambio automáticos

Muchos activos están denominados en divisas distintas (EUR, USD, BTC, etc.). Para mantener el dashboard coherente:

  • Se integró una capa de conversión automática usando APIs públicas (ECB, CoinGecko).
  • Se almacenan los valores originales y el histórico de tipos de cambio para simulaciones y reporting.

Ejemplo de fetch de tipo de cambio:

typescript
1async function getExchangeRate(from: string, to: string): Promise<number> {
2 const res = await fetch(`https://api.exchangerate.host/latest?base=${from}&symbols=${to}`);
3 const data = await res.json();
4 return data.rates[to];
5}


4. Exportación dinámica a Google Sheets y plantillas

La exportación a hojas de cálculo era clave para reporting avanzado o trabajar con asesores. Implementé:

  • Plantillas personalizables para definir el formato y contenido de las exportaciones.
  • Integración con la API de Google Sheets usando OAuth2 local, sin exponer credenciales.
  • Exportación manual y programada.


Retos técnicos y cómo los resolví

1. Integración heterogénea y scraping

Cada banco/broker tiene formatos distintos, APIs poco documentadas o requerimientos de scraping. Para evitar que cambios en las webs rompieran el sistema:

  • Separé cada integrador como un módulo Python independiente: así, actualizar uno no afecta al resto.
  • Uso de parsers robustos (regex, heurísticas) y fallback manual (importación desde CSV/Excel).
  • Tests automáticos por entidad/activo para detectar cambios en los formatos.

2. Escalabilidad y rendimiento local

A pesar de ejecutarse en máquina personal (Raspberry Pi, miniPC…), había que optimizar:

  • Cargas diferidas y paginación en frontend para grandes volúmenes de movimientos.
  • Uso de índices en la base de datos para búsquedas rápidas.
  • Sincronización incremental para integraciones (fetch sólo de movimientos nuevos).

3. UX: Flexibilidad sin abrumar

Un dashboard financiero puede volverse complejo rápidamente. Para mantener una buena experiencia:

  • UI modular, con widgets customizables y dashboards por tipo de activo.
  • Wizards y formularios guiados para importar datos y configurar entidades.


Resultados: Impacto y métricas

Desde su despliegue personal y en pruebas con otros usuarios:

  • Más de 15 entidades financieras soportadas, entre bancos, brokers tradicionales y cripto.
  • >30 tipos de activos: desde acciones y fondos hasta préstamos p2p, inmuebles y commodities.
  • Más de 100.000 movimientos procesados en total, con tiempos de carga <1s.
  • Cero incidentes de pérdida o fuga de datos gracias al cifrado local.

Las funcionalidades más usadas han sido el dashboard consolidado, la simulación de escenarios (ahorro/jubilación) y la exportación flexible.


Aprendizajes y mejoras futuras

Lo que funcionó bien:

  • El enfoque modular (integradores Python + backend TypeScript) facilita añadir nuevas fuentes o activos.
  • El cifrado local y la autoalojabilidad han dado tranquilidad y control total a los usuarios.
  • La capa de normalización ha simplificado mucho la agregación de datos heterogéneos.

Posibles mejoras:

  • Mejorar la integración de APIs bancarias abiertas (PSD2/OpenBanking) para reducir el scraping.
  • UI más personalizable y soporte para notificaciones/alertas automáticas.
  • Mobile-friendly: adaptar la SPA a dispositivos móviles.
  • Plugins/extensiones de terceros para permitir a la comunidad añadir nuevas integraciones.


Conclusión

finanze nació de una necesidad muy real: tener control sobre el patrimonio global sin sacrificar privacidad ni flexibilidad. El viaje de diseño y desarrollo ha sido una oportunidad para aplicar conceptos de arquitectura modular, seguridad y automatización, y el resultado es una herramienta potente y extensible que demuestra el valor de unir Python, TypeScript y buenas prácticas de software.

¿Te interesa contribuir o probarlo?

👉 Repositorio en GitHub

¡Siempre abierto a feedback, ideas y colaboraciones! 🚀