← Zurück zu den Artikeln
May 25, 2026
5 min read

Ein Blick in unseren Hausalgorithmus: HRP + Long/Short + CVaR mit Hull-White

Ein Blick in unseren Hausalgorithmus: HRP + Long/Short + CVaR mit 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

📄 Aus diesem Artikel ist ein Forschungspapier geworden. Die HRP-Allokation im Kern dieser Pipeline wird in einem kontrollierten Test gegen Markowitz, Ledoit-Wolf-Shrinkage und 1/N unter bekannter Kovarianz geprüft (4.800 Experimente). Lest das Paper online (interaktive Version + PDF) unter hrp.marketmaker.cc, Code und Daten unter github.com/suenot/hrp-validation.

In unserem Überblick «12 Portfolio-Optimierungsalgorithmen im Vergleich» haben wir ein Dutzend Allokationsmethoden nebeneinander antreten lassen. Elf davon sind Lehrbuchklassiker. Der zwölfte, Pipeline, ist unser eigener — und er bekam in diesem Beitrag genau einen Aufzählungspunkt. Dieser Artikel ist der tiefe Einblick: was steckt darin, woher kommt jede Formel, und wie wird aus der Spezifikation Rust-Code.

Pipeline erfindet keine neue Methode zur Gewichtsberechnung. Es nimmt das robusteste bekannte Rezept — Hierarchical Risk Parity (HRP) — und umhüllt es mit den zwei Schichten, die ein Live-Handelskonto tatsächlich braucht, die reinem HRP aber fehlen: Richtung (Long/Short aus Strategiesignalen) und ein hartes Risikobudget (CVaR angepasst an das aktuelle Volatilitätsregime). Das ergibt vier Stufen.

Die vier Stufen

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 — Log-Renditen jedes Assets.
  • II — Basisgewichte aus HRP.
  • III — eine Long/Short-Aufteilung aus Agentensignalen, mit Risikoanteilen nach Konfidenz.
  • IV — eine CVaR-Korrektur mit Hull-White-Volatilität; überschüssiges Risiko fließt in Cash.

Gehen wir sie der Reihe nach durch.

Stufe I. Log-Renditen

Alles beginnt mit dem Übergang von Preisen zu Log-Renditen:

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

wobei ii das Asset und tt der Zeitschritt ist. Log-Renditen summieren sich über die Zeit und sind symmetrischer als einfache prozentuale Änderungen — der Standardeingabewert für jede Kovarianzrechnung.

Stufe II. HRP als Fundament

HRP, vorgeschlagen von Marcos López de Prado 2016, umgeht das zentrale Leiden der Mean-Variance-Optimierung — die Invertierung einer schlecht konditionierten Kovarianzmatrix. Es invertiert sie überhaupt nicht. Stattdessen arbeitet es mit der Struktur der Korrelationen.

Kovarianz und Korrelation

Aus den Renditen bauen wir die Kovarianzmatrix Σ\Sigma und normalisieren sie zur Korrelationsmatrix 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}

Distanzmatrix

Wir wandeln die Korrelation in eine Distanzmetrik um, sodass stark korrelierte Assets "nahe beieinander" landen:

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

Je näher ρi,j\rho_{i,j} bei 1 liegt, desto näher liegt di,jd_{i,j} bei 0 — und desto wahrscheinlicher teilen sich die Assets einen Cluster.

Dendrogramm und Blattreihenfolge

Aus der Distanzmatrix bauen wir eine Cluster-Hierarchie via average linkage und lesen die Blattreihenfolge π=(π1,,πN)\pi = (\pi_1, \ldots, \pi_N) ab — eine Permutation der Assets, in der ähnliche nebeneinander stehen.

Optionaler Schritt: die optimale Clusteranzahl kann über den Silhouettenkoeffizienten si=biaimax(bi,ai)s_i = \dfrac{b_i - a_i}{\max(b_i, a_i)} gewählt werden, wobei aia_i die mittlere Distanz innerhalb eines Clusters und bib_i die mittlere Distanz zum nächstgelegenen benachbarten Cluster ist. Der Basisdurchlauf braucht das nicht — die rekursive Bisektion respektiert die Hierarchie bereits.

Quasi-Diagonalisierung

Wir permutieren die Zeilen und Spalten von Σ\Sigma nach π\pi und sammeln große Werte entlang der Diagonalen:

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

Rekursive Bisektion

Dann läuft die Rekursion von oben nach unten. Bei jedem Schritt wird ein Cluster in zwei Hälften LL und RR geteilt, und Kapital wird zwischen den Hälften umgekehrt proportional zu ihren Varianzen verteilt:

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

Die Varianz eines Clusters wird auf seinem Kovarianz-Teilblock berechnet als σC2=1m2i,jCΣi,jq\sigma_C^2 = \tfrac{1}{m^2}\sum_{i,j \in C}\Sigma^{q}_{i,j}. Der Abstieg läuft weiter, bis jeder Knoten ein einzelnes Asset enthält. Die Gewichte sind long-only, nicht negativ und summieren sich zu 1,0.

