# D14-F02-A04 — Hierarchical Risk Parity

> **Domain:** D14 — Portfolio Construction  
> **Family:** D14-F02 — Risk Allocation  
> **Status:** Tested canonical source; article and video remain draft until visitor release validation.

## Executive summary

Hierarchical Risk Parity (HRP) first discovers a tree in the covariance
structure, then allocates down that tree. This package freezes a transparent
original-profile recipe: correlation distance, deterministic single linkage,
quasi-diagonal leaf order, and inverse-variance recursive bisection. It does
not call every Ward/average/CDaR library option “HRP.”

The original-paper mirror was inspected at
[Building Diversified Portfolios that Outperform Out of Sample](https://smallake.kr/wp-content/uploads/2020/04/SSRN-id2708678.pdf).
The official [skfolio HRP documentation](https://skfolio.org/generated/skfolio.optimization.HierarchicalRiskParity.html)
is used to separate original choices from library defaults. “Outperform” is a
paper title and discovery label, not a promise made by this package.

## Why a hierarchy?

A flat optimizer compares every asset with every other asset. HRP uses the
correlation structure to place similar assets on nearby branches, reorders the
covariance into a quasi-diagonal form, and recursively splits capital between
branches according to their measured variance. The result is a heuristic
allocation, not a solution to a stated return-optimization objective.

## Definitions

| Term | Definition |
|---|---|
| Correlation | rho_ij = Sigma_ij / sqrt(Sigma_ii Sigma_jj). |
| Pair profile | D_ij = sqrt((1-rho_ij)/2), with D_ii = 0. |
| Distance | d_ij = ||D_{·i} - D_{·j}||_2, the Euclidean distance between pair profiles. |
| Single linkage | Distance between two clusters is the minimum cross-cluster leaf distance. |
| Quasi-diagonal order | Deterministic leaf order obtained by traversing the merge tree. |
| Branch variance | Variance of inverse-variance weights within one ordered branch. |
| Recursive bisection | For left/right branch risks v_L,v_R, left capital is v_R/(v_L+v_R). |

## Frozen contract

Input IDs are non-empty unique strings. Covariance is finite, exactly symmetric,
positive diagonal, one horizon and scale. The implementation normalizes by the
actual largest absolute entry, accepts positive semidefinite input within
1e-12 normalized Jacobi tolerance (including singular matrices), and never
repairs or silently symmetrizes. A zero or unrepresentable branch risk returns
numerical-range-invalid.

Output weights are finite, strictly positive, and sum within 1e-12 of one.
Absolute component risk is w_i(Sigma w)_i/sigma_p; signed contributions are
allowed, because an individual marginal contribution can be negative even when
portfolio volatility is positive. Merges, distances, order, method choices,
portfolio risk, and status are returned for inspection. Provider provenance,
return estimation, corporate actions, FX, costs, leverage, and ranking claims
are out of scope.

## Input and output tables

| Input | Type / unit | Constraint |
|---|---|---|
| assetIds | ordered string array | non-empty, unique, non-blank |
| covariance | numeric N x N | finite, exact symmetry, positive diagonal, PSD after scaling |

| Output | Meaning | Invariant |
|---|---|---|
| weights | fully invested capital weights | finite, positive, sum 1 within 1e-12 |
| correlationMatrix, distanceMatrix | inspected tree inputs | derived from covariance without hidden repair |
| quasiDiagonalOrder, merges | hierarchy evidence | deterministic for fixed ordered input |
| componentRiskContributions, componentRiskShares | absolute and relative risk | contributions sum to portfolio volatility |
| portfolioVariance, portfolioVolatility | supplied covariance scale | finite, strictly positive |
| method, linkage, splitRule, status | computation provenance | explicit labels; status ok only after checks |

## Algorithm

1. Validate IDs and covariance shape, finite range, exact symmetry, diagonal, and PSD.
2. Derive correlation and pair profile D_ij = sqrt((1-rho_ij)/2); reject an out-of-range correlation.
3. Measure Euclidean distance between columns of D, then run deterministic single linkage; ties use distance then lexicographic cluster order.
4. Traverse the merge tree to obtain the quasi-diagonal leaf order.
5. Recursively bisect the order. For each branch use stable min(diagonal)/diagonal inverse-variance weights; split capital in inverse proportion to branch variance.
6. Recompute portfolio variance, volatility, signed component contributions, and shares from returned weights.

The full definition and numerical boundaries are in
[DEFINITION-CONTRACT.md](./DEFINITION-CONTRACT.md), with the independently
computed four-asset values in [CANONICAL-EXAMPLE.md](./CANONICAL-EXAMPLE.md).

## Evidence and historical boundary

A historically proven allocation is **deferred**. The prior 4070.SR
Tihama suspension/resumption case is useful only as a missing/stale quote
availability boundary: suspension is not zero variance. Islam's confirmed
input-integrity motivation also covers split-invalid prices, suspect
quantity/mark imports, changing weights, and USD display of Egypt/Japan/USA
holdings. Quantity times local mark times FX is market value, not cost basis,
and local-return covariance is not base-return covariance. The HRP core accepts
only a supplied covariance and does not infer those facts.

The [Stale-Quote Detector](https://thefintechbuilder.com/market-data-engineering/cleaning-and-validation/stale-quote-detector/)
method is linked as prior context; any stale/split/FX panel in the lab is
clearly synthetic and routed as an upstream evidence reminder.

## Visuals and computed lab

The Mermaid flow is
[visuals/mermaid/hrp-flow.md](./visuals/mermaid/hrp-flow.md), the static
diagram is [visuals/static/hrp-tree.svg](./visuals/static/hrp-tree.svg), and
the editable browser lab is
[visuals/animated/playground.html](./visuals/animated/playground.html).
The browser lab calls the same generated TypeScript module used by the tests
and displays hierarchy records as well as final risks.

## Implementation and testing

Reference functions are implementations/python/hierarchical_risk_parity.py and
implementations/typescript/hierarchical-risk-parity.ts. Clustering is O(N^3)
with the straightforward single-linkage scan; storage is O(N^2). The JSON-lines
CLI supports direct parity.

```powershell
python -m unittest discover -s tests -p "test_*.py"
node_modules/.bin/tsc --ignoreConfig --target ES2022 --module NodeNext --moduleResolution NodeNext --strict --skipLibCheck --types node --outDir .tmp-ts implementations/typescript/hierarchical-risk-parity.ts tests/typescript/hierarchical-risk-parity.test.ts
$env:A04_FIXTURE_PATH=(Resolve-Path tests/fixtures/a04-hrp-fixtures.json)
$env:A04_PYTHON_CLI_PATH=(Resolve-Path implementations/python/hierarchical_risk_parity_cli.py)
node .tmp-ts/tests/typescript/hierarchical-risk-parity.test.js
```

Use the repository TypeScript 7.0.2 and installed @types/node; unpinned npx
does not provision those prerequisites. Serve the lab with
python -m http.server 8765 --directory visuals/animated, then open
http://127.0.0.1:8765/playground.html. file:// ESM loading is unsupported.

## Edge cases and limitations

| Case | Behavior | Reason |
|---|---|---|
| Singular PSD matrix | Accepted if branch risks remain positive | HRP does not invert covariance. |
| Indefinite/asymmetric/zero diagonal | Structured invalid-covariance | Tree distances and variance need a coherent matrix. |
| Zero branch variance | numerical-range-invalid | No silent all-capital-to-zero-risk decision. |
| Alternative linkage or risk measure | Not this method label | Ward, average, CDaR, and HERC are explicit variants. |
| Missing/stale/split/FX evidence | Upstream validation route | Arithmetic cannot authenticate a provider panel. |

HRP is a covariance-dependent heuristic. A stable tree does not prove a stable
future portfolio, and a single backtest cannot prove superiority. The result
contains no expected-return forecast or investment recommendation.

## Related topics

- D14-F02-A01 — standalone reciprocal-volatility baseline.
- D14-F02-A02 — global equal-risk contribution contrast.
- D14-F02-A03 — arbitrary positive risk budgets.
- D14-F02-A05 — hierarchical equal-risk contribution variant.

See [REFERENCES.md](./REFERENCES.md).
