Datos en Tiempo Real y Arquitectura SSE
📡 Datos en Tiempo Real y Arquitectura SSE
Sección titulada «📡 Datos en Tiempo Real y Arquitectura SSE»Transmitir cotizaciones en tiempo real directamente al navegador plantea retos técnicos importantes:
- Conectar el navegador directamente a múltiples WebSockets externos agota recursos de red, provoca problemas de CORS y expone las tenencias del usuario ante terceros.
- Hacer peticiones periódicas por sondeo (polling) sobre APIs REST satura los límites de tasa de los exchanges (
429 Too Many Requests).
Para resolver esto de forma limpia y eficiente, Criptofolio utiliza una arquitectura centralizada basada en Server-Sent Events (SSE) orquestada por el backend en Hono.
🏛️ Diagrama de la Arquitectura
Sección titulada «🏛️ Diagrama de la Arquitectura»flowchart TD
subgraph Frontend ["Frontend en Vue 3"]
UI["Componentes Visuales (Precio y Valoración en Vivo)"]
BffAdapter["BffMarketDataAdapter (EventSource)"]
end
subgraph Backend ["Servidor Backend Hono"]
SSEEndpoint["GET /api/market/stream (SSE)"]
Orchestrator["MarketDataOrchestrator"]
PriceHistory["IPriceHistoryPort (Caché y Parquet)"]
Provider1["Adaptador Kraken WS (Activo)"]
Provider2["Adaptador Binance WS (En espera)"]
end
subgraph Exchanges ["Exchanges Externos"]
KrakenWS["Kraken WebSocket API v2"]
BinanceWS["Binance WebSocket Stream"]
end
UI --> BffAdapter
BffAdapter -->|Conexión única EventSource| SSEEndpoint
SSEEndpoint --> Orchestrator
Orchestrator -->|Intercambio en caliente| Provider1
Orchestrator -.->|Desactivado| Provider2
KrakenWS ==>|Ticks en vivo| Provider1
Provider1 --> Orchestrator
Orchestrator -->|1. Volcado en Caché e Histórico| PriceHistory
Orchestrator -->|2. Difusión a Clientes| SSEEndpoint
⚡ Innovaciones Arquitectónicas
Sección titulada «⚡ Innovaciones Arquitectónicas»1. El Paradigma de Canal Único
Sección titulada «1. El Paradigma de Canal Único»El navegador abre exactamente una única conexión HTTP persistente mediante la API estándar de HTML5 EventSource hacia /api/market/stream. Todos los activos de la cartera (BTC/EUR, ETH/EUR, SOL/USD) viajan multiplexados por ese mismo canal.
2. Intercambio de Proveedores en Caliente (Hot-Swapping)
Sección titulada «2. Intercambio de Proveedores en Caliente (Hot-Swapping)»El usuario puede cambiar su proveedor preferido en los ajustes de la Bóveda (por ejemplo, pasar de Kraken a Binance o CoinGecko):
- El
MarketDataOrchestratordel backend cierra de forma ordenada la sesión activa de WebSocket con Kraken. - Inicia la conexión con el nuevo proveedor seleccionado.
- Comienza a inyectar las nuevas cotizaciones por el mismo canal SSE que ya estaba abierto.
- El frontend no necesita reconectarse ni recargar la interfaz, asegurando una experiencia continua.
3. Sincronización entre REST y Series Históricas
Sección titulada «3. Sincronización entre REST y Series Históricas»Cada tick de precio emitido por el canal SSE se guarda de forma concurrente en IPriceHistoryPort:
- Garantiza que las llamadas REST estándar (
GET /api/metrics/kpis) calculen el patrimonio usando exactamente el mismo precio que se está mostrando en los tickers en vivo. - Escribe las muestras de precios en archivos Apache Parquet en disco para alimentar los análisis históricos de largo plazo.
📦 Consumo desde Vue 3 (useMarketStream)
Sección titulada «📦 Consumo desde Vue 3 (useMarketStream)»Los componentes visuales acceden al flujo de cotizaciones mediante un composable:
import { useMarketStream } from '@/composables/queries/useMarketStream';
export function useLivePortfolio() { const { isConnected, latestTicks } = useMarketStream();
const btcPrice = computed(() => latestTicks.value['BTC/EUR']?.price);
return { isConnected, btcPrice };}