Coverage for src/pyhrp/hrp.py: 100%
20 statements
« prev ^ index » next coverage.py v7.14.3, created at 2026-09-15 05:20 +0000
« prev ^ index » next coverage.py v7.14.3, created at 2026-09-15 05:20 +0000
1"""Hierarchical Risk Parity (HRP) allocation entry points.
3This module exposes the top-level allocation functions and re-exports the
4supporting building blocks so the public ``pyhrp.hrp`` API is unchanged:
5- hrp: Compute HRP portfolio weights from prices
6- schur_hrp: Compute Schur Complementary Allocation weights from prices
7- build_tree: Build a hierarchical cluster tree (see :mod:`pyhrp.dendrogram`)
8- compute_returns: Simple returns from prices (see :mod:`pyhrp.covariance`)
9- compute_cov / compute_corr: Second-moment estimators (see :mod:`pyhrp.covariance`)
10- Dendrogram: Clustering result container (see :mod:`pyhrp.dendrogram`)
11"""
13from __future__ import annotations
15from typing import Literal
17import polars as pl
19from .algos import risk_parity, schur_risk_parity
20from .cluster import Cluster
21from .covariance import check_finite_matrix, compute_corr, compute_cov, compute_returns
22from .dendrogram import Dendrogram, build_tree
24__all__ = [
25 "Dendrogram",
26 "build_tree",
27 "check_finite_matrix",
28 "compute_corr",
29 "compute_cov",
30 "compute_returns",
31 "hrp",
32 "schur_hrp",
33]
36def hrp(
37 prices: pl.DataFrame,
38 node: Cluster | None = None,
39 method: Literal["single", "complete", "average", "ward"] = "ward",
40 bisection: bool = False,
41) -> Cluster:
42 """Compute the hierarchical risk parity portfolio weights.
44 This is the main entry point for the HRP algorithm. It calculates returns from prices,
45 builds a hierarchical clustering tree if not provided, and applies risk parity weights.
47 Note:
48 A ``node`` passed in is weighted in place and returned; see the allocator
49 contract in :mod:`pyhrp.algos`. Passing ``dendrogram.root`` therefore
50 rewrites the portfolios inside that ``Dendrogram``, even though the
51 ``Dendrogram`` itself is a frozen dataclass.
53 Args:
54 prices (pl.DataFrame): Asset price time series (columns are assets, rows are dates)
55 node (Cluster, optional): Root node of the hierarchical clustering tree.
56 If None, a tree will be built from the correlation matrix.
57 method (Literal["single", "complete", "average", "ward"]): Linkage method to use for distance calculation
58 - "single": minimum distance between points (nearest neighbor)
59 - "complete": maximum distance between points (furthest neighbor)
60 - "average": average distance between all points
61 - "ward": Ward variance minimization
62 bisection (bool): Whether to use bisection method for tree construction
64 Returns:
65 Cluster: The root cluster with portfolio weights assigned according to HRP
66 """
67 returns = compute_returns(prices)
68 cov = check_finite_matrix(compute_cov(returns), name="covariance matrix")
69 cor = compute_corr(returns)
70 node = node or build_tree(cor, method=method, bisection=bisection).root
72 return risk_parity(root=node, cov=cov)
75def schur_hrp(
76 prices: pl.DataFrame,
77 node: Cluster | None = None,
78 method: Literal["single", "complete", "average", "ward"] = "ward",
79 bisection: bool = False,
80 gamma: float = 0.5,
81) -> Cluster:
82 """Compute Schur Complementary Allocation portfolio weights.
84 Extends HRP by augmenting each sub-covariance block with off-diagonal information
85 via Schur complements before splitting risk between clusters. Introduced by Peter Cotton
86 (arXiv:2411.05807). At gamma=0 this is identical to HRP; at gamma=1 it recovers the
87 global minimum-variance portfolio through the same recursive hierarchy.
89 Note:
90 A ``node`` passed in is weighted in place and returned; see the allocator
91 contract in :mod:`pyhrp.algos`. Passing ``dendrogram.root`` therefore
92 rewrites the portfolios inside that ``Dendrogram``, even though the
93 ``Dendrogram`` itself is a frozen dataclass.
95 Args:
96 prices (pl.DataFrame): Asset price time series (columns are assets, rows are dates)
97 node (Cluster, optional): Root node of the hierarchical clustering tree.
98 If None, a tree will be built from the correlation matrix.
99 method (Literal["single", "complete", "average", "ward"]): Linkage method for clustering
100 bisection (bool): Whether to use bisection method for tree construction
101 gamma (float): Schur interpolation parameter in [0, 1].
102 0 recovers standard HRP; 1 recovers minimum-variance portfolio.
104 Returns:
105 Cluster: The root cluster with portfolio weights assigned
106 """
107 returns = compute_returns(prices)
108 cov = check_finite_matrix(compute_cov(returns), name="covariance matrix")
109 cor = compute_corr(returns)
110 node = node or build_tree(cor, method=method, bisection=bisection).root
112 return schur_risk_parity(root=node, cov=cov, gamma=gamma)