Chargement de SwissQuant / Loading SwissQuant

Hedge Fund Risk Parity

Allocation mensuelle entre SPY, TLT, GLD et UUP pour égaliser leurs contributions au risque estimé, en tenant compte des corrélations. Sans levier ni ciblage de volatilité.

Catégorie : Allocation de portefeuille · Univers : SPY, TLT, GLD, UUP

Famille : Allocation de portefeuille

Verdict en bref

Sur 2011–2026, l'ERC sans levier a rapporté nettement moins que le 60/40 — 6,20 % contre 9,45 % par an — avec une volatilité beaucoup plus faible : 4,19 % contre 9,15 %. À volatilité égale, le 60/40 mélangé à SHY a rapporté 4,86 % par an, contre 6,20 % pour l'ERC, avec une perte maximale plus profonde : −11,41 % contre −5,13 %. L'avantage à volatilité égale n'est pas retrouvé sans UUP : il dépend ici de la présence et de la forte pondération de l'exposition au dollar, dont la valeur ajustée s'est appréciée sur la période. Les mélanges sont calibrés rétrospectivement sur une seule période ; cette comparaison ne démontre pas une supériorité durable.

Réplication calculée · audit en attente. Contenu éducatif ; résultats simulés passés, sans garantie de rendement ni protection. Ceci n'est pas un conseil en placement.

Le principe

Des parts égales en capital ne produisent pas des parts égales de risque. L'ERC ajuste les poids en fonction de la volatilité et des corrélations estimées pour équilibrer les contributions au risque. Cela ne garantit ni rendement ni protection.

Cinq règles pour comprendre le mécanisme

  1. Univers : SPY, TLT, GLD, UUP. Cours ajustés Yahoo archivés, en USD ; aucune observation manquante comblée.
  2. Estimation : 252 rendements quotidiens simples, à partir de 253 clôtures terminant à la séance précédant l'exécution ; covariance empirique annualisée.
  3. Allocation : contribution estimée de chaque ETF égale à 25 % du risque total ; résolution convexe du budget de risque et vérification des contributions. Poids positifs totalisant 100 %, sans levier.
  4. Exécution : rééquilibrage à la clôture ajustée de la dernière séance commune de chaque mois, avec les signaux fixés la veille.
  5. Évaluation : coûts de 0,09 % par dollar acheté ou vendu, achats initiaux inclus ; comparateur 60 % SPY / 40 % AGG rééquilibré mensuellement aux mêmes coûts. Sharpe affiché à 0 % ; perte maximale sur NAV mensuelle.

Résultats recalculés et variantes

Période réellement évaluée : du 2011-01-31 au 2026-08-31 ; 187 rendements mensuels complets, premier mois complet au 2011-02-28. Frais et glissement : 0,09 % par côté ; Sharpe à 0 %. Perte maximale calculée sur la NAV mensuelle.

PortefeuilleCAGRVolatilitéSharpePerte maximaleNAV finale · base 100
ERC officiel · quatre ETF6,20 %4,19 %1,46−5,13 %255,31
60/40 SPY/AGG9,45 %9,15 %1,04−20,06 %408,23
60/40 + SHY · volatilité ERC égale4,86 %4,19 %1,16−11,41 %209,52
Variante · inverse de volatilité6,48 %4,74 %1,35−5,24 %266,01
Robustesse · ERC sans dollar8,91 %9,00 %1,00−21,56 %378,07
60/40 + SHY · volatilité sans dollar égale9,31 %9,00 %1,04−19,80 %400,17

Les deux comparateurs 60/40 + SHY sont calibrés séparément, rétrospectivement sur toute la période, à la volatilité respective de l'ERC officiel et de l'ERC sans dollar ; ce n'est pas une validation hors échantillon.

6 derniers mois · positions après rééquilibrage

NAV sur base 100 ; poids cibles du modèle officiel après rééquilibrage.

MoisNAV #009RendementNAV 60/40Poids
2026-03250,69−1,96 %368,93SPY 12,23 % · TLT 24,68 % · GLD 12,73 % · UUP 50,35 %
2026-04250,980,11 %392,42SPY 16,04 % · TLT 23,77 % · GLD 9,70 % · UUP 50,49 %
2026-05254,421,37 %405,26SPY 16,16 % · TLT 22,85 % · GLD 8,30 % · UUP 52,69 %
2026-06255,840,56 %403,17SPY 14,72 % · TLT 23,18 % · GLD 7,87 % · UUP 54,23 %
2026-07252,19−1,42 %401,16SPY 14,36 % · TLT 23,15 % · GLD 7,89 % · UUP 54,59 %
2026-08255,311,24 %408,23SPY 13,86 % · TLT 21,76 % · GLD 7,61 % · UUP 56,77 %

Extrait essentiel · replicate_009.py

Extrait abrégé, non autonome ; contrôles et départs multiples dans les détails techniques.

