Skip to content
13

Schur Complement Hierarchical Risk Parity

PortfolioOptimisers.SchurComplementAlgorithm Type
julia
abstract type SchurComplementAlgorithm <: AbstractAlgorithm

Abstract supertype for Schur Complement algorithm variants.

Related

source
PortfolioOptimisers.NonMonotonicSchurComplement Type
julia
struct NonMonotonicSchurComplement <: SchurComplementAlgorithm

Non-monotonic Schur Complement algorithm variant for SCHRP.

Uses the raw Schur complement formula without monotonicity correction.

Related

source
PortfolioOptimisers.MonotonicSchurComplement Type
julia
struct MonotonicSchurComplement{__T_N, __T_tol, __T_iter, __T_strict} <: SchurComplementAlgorithm

Monotonic Schur Complement algorithm variant for SCHRP.

Applies a bisection-based correction to ensure the Schur complement allocation factor γ is monotonically increasing with cluster risk, controlled by convergence tolerance tol and maximum iterations iter.

Fields

  • N: Number of bisection steps for the monotonic Schur complement.

  • tol: Convergence tolerance.

  • iter: Maximum number of iterations.

  • strict: Whether to raise an error if convergence is not achieved.

Constructors

julia
MonotonicSchurComplement(;
    N::Integer = 10,
    tol::Number = 1e-4,
    iter::Option{<:Integer} = nothing,
    strict::Bool = false
) -> MonotonicSchurComplement

Keywords correspond to the struct's fields.

Related

source
PortfolioOptimisers.SchurComplementParams Type
julia
struct SchurComplementParams{__T_r, __T_gamma, __T_pdm, __T_alg, __T_flag} <: AbstractAlgorithm

Parameters for the Schur Complement step of SCHRP.

SchurComplementParams collects the risk measure, initial allocation factor γ, positive-definite matrix correction, and monotonicity algorithm used in the Schur Complement Hierarchical Risk Parity optimisation.

Fields

  • r: Risk measure or vector of risk measures.

  • gamma: Schur complement decomposition parameter.

  • pdm: Positive definite matrix estimator.

  • alg: Schur complement algorithm variant.

  • flag: Algorithm selection flag.

Constructors

julia
SchurComplementParams(;
    r::Sd_Var = Variance(),
    gamma::Number = 0.5,
    pdm::Option{<:Posdef} = Posdef(),
    alg::SchurComplementAlgorithm = MonotonicSchurComplement(),
    flag::Bool = true
) -> SchurComplementParams

Keywords correspond to the struct's fields.

Validation

  • 0 <= gamma <= 1.

Related

source
PortfolioOptimisers.port_opt_view Method
julia
port_opt_view(sp, i, X)

Get a view or subset of Schur complement parameters for cluster index i.

Returns a SchurComplementParams with the risk measure sliced for the given cluster index. Used internally when iterating over cluster levels.

Arguments

  • sp: SchurComplementParams or vector thereof.

  • i: Cluster index or range.

  • X: Data matrix (used for slicing risk measures).

Returns

Related

source
PortfolioOptimisers.Sd_Var Type
julia
const Sd_Var = Union{<:StandardDeviation, <:Variance}

Alias for a standard deviation or variance risk measure.

Used in the Schur Complement HRP to accept either risk measure type for computing naive portfolio risk.

Related

source
PortfolioOptimisers.naive_portfolio_risk Method
julia
naive_portfolio_risk(r, sigma)

Compute the naive (inverse-volatility) portfolio risk for a given risk measure.

Returns the portfolio risk when weights are set to the inverse-variance or inverse-volatility allocation (i.e., w = 1/diag(sigma), normalised to sum to one). Dispatches on the risk measure type.

Arguments

Returns

  • Scalar portfolio risk.

Related

source
PortfolioOptimisers.symmetric_step_up_matrix Method
julia
symmetric_step_up_matrix(n1::Integer, n2::Integer)

Construct a symmetric step-up matrix for Schur complement augmentation.

Builds a matrix that maps between cluster levels of sizes n1 and n2. Requires |n1 - n2| <= 1.

Arguments

  • n1: Number of rows (one cluster level size).

  • n2: Number of columns (adjacent cluster level size).

Returns

  • A numeric matrix of size n1 × n2.

Related

source
PortfolioOptimisers.schur_augmentation Method
julia
schur_augmentation(A, B, C, gamma)

Apply the Schur complement augmentation to a risk sub-matrix.

