← Volver a los artículos
May 25, 2026
5 min de lectura

Dentro de nuestro algoritmo propio: HRP + Long/Short + CVaR con Hull-White

Dentro de nuestro algoritmo propio: HRP + Long/Short + CVaR con Hull-White
#portfolio optimization
#HRP
#hierarchical risk parity
#CVaR
#Hull-White
#EWMA
#long/short
#risk management
#Rust
#quantitative finance
📊
Part 3 of 5 · Collection
Portfolio Construction & Risk

📄 Este artículo se convirtió en un paper de investigación. La asignación HRP en el corazón de este pipeline se somete a una prueba controlada frente a Markowitz, el shrinkage de Ledoit-Wolf y 1/N bajo covarianza conocida (4.800 experimentos). Lee el paper en línea (versión interactiva + PDF) en hrp.marketmaker.cc, código y datos en github.com/suenot/hrp-validation.

En nuestro resumen «12 algoritmos de optimización de carteras, comparados» enfrentamos una docena de métodos de asignación uno junto al otro. Once de ellos son clásicos de manual. El duodécimo, Pipeline, es el nuestro — y recibió exactamente un punto en esa entrada. Este artículo es la inmersión profunda: qué hay dentro, de dónde viene cada fórmula y cómo la especificación se convierte en Rust.

Pipeline no inventa una nueva forma de calcular pesos. Toma la receta más robusta conocida — Hierarchical Risk Parity (HRP) — y la envuelve con las dos capas que una cuenta de trading en vivo realmente necesita pero que el HRP puro no tiene: dirección (long/short a partir de señales de estrategia) y un presupuesto de riesgo estricto (CVaR ajustado al régimen de volatilidad actual). Eso da cuatro etapas.

Las cuatro etapas

prices  I  log returns  II  HRP weights  III  long/short  IV  CVaR budget\text{prices} \;\xrightarrow{\text{I}}\; \text{log returns} \;\xrightarrow{\text{II}}\; \text{HRP weights} \;\xrightarrow{\text{III}}\; \text{long/short} \;\xrightarrow{\text{IV}}\; \text{CVaR budget}
  • I — retornos logarítmicos de cada activo.
  • II — pesos base a partir de HRP.
  • III — una división long/short a partir de señales de agentes, con las cuotas de riesgo fijadas por confianza.
  • IV — una corrección CVaR con volatilidad Hull-White; el exceso de riesgo va a efectivo.

Recorrámoslas en orden.

Etapa I. Retornos logarítmicos

Todo comienza con el paso de precios a retornos logarítmicos:

ri,t=ln ⁣(Si,tSi,t1)r_{i,t} = \ln\!\left(\frac{S_{i,t}}{S_{i,t-1}}\right)

donde ii es el activo y tt el paso temporal. Los retornos logarítmicos se suman a lo largo del tiempo y son más simétricos que los cambios porcentuales simples — la entrada estándar para cualquier cálculo de covarianza.

Etapa II. HRP como fundamento

HRP, propuesto por Marcos López de Prado en 2016, esquiva la dolencia central de la optimización media-varianza — invertir una matriz de covarianza mal condicionada. Nunca la invierte en absoluto. En su lugar, trabaja con la estructura de las correlaciones.

Covarianza y correlación

A partir de los retornos construimos la matriz de covarianza Σ\Sigma y la normalizamos en la matriz de correlación CC:

Σi,j=Cov(ri,rj),Ci,j=ρi,j=Cov(ri,rj)σiσj\Sigma_{i,j} = \mathrm{Cov}(r_i, r_j), \qquad C_{i,j} = \rho_{i,j} = \frac{\mathrm{Cov}(r_i, r_j)}{\sigma_i \sigma_j}

Matriz de distancias

Convertimos la correlación en una métrica de distancia, de modo que los activos fuertemente correlacionados queden "cerca":

di,j=1ρi,j2d_{i,j} = \sqrt{\frac{1 - \rho_{i,j}}{2}}

Cuanto más cerca esté ρi,j\rho_{i,j} de 1, más cerca está di,jd_{i,j} de 0 — y más probable es que los activos compartan un clúster.

Dendrograma y orden de hojas

A partir de la matriz de distancias construimos una jerarquía de clústeres mediante average linkage y leemos el orden de hojas π=(π1,,πN)\pi = (\pi_1, \ldots, \pi_N) — una permutación de los activos en la que los similares quedan adyacentes.

Paso opcional: el número óptimo de clústeres puede elegirse mediante el coeficiente de silueta si=biaimax(bi,ai)s_i = \dfrac{b_i - a_i}{\max(b_i, a_i)}, donde aia_i es la distancia media dentro de un clúster y bib_i la distancia media al vecino más cercano. El pase base no lo necesita — la bisección recursiva ya respeta la jerarquía.