In unserer Implementierung ist das die Funktion hrp_from_cov(cov) -> Vec<f64>: Korrelation → Distanz → average linkage → Blattreihenfolge → Quasi-Diagonalisierung → rekursive Bisektion. Pipeline ruft sie als Basis auf — und sie ist auch das öffentliche optimize() für den Fall ohne Signale.

Stufe III. Das Long/Short-Overlay

Reines HRP ist ein "nur-kaufen"-Portfolio. Aber eine Strategie sagt oft nicht nur wie viel, sondern in welche Richtung. Stufe III nimmt Signale pro Asset (Long/Short) vom Agenten und baut zwei Teilportfolios.

  1. Assets werden nach Signal in Long- und Short-Körbe aufgeteilt.
  2. Innerhalb jedes Korbs werden Gewichte mit demselben HRP berechnet (auf dem Kovarianz-Teilblock dieser Assets), summiert auf 1 pro Korb.
  3. Wenn der Agent auch eine Konfidenz pip_i ausgibt, werden die Risikoanteile zwischen den Seiten über die Gesamtkonfidenz festgelegt:

ξ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}

Ohne Konfidenz fallen die Anteile auf die Assetanzahl in jedem Korb zurück. Das finale vorzeichenbehaftete Gewicht ist wi=λLwiHRPw_i = \lambda_L \cdot w_i^{\text{HRP}} für Longs und wi=λSwiHRPw_i = -\lambda_S \cdot w_i^{\text{HRP}} für Shorts, wonach die gesamte Bruttoexponierung auf 1 normalisiert wird.

Eine ehrliche Anmerkung zum Code. Die ursprüngliche Spezifikation enthält Korrekturfaktoren αL=λL/σL\alpha_L = \sqrt{\lambda_L}/\sigma_L, αS=λS/σS\alpha_S = \sqrt{\lambda_S}/\sigma_S — markiert sie aber auch mit einem "brauchen wir diesen Schritt überhaupt?". Die Implementierung wendet sie nicht an: die beiden Seiten werden direkt über die Risikoanteile λ\lambda kombiniert, was die Bruttoexponierung exakt bei 1 hält und keine versteckte Hebelwirkung erzeugt. Das ist eine bewusste Vereinfachung der Spezifikation, kein Versehen.

Stufe IV. CVaR mit einer Hull-White-Anpassung

HRP balanciert Risiko strukturell, weiß aber nichts über das absolute Risikoniveau in Geldwerten. Die letzte Stufe setzt eine harte Obergrenze für das Tail-Risiko — und macht sie sensibel gegenüber einem Wechsel des Marktregimes.

Portfoliorendite und EWMA-Volatilität

Zunächst fassen wir die Gewichte zu einer Portfoliorendite zusammen und schätzen die bedingte Volatilität mit 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

mit λ=0.94\lambda = 0.94 (der klassische RiskMetrics-Wert). EWMA liefert die Volatilität "von heute" statt einer über die gesamte Historie gemittelten.

Hull-White-Neuskalierung

Die Kernidee: vergangene Renditen können nicht so übernommen werden, wie sie sind — sie ereigneten sich unter einer anderen Volatilität. Die Hull-White-Methode skaliert jede vergangene Rendite auf das aktuelle Niveau neu:

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

Ein ruhiger Monat wird "gestreckt", ein turbulenter "komprimiert", und die Verteilung wird in das aktuelle Regime übertragen.

VaR und CVaR

Auf der neuskalierten Verteilung nehmen wir das Verlustquantil und den mittleren Verlust im Tail:

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 (auch Expected Shortfall genannt) beantwortet nicht "wie schlimm ist ein typischer schlechter Tag", sondern "wie schlimm ist es im Durchschnitt über die schlechtesten α\alpha Prozent" — es erfasst also die Dicke des Tails, nicht nur seinen Rand.

Risikobudget und Cash

Übersteigt CVaR die akzeptable Schwelle, wird jede riskante Position um einen einzigen Faktor geschrumpft, und das freigewordene Kapital wandert in Cash:

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}|

So entrisikoiert sich das Portfolio selbst, wenn das Tail-Risiko wächst, und tritt wieder in den Markt ein, wenn es sich beruhigt.

Von der Spezifikation zum Code

Der gesamte Algorithmus lebt in einer einzigen Rust-Crate, portfolio-pipeline, und folgt dem einheitlichen Vertrag des Workspace:

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

Das ist die Long-only-Projektion (Stufen I, II, IV ohne Signale) — genau dieselbe prices -> weights-Schnittstelle wie bei den anderen elf Algorithmen, sodass Pipeline ein Drop-in-Ersatz für jeden von ihnen ist. Die vollständige Version mit jeder Stufe ist eine separate Funktion:

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 + σ

Die Overlay-Vorgaben: Tail cvar_alpha = 0.05, Budget cvar_max = 0.05, EWMA ewma_lambda = 0.94, Hull-White-Fenster hw_window = 0 (gesamte Historie). Die Implementierung hat keine externen Abhängigkeiten und ist bewusst defensiv: bei kurzen Historien (weniger als 4 Preispunkte) liefert sie Gleichgewichte, und das CVaR-Overlay greift erst ab ≥8 Renditebeobachtungen — sonst gibt es nichts, aus dem sich ein Tail schätzen ließe.

