DuckDB OLAP y Window Functions Vectorizadas
🦆 DuckDB OLAP y Window Functions Vectorizadas
Sección titulada «🦆 DuckDB OLAP y Window Functions Vectorizadas»Criptofolio delega las cargas de trabajo de cálculo intensivo —cruce de lotes fiscales FIFO, rentabilidades ponderadas por tiempo y métricas de riesgo institucional— en una instancia local de DuckDB (fiscal.duckdb).
DuckDB funciona como un motor OLAP columnar en proceso que aprovecha instrucciones vectorizadas SIMD de la CPU, permitiendo resolver consultas multianuales sobre cientos de miles de registros en pocos milisegundos.
📊 Arquitectura de las Vistas Analíticas Principales
Sección titulada «📊 Arquitectura de las Vistas Analíticas Principales»El motor estructura el cálculo de la cartera en cuatro vistas SQL fundamentales:
flowchart TD
Ledger["ledger.spot_transactions (SQLite)"] --> Balances["v_daily_running_balances"]
Prices["historical_prices (*.parquet)"] --> Balances
Balances --> Val["v_portfolio_daily_valuation\n(Materializada en m_portfolio_daily_valuation)"]
Val --> Vol["v_portfolio_returns_volatility\n(Volatilidad anualizada a 30 días)"]
Val --> Drawdown["v_portfolio_ath_drawdown\n(ATH móvil y curva de Drawdown)"]
Vol --> AlphaBeta["v_portfolio_alpha_beta\n(Covarianza frente a Bitcoin)"]
🔬 Fórmulas Matemáticas y Definición de Vistas
Sección titulada «🔬 Fórmulas Matemáticas y Definición de Vistas»1. Valoración Diaria de la Cartera (v_portfolio_daily_valuation)
Sección titulada «1. Valoración Diaria de la Cartera (v_portfolio_daily_valuation)»Calcula los saldos acumulados de cada activo y proyecta los precios históricos mediante joins ASOF:
SELECT b.date, b.asset_id, b.cumulative_qty, p.price_eur, (b.cumulative_qty * p.price_eur) AS valuation_eurFROM v_daily_running_balances bASOF JOIN historical_prices p ON b.asset_id = p.asset_id AND b.date >= p.price_timestamp;2. Volatilidad Anualizada a 30 Días (v_portfolio_returns_volatility)
Sección titulada «2. Volatilidad Anualizada a 30 Días (v_portfolio_returns_volatility)»Calcula los retornos logarítmicos diarios de la cartera y aplica la escala anualizada habitual en finanzas institucionales:
$$\text{Retorno Diario}t = \frac{\text{Valor}t - \text{Valor}{t-1}}{\text{Valor}{t-1}}$$
$$\text{Volatilidad}{30d} = \sigma(\text{Retornos Diarios}{t-29 \dots t}) \times \sqrt{365}$$
En SQL de DuckDB, se calcula mediante una ventana móvil:
stddev(daily_return) OVER ( ORDER BY date ROWS BETWEEN 29 PRECEDING AND CURRENT ROW) * sqrt(365) AS annualized_volatility_30d3. ATH Móvil y Caída Porcentual (Drawdown) (v_portfolio_ath_drawdown)
Sección titulada «3. ATH Móvil y Caída Porcentual (Drawdown) (v_portfolio_ath_drawdown)»Rastrea el máximo histórico (All-Time-High) de valoración y computa la curva de caída porcentual:
$$\text{ATH Móvil}_t = \max(\text{Valoración}_0 \dots \text{Valoración}_t)$$
$$\text{Drawdown}_{%} = \frac{\text{Valoración}_t - \text{ATH Móvil}_t}{\text{ATH Móvil}_t}$$
4. Alpha ($\alpha$) y Beta ($\beta$) de Riesgo (v_portfolio_alpha_beta)
Sección titulada «4. Alpha ($\alpha$) y Beta ($\beta$) de Riesgo (v_portfolio_alpha_beta)»Mide la sensibilidad y el rendimiento excedente de la cartera frente al índice de referencia del mercado (Bitcoin):
$$\beta = \frac{\text{Cov}(R_{\text{cartera}}, R_{\text{btc}})}{\text{Var}(R_{\text{btc}})}$$
$$\alpha = \bar{R}{\text{cartera}} - \beta \cdot \bar{R}{\text{btc}}$$
🧵 Pool de Conexiones de DuckDB
Sección titulada «🧵 Pool de Conexiones de DuckDB»El adaptador nativo de DuckDB para Node.js proporciona un rendimiento sobresaliente, pero requiere una gestión cuidadosa de la concurrencia.
Criptofolio encapsula el motor en un pool interno (DUCKDB_POOL_SIZE, por defecto 4):
- Múltiples peticiones HTTP concurrentes de lectura toman descriptores de conexión sobre una única instancia de
DuckDBInstance. - Las consultas analíticas se ejecutan en paralelo en hilos nativos sin bloquear el archivo de base de datos SQLite.