# Essential fragments; full checks and multi-start search in technical details.
# Input: 252 daily returns ending before execution.
covariance = np.cov(returns, rowvar=False, ddof=1) * 252
def objective(holdings: np.ndarray) -> float:
    return float(0.5 * holdings @ covariance @ holdings - 0.25 * np.log(holdings).sum())
# For each deterministic start:
solution = minimize(
    objective, seed, method="SLSQP", bounds=[(1e-8, 100.0)] * 4,
    jac=lambda x: covariance @ x - 0.25 / x,
    options={"ftol": 1e-13, "maxiter": 1000},
)
# After retaining successful solutions:
winner = min(solutions, key=lambda item: objective(item.x))
weights = winner.x / winner.x.sum()
contribution = risk_contributions(weights)
error = float(np.max(np.abs(contribution - 0.25)))
if error > 1e-5:
    fail(f"ERC contribution inequality exceeds tolerance: {error}")
Détails techniques · code complet de la règle d'allocation · replicate_009.py
# Excerpt: official allocation rule. Trading costs are applied separately.
import numpy as np
from scipy.optimize import minimize
ASSETS = ("SPY", "TLT", "GLD", "UUP")
TRANSACTION_COST_RATE = 0.0009

def fail(message):
    raise ValueError(message)

def solve_weights(returns: np.ndarray) -> tuple[dict[str, float], dict[str, float], list[float], float]:
    if returns.shape != (252, 4) or not np.isfinite(returns).all():
        fail("Incomplete or invalid 252 x 4 daily-return window")
    covariance = np.cov(returns, rowvar=False, ddof=1) * 252
    eigenvalues = np.linalg.eigvalsh(covariance)
    if not np.isfinite(covariance).all() or eigenvalues[0] <= 1e-12:
        fail("Covariance matrix is not positive definite")
    inverse_vol = 1 / np.sqrt(np.diag(covariance))
    inverse_vol /= inverse_vol.sum()

    def risk_contributions(weights: np.ndarray) -> np.ndarray:
        variance = float(weights @ covariance @ weights)
        if variance <= 0:
            fail("Non-positive portfolio variance")
        return weights * (covariance @ weights) / variance

    # Convex risk-budget formulation on positive unnormalised holdings.
    # At the optimum x_i*(Sigma x)_i = 1/4 for every asset; normalising x
    # preserves equal *fractional* contributions. Direct squared-RC SLSQP
    # can converge to spurious boundary minima when correlations turn negative.
    def objective(holdings: np.ndarray) -> float:
        return float(0.5 * holdings @ covariance @ holdings - 0.25 * np.log(holdings).sum())

    solutions = []
    for seed in (inverse_vol * 10, np.full(4, 5.0)):
        solution = minimize(
            objective, seed, method="SLSQP", bounds=[(1e-8, 100.0)] * 4,
            jac=lambda x: covariance @ x - 0.25 / x,
            options={"ftol": 1e-13, "maxiter": 1000},
        )
        if solution.success and np.isfinite(solution.x).all() and (solution.x > 0).all():
            solutions.append(solution)
    if not solutions:
        fail("ERC SLSQP failed for all deterministic starts")
    winner = min(solutions, key=lambda item: objective(item.x))
    weights = winner.x / winner.x.sum()
    contribution = risk_contributions(weights)
    error = float(np.max(np.abs(contribution - 0.25)))
    if error > 1e-5:
        fail(f"ERC contribution inequality exceeds tolerance: {error}")
    return ({ticker: float(weights[i]) for i, ticker in enumerate(ASSETS)},
            {ticker: float(inverse_vol[i]) for i, ticker in enumerate(ASSETS)},
            [float(value) for value in contribution], error)

Trois limites à retenir

  1. Dépendance au dollar : UUP dépasse 50 % de l'allocation pendant les six derniers rééquilibrages de l'archive. Le test sans UUP ne conserve pas l'avantage à volatilité égale.
  2. Absence de levier : la risk parity est souvent associée à du levier pour relever son niveau de risque. Aucun levier n'est simulé ici ; le rendement et le risque sont tous deux plus faibles que ceux du 60/40.
  3. Une seule période : paramètres estimés, coûts supposés et prix ajustés susceptibles de révision. Les mélanges 60/40 + SHY sont calibrés après coup ; ils ne constituent pas une validation hors échantillon.

Guide et calcul officiel

Le guide et son code décrivent l'inverse de volatilité, qui ignore les corrélations. La version officielle affichée ici est l'ERC ; l'inverse de volatilité reste une variante secondaire. Le ciblage de volatilité annoncé dans l'ancienne fiche n'est pas appliqué.

Les anciennes données sont conservées séparément ; les anciens rapports PDF ne sont pas proposés depuis cette fiche corrigée.

Références méthodologiques

Ces publications expliquent les méthodes ; elles ne valident pas les résultats SwissQuant.