Computes the augmented matrix A - gamma * B * inv(C) * B' and applies a step-up matrix correction. Used internally in the SCHRP algorithm to decompose inter-cluster risk.

Arguments

  • A: Intra-cluster covariance sub-matrix.

  • B: Off-diagonal cross-cluster covariance sub-matrix.

  • C: Inter-cluster covariance sub-matrix.

  • gamma: Schur complement scaling parameter.

Returns

  • Augmented matrix.

Related

source
PortfolioOptimisers.schur_complement_binary_search Method
julia
schur_complement_binary_search(objective, lgamma, hgamma, ...)

Binary search for the optimal Schur complement scaling parameter γ.

Performs binary search in the interval [lgamma, hgamma] to find the γ value that satisfies the monotonicity condition for the Schur complement HRP.

Arguments

  • objective: Function to evaluate monotonicity.

  • lgamma: Lower bound for γ search.

  • hgamma: Upper bound for γ search.

  • Additional tolerance and iteration parameters.

Returns

  • Optimal γ value.

Related

source
PortfolioOptimisers.schur_complement_weights Function
julia
schur_complement_weights(pr, items, ...)

Compute HRP/HERC weights using the Schur complement method.

Allocates weights across cluster levels using the Schur complement of the covariance matrix, providing more accurate inter-cluster risk decomposition than naive HRP.

Arguments

  • pr: Prior result containing asset moments.

  • items: Vector of vectors of asset indices per cluster level.

  • Additional parameters from SchurComplementParams.

Returns

  • Portfolio weight vector.

Related

source
PortfolioOptimisers.schur_complement_weights Method
julia
schur_complement_weights(
    pr::AbstractPriorResult,
    items::AbstractVector{<:AbstractVector{<:Integer}},
    wb::WeightBounds,
    params::SchurComplementParams{<:Any, <:Any, <:Any, <:MonotonicSchurComplement}
) -> Tuple{Any, Any}

Compute SCHRP weights using the monotonic Schur complement method.

Uses binary search to find the γ value that maximises risk reduction while maintaining monotonicity, then delegates to the non-monotonic overload.

Related

source
PortfolioOptimisers.VecScP Type
julia
const VecScP = AbstractVector{<:SchurComplementParams}

Alias for a vector of Schur complement parameters.

Represents a collection of SchurComplementParams objects, used when different cluster levels have different Schur complement configurations.

Related

source
PortfolioOptimisers.ScP_VecScP Type
julia
const ScP_VecScP = Union{<:SchurComplementParams, <:VecScP}

Alias for a single or vector of Schur complement parameters.

Matches either a single SchurComplementParams or a vector of them (VecScP).

Related

source
PortfolioOptimisers.SchurComplementHierarchicalRiskParityResult Type
julia
struct SchurComplementHierarchicalRiskParityResult{__T_oe, __T_pr, __T_wb, __T_clr, __T_gamma, __T_retcode, __T_w, __T_fb} <: NonJuMPOptimisationResult

Result type returned by SchurComplementHierarchicalRiskParity optimisation.

Stores the optimisation estimator, prior result, weight bounds, clustering result, Schur complement scaling parameter, return code, optimised weights, and optional fallback estimator.

Fields

  • oe: Type of the optimisation estimator that produced this result.

  • pr: Prior result.

  • wb: Weight bounds.

  • clr: Clusters result.

  • gamma: Schur complement decomposition parameter.

  • retcode: Optimisation return code.

  • w: Portfolio weights vector assets × 1.

  • fb: Fallback result or estimator.

Related

source
PortfolioOptimisers.factory Method
julia
factory(a::Union{Nothing, <:AbstractEstimator, <:AbstractAlgorithm,
                 <:AbstractResult}, args...; kwargs...) -> a

No-op factory function for constructing objects with a uniform interface.

Defining methods which dispatch on the first argument allows for a consistent factory interface across different types.

Arguments

  • a: Indicates no object should be constructed.

  • args...: Arbitrary positional arguments (ignored).

  • kwargs...: Arbitrary keyword arguments (ignored).

Returns

  • a: The input unchanged.

Examples

julia
julia> factory(nothing, 1, 2; x = 3)

julia> factory(MeanValue())
MeanValue
  w ┴ nothing

Related

source
julia
factory(res::NonFiniteAllocationOptimisationResult, fb::Option{<:OptE_Opt})

Rebuild a continuous optimisation result with an updated fallback optimiser fb.