Cuasi-diagonalización

Permutamos las filas y columnas de Σ\Sigma según π\pi, agrupando los valores grandes a lo largo de la diagonal:

Σi,jq=Σπi,πj\Sigma^{q}_{i,j} = \Sigma_{\pi_i, \pi_j}

Bisección recursiva

Luego la recursión avanza de arriba hacia abajo. En cada paso un clúster se divide en dos mitades LL y RR, y el capital se asigna entre las mitades inversamente proporcional a sus varianzas:

wL=1/σL21σL2+1σR2,wR=1wLw_L = \frac{1/\sigma_L^2}{\dfrac{1}{\sigma_L^2} + \dfrac{1}{\sigma_R^2}}, \qquad w_R = 1 - w_L

La varianza de un clúster se calcula sobre su subbloque de covarianza como σC2=1m2i,jCΣi,jq\sigma_C^2 = \tfrac{1}{m^2}\sum_{i,j \in C}\Sigma^{q}_{i,j}. El descenso continúa hasta que cada nodo contiene un solo activo. Los pesos son solo largos, no negativos, y suman 1,0.

En nuestra implementación, esta es la función hrp_from_cov(cov) -> Vec<f64>: correlación → distancia → average linkage → orden de hojas → cuasi-diagonalización → bisección recursiva. Pipeline la llama como su base — y también es el optimize() público para el caso sin señales.

Etapa III. La capa long/short

El HRP puro es una cartera "solo comprar". Pero una estrategia a menudo indica no solo cuánto sino en qué dirección. La etapa III toma señales por activo (Long/Short) del agente y construye dos subcarteras.

  1. Los activos se dividen en cestas long y short según la señal.
  2. Dentro de cada cesta, los pesos se calculan con el mismo HRP (sobre el subbloque de covarianza de esos activos), sumando 1 por cesta.
  3. Si el agente también emite una confianza pip_i, las cuotas de riesgo entre los lados se fijan por confianza total:

ξL=iLpi,ξS=iSpi,λL=ξLξL+ξS,λS=ξSξL+ξS\xi_L = \sum_{i \in L} p_i, \quad \xi_S = \sum_{i \in S} p_i, \qquad \lambda_L = \frac{\xi_L}{\xi_L + \xi_S}, \quad \lambda_S = \frac{\xi_S}{\xi_L + \xi_S}

Sin confianza, las cuotas caen de vuelta al número de activos en cada cesta. El peso con signo final es wi=λLwiHRPw_i = \lambda_L \cdot w_i^{\text{HRP}} para los largos y wi=λSwiHRPw_i = -\lambda_S \cdot w_i^{\text{HRP}} para los cortos, tras lo cual toda la exposición bruta se normaliza a 1.

Una nota honesta sobre el código. La especificación original lleva factores de corrección αL=λL/σL\alpha_L = \sqrt{\lambda_L}/\sigma_L, αS=λS/σS\alpha_S = \sqrt{\lambda_S}/\sigma_S — pero también los marca con un "¿realmente necesitamos este paso?". La implementación no los aplica: los dos lados se combinan directamente mediante las cuotas de riesgo λ\lambda, lo que mantiene la exposición bruta exactamente en 1 y no crea apalancamiento oculto. Es una simplificación deliberada de la especificación, no un descuido.

Etapa IV. CVaR con un ajuste Hull-White

El HRP equilibra el riesgo estructuralmente, pero no sabe nada sobre el nivel absoluto de riesgo en términos monetarios. La etapa final impone un techo estricto al riesgo de cola — y lo hace sensible a un cambio de régimen de mercado.

Retorno de la cartera y volatilidad EWMA

Primero colapsamos los pesos en un retorno de cartera y estimamos la volatilidad condicional con EWMA:

rp,t=i=1nwiri,t,σp,t2=λσp,t12+(1λ)rp,t12r_{p,t} = \sum_{i=1}^{n} w_i\, r_{i,t}, \qquad \sigma_{p,t}^2 = \lambda\, \sigma_{p,t-1}^2 + (1 - \lambda)\, r_{p,t-1}^2

con λ=0.94\lambda = 0.94 (el valor clásico de RiskMetrics). EWMA da la volatilidad "de hoy" en lugar de una promediada sobre toda la historia.

Reescalado Hull-White

La idea clave: los retornos pasados no pueden tomarse tal cual — ocurrieron bajo una volatilidad diferente. El método Hull-White reescala cada retorno pasado al nivel actual:

r~p,s=σp,t+1σp,srp,s,s=tN+1,,t\widetilde{r}_{p,s} = \frac{\sigma_{p,t+1}}{\sigma_{p,s}}\, r_{p,s}, \qquad s = t - N + 1, \ldots, t