Warum Rust: eine deterministische Codebasis für Backtest und Produktion, ohne "Python im Research, etwas anderes in Prod"-Drift, und schnell genug, um alle zwölf Algorithmen in einem einzigen Request durch das Vergleichs-Backend laufen zu lassen.

Was es an Zeit kostet

Wie schnell ist "schnell genug"? Wir haben den HRP-Kern (Log-Renditen → Kovarianz → average linkage → Quasi-Diagonalisierung → rekursive Gewichte) in einen eigenständigen Benchmark ausgelagert und dieselbe Mathematik über sieben Sprachen laufen lassen — C, C++, Rust, Zig, Python, Node.js und Bun — unter identischen Bedingungen: Apple Silicon, Single Thread, 365 tägliche Beobachtungen pro Asset, synthetische Preise, Assetanzahl NN von 10 bis 10.000.

Ein Wort zur Komplexität, denn sie bestimmt die gesamte Form. Die Lehrbuchversion von average linkage durchsucht die volle Distanzmatrix bei jedem Merge erneut nach dem nächstgelegenen Paar — das ist O(N3)O(N^3) und wird bei wenigen tausend Assets zum Flaschenhals. Der Benchmark verwendet stattdessen den O(N2)O(N^2) Nearest-Neighbour-Chain-Algorithmus (Müllner 2011) — denselben, der hinter SciPys linkage(method='average') steckt. Damit ist das Clustering nicht mehr die dominierende Stufe: bei N=2000N = 2000 sind es ~15 ms von einem ~0,5 s-Durchlauf. Die Kosten werden jetzt von der Kovarianzmatrix, O(N2T)O(N^2 \cdot T), dominiert — der einen Stufe, die keine HRP-artige Methode vermeiden kann.

Was die Läufe zeigen (vollständige Tabellen pro Sprache und ein Ein-Befehl-Reproduktionsskript liegen im Projekt-Repository):

  • Bei realistischen Portfolios ist es kostenlos. Ein Krypto-Basket besteht aus Dutzenden Assets, selten mehr als hundert. Bei N100N \le 100 ist ein voller HRP-Durchlauf selbst in Node einstellig in Millisekunden und in Rust/C im Mikrosekundenbereich. Gewichte bei jedem Tick neu zu berechnen ist kein Problem.
  • Rust liegt innerhalb ~1,0–1,3× von C — dieselbe Größenordnung, beide kompiliert, und praktisch gleichauf, sobald NN die Tausender erreicht. C ist bei roher Arithmetik einen Hauch schneller, aber Rust liefert dieselbe Vorhersagbarkeit ohne Garbage Collector und ohne UB.
  • Es skaliert auf Tausende von Assets. Mit O(N2)O(N^2)-Linkage dauert ein voller Durchlauf ~0,5 s bei N=2000N = 2000 und einige Sekunden bei N=5000N = 5000 in den kompilierten Sprachen; selbst interpretiertes Node schafft N=2000N = 2000 in unter zwei Sekunden. Die Obergrenze setzt jetzt die Kovarianzstufe, nicht das Clustering.

Die pragmatische Erkenntnis: bei unseren Portfoliogrößen geht es bei der Wahl von Rust nicht darum, "C zu schlagen" (C ist hier leicht schneller) — es geht um eine deterministische Codebasis für Research und Produktion, ohne GC-Pausen und mit jahrelangem Performance-Spielraum. Der vollständige Sieben-Sprachen-Benchmark mit Ergebnissen und Reproduktionsskript ist offen im Projekt-Repository.

Wo Pipeline unter den zwölf steht

In unserem Vergleich auf einem einzigen (bewusst präparierten) Basket verhielt sich Pipeline wie HRP — weil es über den Long-only-Einstiegspunkt optimize() HRP mit einem CVaR-Overlay ist. Seine Richtungsmaschinerie erwacht erst, wenn man ihm Strategiesignale zuführt. Das ist der springende Punkt: Pipeline ist nicht "noch ein weiterer Optimierer zum Backtesten von Gewichten", sondern die Ausführungsschicht zwischen Strategiesignalen und echten Orders — es nimmt eure Kauf-/Verkaufsentscheidungen, legt Kapital per HRP innerhalb jeder Seite an, balanciert die Seiten nach Konfidenz und kappt das Tail-Risiko auf ein festgelegtes Budget.

Für den vollen Kontext — welche anderen elf Methoden existieren und wie sie sich unterscheiden — siehe den Überblick, «12 Portfolio-Optimierungsalgorithmen im Vergleich». Und ihr könnt alles live ausprobieren unter portfolio-optimizer.marketmaker.cc.

Referenzen

  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

Zitation

@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/de/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

Dem Markt einen Schritt voraus

Abonniere unseren Newsletter für exklusive KI-Trading-Einblicke, Marktanalysen und Plattform-Updates.

Wir respektieren deine Privatsphäre. Jederzeit abbestellbar.