Every optimisation result carries fb as its last field, so the generic rebuild copies all fields unchanged except the trailing fb. Concrete result types may override this method when rebuilding requires more than swapping fb.

Related

source
julia
factory(
    opt::Union{NonFiniteAllocationOptimisationEstimator, NonFiniteAllocationOptimisationResult},
    _
) -> RandomWeighted{_A, var"#s179", _B, _C, _D, var"#s1791", _E, Bool} where {_A, var"#s179"<:AbstractRNG, _B, _C, _D, var"#s1791"<:WeightFinaliser, _E}

Return opt unchanged.

Default pass-through factory for optimisation estimators and results. Overridden for estimators that carry parameters requiring update at each optimisation step.

Related

source
PortfolioOptimisers.SchurComplementHierarchicalRiskParity Type
julia
struct SchurComplementHierarchicalRiskParity{__T_opt, __T_params, __T_fb} <: ClusteringOptimisationEstimator

Schur Complement Hierarchical Risk Parity (SCHRP) portfolio optimiser.

SchurComplementHierarchicalRiskParity extends HRP by using the Schur complement of the covariance matrix to more accurately decompose inter-cluster risk when allocating portfolio weights across the dendrogram.

Fields

  • opt: Base hierarchical optimiser configuration.

  • params: Schur complement decomposition parameters.

  • fb: Fallback result or estimator.

Constructors

julia
SchurComplementHierarchicalRiskParity(;
    opt::HierarchicalOptimiser = HierarchicalOptimiser(),
    params::ScP_VecScP = SchurComplementParams(),
    fb::Option{<:OptE_Opt} = nothing
) -> SchurComplementHierarchicalRiskParity

Keywords correspond to the struct's fields.

Validation

  • If params is a vector: !isempty(params).

Propagated parameters

When factory is called on this type, the following @fprop-tagged fields are automatically propagated:

  • opt: Recursively updated via factory.

  • fb: Recursively updated via factory.

Examples

julia
julia> SchurComplementHierarchicalRiskParity()
SchurComplementHierarchicalRiskParity
     opt ┼ HierarchicalOptimiser
         │       pe ┼ EmpiricalPrior
         │          │        ce ┼ PortfolioOptimisersCovariance
         │          │           │   ce ┼ Covariance
         │          │           │      │    me ┼ SimpleExpectedReturns
         │          │           │      │       │   w ┴ nothing
         │          │           │      │    ce ┼ GeneralCovariance
         │          │           │      │       │   ce ┼ StatsBase.SimpleCovariance: StatsBase.SimpleCovariance(true)
         │          │           │      │       │    w ┴ nothing
         │          │           │      │   alg ┴ Full()
         │          │           │   mp ┼ MatrixProcessing
         │          │           │      │     pdm ┼ Posdef
         │          │           │      │         │      alg ┼ UnionAll: NearestCorrelationMatrix.Newton
         │          │           │      │         │   kwargs ┴ @NamedTuple{}: NamedTuple()
         │          │           │      │      dn ┼ nothing
         │          │           │      │      dt ┼ nothing
         │          │           │      │     alg ┼ nothing
         │          │           │      │   order ┴ NTuple{4, Symbol}: (:pdm, :dn, :dt, :alg)
         │          │        me ┼ SimpleExpectedReturns
         │          │           │   w ┴ nothing
         │          │   horizon ┴ nothing
         │      cle ┼ ClustersEstimator
         │          │    ce ┼ PortfolioOptimisersCovariance
         │          │       │   ce ┼ Covariance
         │          │       │      │    me ┼ SimpleExpectedReturns
         │          │       │      │       │   w ┴ nothing
         │          │       │      │    ce ┼ GeneralCovariance
         │          │       │      │       │   ce ┼ StatsBase.SimpleCovariance: StatsBase.SimpleCovariance(true)
         │          │       │      │       │    w ┴ nothing
         │          │       │      │   alg ┴ Full()
         │          │       │   mp ┼ MatrixProcessing
         │          │       │      │     pdm ┼ Posdef
         │          │       │      │         │      alg ┼ UnionAll: NearestCorrelationMatrix.Newton
         │          │       │      │         │   kwargs ┴ @NamedTuple{}: NamedTuple()
         │          │       │      │      dn ┼ nothing
         │          │       │      │      dt ┼ nothing
         │          │       │      │     alg ┼ nothing
         │          │       │      │   order ┴ NTuple{4, Symbol}: (:pdm, :dn, :dt, :alg)
         │          │    de ┼ Distance
         │          │       │   power ┼ nothing
         │          │       │     alg ┴ CanonicalDistance()
         │          │   alg ┼ HClustAlgorithm
         │          │       │   linkage ┴ Symbol: :ward
         │          │   onc ┼ OptimalNumberClusters
         │          │       │   max_k ┼ nothing
         │          │       │     alg ┼ SecondOrderDifference
         │          │       │         │   alg ┼ StandardisedValue
         │          │       │         │       │   mv ┼ MeanValue
         │          │       │         │       │      │   w ┴ nothing
         │          │       │         │       │   sv ┼ StdValue
         │          │       │         │       │      │           w ┼ nothing
         │          │       │         │       │      │   corrected ┴ Bool: true
         │      slv ┼ nothing
         │       wb ┼ WeightBounds
         │          │   lb ┼ Float64: 0.0
         │          │   ub ┴ Float64: 1.0
         │     fees ┼ nothing
         │     sets ┼ nothing
         │       wf ┼ IterativeWeightFinaliser
         │          │   iter ┴ Int64: 100
         │      brt ┼ Bool: false
         │   cle_pr ┼ Bool: true
         │   strict ┴ Bool: false
  params ┼ SchurComplementParams
         │       r ┼ Variance
         │         │   settings ┼ RiskMeasureSettings
         │         │            │   scale ┼ Float64: 1.0
         │         │            │      ub ┼ nothing
         │         │            │     rke ┴ Bool: true
         │         │      sigma ┼ nothing
         │         │       chol ┼ nothing
         │         │         rc ┼ nothing
         │         │        alg ┴ SquaredSOCRiskExpr()
         │   gamma ┼ Float64: 0.5
         │     pdm ┼ Posdef
         │         │      alg ┼ UnionAll: NearestCorrelationMatrix.Newton
         │         │   kwargs ┴ @NamedTuple{}: NamedTuple()
         │     alg ┼ MonotonicSchurComplement
         │         │        N ┼ Int64: 10
         │         │      tol ┼ Float64: 0.0001
         │         │     iter ┼ nothing
         │         │   strict ┴ Bool: false
         │    flag ┴ Bool: true
      fb ┴ nothing