Un mes tranquilo se "estira", uno turbulento se "comprime", y la distribución se lleva al régimen actual.

VaR y CVaR

Sobre la distribución reescalada tomamos el cuantil de pérdida y la pérdida media en la cola:

VaRαHW=q1α(r~p)VaR_\alpha^{HW} = -q_{1-\alpha}(\widetilde{r}_p)

CVaRαHW=E ⁣[r~pr~pq1α(r~p)]CVaR_\alpha^{HW} = -\mathbb{E}\!\left[\widetilde{r}_p \mid \widetilde{r}_p \le q_{1-\alpha}(\widetilde{r}_p)\right]

CVaR (también conocido como Expected Shortfall) no responde "qué tan malo es un día malo típico" sino "qué tan malo es en promedio a través del peor α\alpha por ciento" — así que ve el grosor de la cola, no solo su borde.

Presupuesto de riesgo y efectivo

Si el CVaR supera el umbral aceptable, cada posición de riesgo se reduce con un único factor, y el capital liberado pasa a efectivo:

winew=γwi,γ=CVaRmaxCVaRαHW,wcash=1i=1nwineww_i^{new} = \gamma\, w_i, \quad \gamma = \frac{CVaR_{\max}}{CVaR_\alpha^{HW}}, \qquad w_{cash} = 1 - \sum_{i=1}^{n} |w_i^{new}|

Así, la cartera se desapalanca de riesgo cuando el riesgo de cola crece y vuelve a entrar en el mercado cuando se calma.

De la especificación al código

Todo el algoritmo vive en un único crate de Rust, portfolio-pipeline, y obedece el contrato uniforme del workspace:

pub fn optimize(prices: &[Vec<f64>]) -> Vec<f64>

Esta es la proyección solo-larga (etapas I, II, IV sin señales) — exactamente la misma interfaz prices -> weights que los otros once algoritmos, de modo que Pipeline es un reemplazo directo para cualquiera de ellos. La versión completa con todas las etapas es una función separada:

pub fn run(
    prices: &[Vec<f64>],
    signals: Option<&[Side]>,      // Long / Short per asset
    confidence: Option<&[f64]>,    // agent confidence → risk shares λ
    cfg: &PipelineConfig,          // CVaR / Hull-White parameters
) -> PipelineResult                // signed weights + cash + cvar + σ

Los valores por defecto de la capa: cola cvar_alpha = 0.05, presupuesto cvar_max = 0.05, EWMA ewma_lambda = 0.94, ventana Hull-White hw_window = 0 (toda la historia). La implementación no tiene dependencias externas y es deliberadamente defensiva: en historiales cortos (menos de 4 puntos de precio) devuelve pesos iguales, y la capa CVaR solo se activa a partir de ≥8 observaciones de retorno — de lo contrario no hay nada de donde estimar una cola.

Por qué Rust: una única base de código determinista tanto para backtest como para producción, sin la deriva de "Python en investigación, otra cosa en producción", y lo bastante rápida para ejecutar los doce algoritmos en una sola solicitud a través del backend de comparación.

Lo que cuesta en tiempo

¿Qué tan rápido es "lo bastante rápido"? Extrajimos el núcleo de HRP (retornos logarítmicos → covarianza → average linkage → cuasi-diagonalización → pesos recursivos) a un benchmark independiente y ejecutamos exactamente la misma matemática en siete lenguajes — C, C++, Rust, Zig, Python, Node.js y Bun — bajo condiciones idénticas: Apple Silicon, un solo hilo, 365 observaciones diarias por activo, precios sintéticos, número de activos NN de 10 a 10.000.

Una palabra sobre la complejidad, porque define toda la forma. La versión de manual de average linkage vuelve a escanear toda la matriz de distancias en busca del par más cercano en cada fusión — eso es O(N3)O(N^3) y se convierte en el cuello de botella con unos pocos miles de activos. El benchmark usa en su lugar el algoritmo de cadena de vecinos más cercanos O(N2)O(N^2) (Müllner 2011) — el mismo que hay detrás de linkage(method='average') de SciPy. Con eso implementado, el clustering ya no es la etapa dominante: en N=2000N = 2000 son ~15 ms de un pase de ~0,5 s. El costo ahora está dominado por la matriz de covarianza, O(N2T)O(N^2 \cdot T) — la única etapa que ningún método tipo HRP puede evitar.

