Ein Blick in unseren Hausalgorithmus: HRP + Long/Short + CVaR mit Hull-White
📄 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
- 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:
wobei das Asset und 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 und normalisieren sie zur Korrelationsmatrix :
Distanzmatrix
Wir wandeln die Korrelation in eine Distanzmetrik um, sodass stark korrelierte Assets "nahe beieinander" landen:
Je näher bei 1 liegt, desto näher liegt 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 ab — eine Permutation der Assets, in der ähnliche nebeneinander stehen.
Optionaler Schritt: die optimale Clusteranzahl kann über den Silhouettenkoeffizienten gewählt werden, wobei die mittlere Distanz innerhalb eines Clusters und 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 nach und sammeln große Werte entlang der Diagonalen:
Rekursive Bisektion
Dann läuft die Rekursion von oben nach unten. Bei jedem Schritt wird ein Cluster in zwei Hälften und geteilt, und Kapital wird zwischen den Hälften umgekehrt proportional zu ihren Varianzen verteilt:
Die Varianz eines Clusters wird auf seinem Kovarianz-Teilblock berechnet als . 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.
- Assets werden nach Signal in Long- und Short-Körbe aufgeteilt.
- Innerhalb jedes Korbs werden Gewichte mit demselben HRP berechnet (auf dem Kovarianz-Teilblock dieser Assets), summiert auf 1 pro Korb.
- Wenn der Agent auch eine Konfidenz ausgibt, werden die Risikoanteile zwischen den Seiten über die Gesamtkonfidenz festgelegt:
Ohne Konfidenz fallen die Anteile auf die Assetanzahl in jedem Korb zurück. Das finale vorzeichenbehaftete Gewicht ist für Longs und für Shorts, wonach die gesamte Bruttoexponierung auf 1 normalisiert wird.
Eine ehrliche Anmerkung zum Code. Die ursprüngliche Spezifikation enthält Korrekturfaktoren , — 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 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:
mit (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:
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:
CVaR (auch Expected Shortfall genannt) beantwortet nicht "wie schlimm ist ein typischer schlechter Tag", sondern "wie schlimm ist es im Durchschnitt über die schlechtesten 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:
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 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 und wird bei wenigen tausend Assets zum Flaschenhals. Der Benchmark verwendet stattdessen den 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 sind es ~15 ms von einem ~0,5 s-Durchlauf. Die Kosten werden jetzt von der Kovarianzmatrix, , 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 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 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 -Linkage dauert ein voller Durchlauf ~0,5 s bei und einige Sekunden bei in den kompilierten Sprachen; selbst interpretiertes Node schafft 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
- López de Prado, M. (2016). Building Diversified Portfolios that Outperform Out of Sample. The Journal of Portfolio Management.
- López de Prado, M. (2018). Advances in Financial Machine Learning. Wiley.
- Hull, J., & White, A. (1998). Incorporating Volatility Updating into the Historical Simulation Method for Value at Risk. Journal of Risk.
- Rockafellar, R. T., & Uryasev, S. (2000). Optimization of Conditional Value-at-Risk. Journal of Risk.
- RiskMetrics Group (1996). RiskMetrics — Technical Document. J.P. Morgan.
- 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.}
}
Authors
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.
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.
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.