Mathematical definition

When splitting cluster C with sub-clusters C1 and C2, the Schur complement of the covariance partitioned as ΣC=(Σ11Σ12Σ21Σ22) is:

S(Σ11)=Σ22Σ21Σ111Σ12.

Where:

  • S(Σ11): Schur complement of the covariance block Σ11.

  • Σ11, Σ12, Σ21, Σ22: Covariance sub-blocks corresponding to the partition of cluster C into C1 and C2.

The bisection weight α is then computed from the Schur-complement-corrected inter-cluster risks of C1 and C2, yielding a more accurate decomposition than vanilla HRP.

Related

source
PortfolioOptimisers.needs_previous_weights Method
julia
needs_previous_weights(
    opt::SchurComplementHierarchicalRiskParity
) -> Any

Return whether the SchurComplementHierarchicalRiskParity requires previous portfolio weights.

Related

source
PortfolioOptimisers.port_opt_view Method
julia
port_opt_view(
    sh::SchurComplementHierarchicalRiskParity,
    i,
    X::AbstractMatrix{<:Union{var"#s20", var"#s19"} where {var"#s20"<:Number, var"#s19"<:AbstractJuMPScalar}},
    args...
) -> SchurComplementHierarchicalRiskParity

Return a view of SchurComplementHierarchicalRiskParity sh sliced to asset indices i.

Related

source
PortfolioOptimisers.optimise Function
julia
optimise(sh::SchurComplementHierarchicalRiskParity{<:Any, <:Any, Nothing},
         rd::ReturnsResult = ReturnsResult(); dims::Int = 1, kwargs...) -> SchurComplementHierarchicalRiskParityResult

Run the Schur Complement Hierarchical Risk Parity portfolio optimisation.

Arguments

  • sh: The Schur complement hierarchical risk parity optimiser to use.

  • rd: The returns result to use. If isa(sh.opt.pe, AbstractPriorResult), rd is not necessary if doing a standalone optimisation, but may be required/desired by fallbacks and/or clusterisation.

  • dims: The dimension along which observations advance in time.

  • kwargs: Additional keyword arguments passed to the optimisation function.

Related

source