Lo que muestran las ejecuciones (las tablas completas por lenguaje y un script de reproducción de un solo comando están en el repositorio del proyecto):

  • En carteras realistas es gratis. Una cesta cripto tiene decenas de activos, rara vez más de cien. En N100N \le 100 un pase completo de HRP es de milisegundos de un solo dígito incluso en Node y microsegundos en Rust/C. Recalcular pesos en cada tick no es un problema.
  • Rust está dentro de ~1,0–1,3× de C — el mismo orden de magnitud, ambos compilados, y efectivamente empatados una vez que NN alcanza los miles. C es un poco más rápido en aritmética pura, pero Rust ofrece la misma previsibilidad sin recolector de basura y sin comportamiento indefinido.
  • Escala a miles de activos. Con linkage O(N2)O(N^2) un pase completo es de ~0,5 s en N=2000N = 2000 y unos pocos segundos en N=5000N = 5000 en los lenguajes compilados; incluso Node interpretado supera N=2000N = 2000 en menos de dos segundos. Lo que ahora marca el techo es la etapa de covarianza, no el clustering.

La conclusión pragmática: en nuestros tamaños de cartera, elegir Rust no se trata de "vencer a C" (C es ligeramente más rápido aquí) — se trata de una única base de código determinista para investigación y producción, sin pausas de GC y con años de margen de rendimiento. El benchmark completo de siete lenguajes, con resultados y script de reproducción, está abierto en el repositorio del proyecto.

Dónde se sitúa Pipeline entre los doce

En nuestra comparación sobre una única cesta (deliberadamente amañada), Pipeline se comportó como HRP — porque a través del punto de entrada solo-largo optimize() es HRP con una capa CVaR. Su maquinaria direccional solo cobra vida cuando se le alimentan señales de estrategia. Ese es todo el punto: Pipeline no es "otro optimizador más para hacer backtest de pesos" sino la capa de ejecución entre las señales de estrategia y las órdenes reales — toma tus decisiones de compra/venta, distribuye capital vía HRP dentro de cada lado, equilibra los lados por confianza y recorta el riesgo de cola hasta un presupuesto fijado.

Para el contexto completo — qué otros once métodos existen y en qué se diferencian — ver el resumen, «12 algoritmos de optimización de carteras, comparados». Y puedes probar todo en vivo en portfolio-optimizer.marketmaker.cc.

Referencias

  1. López de Prado, M. (2016). Building Diversified Portfolios that Outperform Out of Sample. The Journal of Portfolio Management.
  2. López de Prado, M. (2018). Advances in Financial Machine Learning. Wiley.
  3. Hull, J., & White, A. (1998). Incorporating Volatility Updating into the Historical Simulation Method for Value at Risk. Journal of Risk.
  4. Rockafellar, R. T., & Uryasev, S. (2000). Optimization of Conditional Value-at-Risk. Journal of Risk.
  5. RiskMetrics Group (1996). RiskMetrics — Technical Document. J.P. Morgan.
  6. Marketmaker.cc: marketmaker.cc

Cita

@article{soloviov2026pipeline,
  author = {Soloviov, Eugen and Zhuravleva, Marina and Kiselev, Kirill},
  title = {Inside Our House Algorithm: HRP + Long/Short + CVaR with Hull-White Adjustment},
  year = {2026},
  url = {https://marketmaker.cc/es/blog/post/portfolio-pipeline-hrp-cvar},
  description = {A deep dive into Pipeline, a composite portfolio allocation algorithm built on Hierarchical Risk Parity with a signal-driven long/short overlay and a Hull-White CVaR risk-budget correction, with the full specification and its Rust implementation.}
}
blog.disclaimer

Authors

Eugen Soloviov
Eugen Soloviov

Trading-systems engineer

Trading-systems engineer building bots since 2017: cross-exchange arbitrage (connected up to 30 venues), cointegration-based pairs arbitrage across spot and futures, scalping, news and sentiment-driven strategies, trend algorithms, and portfolio management and balancing algorithms. Also builds sub-millisecond order execution, big-data warehouses, backtesting engines, AI agents, and trading interfaces (incl. open-source profitmaker.cc). Stack: JS/TS, Python, Rust/Zig/Go, DevOps, backend, frontend, architecture.

Marina Zhuravleva
Marina Zhuravleva

Financial mathematics

Fifth-year student at Bauman Moscow State Technical University (Automatic Control Systems), specializing in financial mathematics. Background in calibrating stochastic-volatility (Heston) and local-volatility (Dupire) models, fair pricing of options including exotics via both Monte-Carlo and analytic formulas, hedging-error reduction, and exposure to LSV models.

Kirill Kiselev
Kirill Kiselev

Portfolio optimization

Fourth-year student at the Faculty of Mechanics and Mathematics, Novosibirsk State University (NSU); thesis on Heston-model calibration and delta-hedging within the same model. Works on portfolio optimization.

Newsletter

Mantente a la vanguardia

Suscríbete a nuestro boletín para recibir información exclusiva sobre trading con IA, análisis de mercado y actualizaciones de la plataforma.

Respetamos tu privacidad. Puedes darte de baja en cualquier momento.