Base clustering optimisation

PortfolioOptimisers.HierarchicalResultType
struct HierarchicalResult{__T_pr, __T_clr, __T_wb, __T_fees, __T_retcode, __T_w, __T_imsk} <: BaseHierarchicalOptimisationResult

Shared field core for hierarchical (clustering-based) optimisation results.

Holds the fields common to HierarchicalRiskParityResult and HierarchicalEqualRiskContributionResult, and is embedded as the first field (hr) of each — analogous to how JuMPOptimisationResult is embedded as jr on the JuMP side. Each leaf keeps only the measures and scalarisers its own estimator carries, plus the trailing fb.

The core carries no fb

fb is fixed as the last field of each concrete result and kept out of the core, because every optimisation result already ends in fb. Both leaves end in fb, so the one generic factory(res, fb) rebuilds them by the same convention and needs no change. The core sits off AbstractResult's optimisation branch, so that generic never reaches it.

Fields

  • pr: Prior result.
  • clr: Clusters result.
  • wb: Weight bounds.
  • fees: Fees estimator or result.
  • retcode: Optimisation return code.
  • w: Portfolio weights vector assets × 1.
  • imsk: The Investable Mask the optimisation reduced on: true at every asset whose prior moments were finite. It is nothing when every asset was investable, and that sentinel is what skips both the reduction and the expansion. investable_mask derives it once from the full-universe prior result, and the result carries it, because the reduced prior can no longer yield it.

Constructors

HierarchicalResult(;    pr::Option{<:AbstractPriorResult},    clr::Option{<:AbstractClusteringResult},    wb::Option{<:WeightBounds},    fees::Option{<:Fees},    retcode::OptimisationReturnCode,    w::Option{<:VecNum},    imsk::Option{<:BitVector} = nothing) -> HierarchicalResult

Keywords correspond to the struct's fields.

The keyword constructor is the one door a hierarchical _optimise exits through, so it is where the solved weights expand back onto the full asset universe, through expand_investable_weights. The positional constructor never expands: every retcode rebuild goes through it, and a second pass would expand twice.

Related

source
PortfolioOptimisers.HierarchicalRiskParityResultType
struct HierarchicalRiskParityResult{__T_hr, __T_r, __T_sca, __T_fb} <: HierarchicalOptimisationResult

Result type for HierarchicalRiskParity.

Carries the shared core as hr, plus the one measure and the one scalariser its estimator holds, both stored resolved.

Every property of the core forwards through this type, so res.w, res.pr, res.clr, res.wb, res.fees and res.retcode read as if the fields were flat.

Fields

  • r: The risk measure the optimisation ran under, or a vector of them, stored resolved — a Deferred Quantity has already been fitted and an unstated slot has already taken the prior's field. A resolved measure is fitted state, not configuration, so it belongs on the Result. Pass it back as expected_risk(res.r, res.w, res.pr; sca = res.sca).
  • sca: The scalariser the optimisation ran under, taken from opt.sca. Pass it back as expected_risk(res.r, res.w, res.pr; sca = res.sca) so the reported figure matches the optimised one.
  • fb: The fallback chain that answered this result: the (estimator, result) pair of every attempt optimise made before this one, in the order they ran, or nothing when the estimator it was asked of answered (see FbChain).

Constructors

HierarchicalRiskParityResult(;    hr::HierarchicalResult,    r::BaseRM_VecBaseRM,    sca::Scalariser,    fb::Option{<:OptE_Opt_FbChain}) -> HierarchicalRiskParityResult

Keywords correspond to the struct's fields.

Related

source
PortfolioOptimisers.HierarchicalEqualRiskContributionResultType
struct HierarchicalEqualRiskContributionResult{__T_hr, __T_ri, __T_ro, __T_scai, __T_scao, __T_fb} <: HierarchicalOptimisationResult

Result type for HierarchicalEqualRiskContribution.

Carries the shared core as hr, plus the two measures and two scalarisers its estimator holds — the intra-cluster pair and the inter-cluster pair — all stored resolved.

The differing arity against HierarchicalRiskParityResult is why the shared HierarchicalResult split into two leaves rather than growing Option slots or union-typed fields.

Every property of the core forwards through this type, so res.w, res.pr, res.clr, res.wb, res.fees and res.retcode read as if the fields were flat.

Fields

  • ri: The intra-cluster risk measure the optimisation ran under, or a vector of them, stored resolved.
  • ro: The inter-cluster risk measure the optimisation ran under, or a vector of them, stored resolved.
  • scai: Inner scalariser.
  • scao: Outer scalariser.
  • fb: The fallback chain that answered this result: the (estimator, result) pair of every attempt optimise made before this one, in the order they ran, or nothing when the estimator it was asked of answered (see FbChain).

Constructors

HierarchicalEqualRiskContributionResult(;    hr::HierarchicalResult,    ri::BaseRM_VecBaseRM,    ro::BaseRM_VecBaseRM,    scai::Scalariser,    scao::Scalariser,    fb::Option{<:OptE_Opt_FbChain}) -> HierarchicalEqualRiskContributionResult

Keywords correspond to the struct's fields.

Related

source
PortfolioOptimisers.HierarchicalOptimiserType
struct HierarchicalOptimiser{__T_pe, __T_cle, __T_slv, __T_wb, __T_fees, __T_sets, __T_wf, __T_brt, __T_x_src, __T_strict, __T_cache} <: BaseClusteringOptimisationEstimator

Base configuration for hierarchical clustering-based portfolio optimisers.

HierarchicalOptimiser combines a prior estimator, a clustering estimator, and weight bound/fee specifications to provide a reusable base configuration for hierarchical optimisers (HRP, HERC, SCHRP, etc.).

Fields

  • pe: Prior estimator.
  • cle: Clusters estimator.
  • slv: Solver or vector of solvers.
  • wb: Weight bounds.
  • fees: Fees estimator or result.
  • sets: Sets used to map estimator values to assets.
  • wf: Weight finaliser.
  • brt: Whether to use bootstrap returns.
  • x_src: Which returns matrix the clustering, phylogeny and centrality estimators read: :prior takes the prior result's X, :data takes the raw returns result's X. Ignored when no returns result is available, in which case the prior result's X is used.
  • strict: Whether to strictly enforce weight bounds.
  • cache: Optional ReturnsBufferState, the fold context of the online step. It is nothing until partial_fit! writes one, and optimise(opt) with no returns reads it. The returns themselves are carried by the prior, which owns the rows once; this holds every other column of the carrier and the context pinned at the first step. factory carries it unchanged and port_opt_view slices it to the selected assets.

Constructors

HierarchicalOptimiser(;    pe::Onl{<:TD{<:PrE_Pr}} = EmpiricalPrior(),    cle::TD{<:HClE_HCl} = ClustersEstimator(),    slv::Option{<:Slv_VecSlv} = nothing,    wb::TD_Option{<:WbE_Wb} = WeightBounds(),    fees::TD_Option{<:FeesE_Fees} = nothing,    sets::TD_Option{<:UniverseSets} = nothing,    wf::TD{<:WeightFinaliser} = IterativeWeightFinaliser(),    brt::Bool = false,    x_src::Symbol = :prior,    strict::Bool = false,    cache::Option{<:ReturnsBufferState} = nothing) -> HierarchicalOptimiser

Keywords correspond to the struct's fields. Fields typed TD_Option or TD may hold a TimeDependent per-fold schedule instead of a static value; a cross-validation fold loop resolves it per fold, and a fold-less optimise runs with the field at its static default. The problem definition — the prior estimator, clustering estimator, weight finaliser and asset sets as much as the bounds and fees — may therefore vary over folds; execution control (slv, brt, x_src, strict) stays static.

Validation

  • x_src in (:prior, :data).
  • If wb is a WeightBoundsEstimator: !isnothing(sets).
  • If any field holds a TimeDependent: every vector entry is test-substituted through this constructor so type compatibility errors surface immediately.

Propagated parameters

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

  • fees: Recursively updated via factory.

View parameters

When port_opt_view is called on this type, the following @vprop-tagged fields are automatically subset to the selected indices:

Examples

julia> HierarchicalOptimiser()HierarchicalOptimiser      pe ┼ EmpiricalPrior         │           ce ┼ PortfolioOptimisersCovariance         │              │   ce ┼ Covariance         │              │      │    me ┼ SimpleExpectedReturns         │              │      │       │   w ┴ nothing         │              │      │    ce ┼ GeneralCovariance         │              │      │       │   ce ┼ StatsBase.SimpleCovariance: StatsBase.SimpleCovariance(true)         │              │      │       │    w ┴ nothing         │              │      │   alg ┼ FullMoment()         │              │      │     w ┴ nothing         │              │   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         │   fill_limit ┴ nothing     cle ┼ ClustersEstimator         │    ce ┼ PortfolioOptimisersCovariance         │       │   ce ┼ Covariance         │       │      │    me ┼ SimpleExpectedReturns         │       │      │       │   w ┴ nothing         │       │      │    ce ┼ GeneralCovariance         │       │      │       │   ce ┼ StatsBase.SimpleCovariance: StatsBase.SimpleCovariance(true)         │       │      │       │    w ┴ nothing         │       │      │   alg ┼ FullMoment()         │       │      │     w ┴ nothing         │       │   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   x_src ┼ Symbol: :prior  strict ┴ Bool: false

Related

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

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.

factory and port_opt_view are the two propagation mechanisms in this library. They are duals: factory threads runtime values (prior moments, observation weights, previous portfolio weights) down through a composed struct tree; port_opt_view threads an index selection (a subset of assets or observations) down through the same tree.

The vector method is the one forwarding contract for every vector-valued propagation field: it applies factory to each element and forwards args... and kwargs... unchanged, so a family that admits a vector of estimators, algorithms, or results needs no method of its own. A family that needs more than the forward, such as a concrete element type (concrete_typed_array_if_abstract), defines its own more specific method.

Algorithm

The scalar method:

  1. Return a unchanged, and drop args... and kwargs.... This method is the leaf of the recursion, and it is what makes an untagged type safe to call the verb on.

The vector method:

  1. For each element ai of a, call factory on ai, and forward args... and kwargs... unchanged.
  2. Collect the results into a new vector, in the order of a, and return it.

A @propagatable struct with at least one @fprop- or @wprop-tagged field carries a generated method that dominates the scalar method. That method rebuilds the struct with its keyword constructor, sending each @fprop field through factory_child and each @wprop field through _wprop.

Arguments

  • a: Indicates no object should be constructed, or a vector whose elements are rebuilt one by one.
  • args...: Arbitrary positional arguments (ignored by the scalar method, forwarded by the vector method).
  • kwargs...: Arbitrary keyword arguments (ignored by the scalar method, forwarded by the vector method).

Returns

  • a: The input unchanged.
  • v::Vector: The element-wise rebuilds, for the vector method.

Examples

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

Related

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

Rebuild a continuous optimisation result with an updated fallback record 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. optimise is the one caller, and it hands in the FbChain it walked.

Related

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

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.factoryMethod
factory(a::Union{Nothing, <:AbstractEstimator, <:AbstractAlgorithm,
                 <:AbstractResult}, args...; kwargs...) -> a
factory(a::AbstractVector{<:Union{Nothing, <:AbstractEstimator, <:AbstractAlgorithm,
                                  <:AbstractResult}}, args...; kwargs...) -> Vector

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.

factory and port_opt_view are the two propagation mechanisms in this library. They are duals: factory threads runtime values (prior moments, observation weights, previous portfolio weights) down through a composed struct tree; port_opt_view threads an index selection (a subset of assets or observations) down through the same tree.

The vector method is the one forwarding contract for every vector-valued propagation field: it applies factory to each element and forwards args... and kwargs... unchanged, so a family that admits a vector of estimators, algorithms, or results needs no method of its own. A family that needs more than the forward, such as a concrete element type (concrete_typed_array_if_abstract), defines its own more specific method.

Algorithm

The scalar method:

  1. Return a unchanged, and drop args... and kwargs.... This method is the leaf of the recursion, and it is what makes an untagged type safe to call the verb on.

The vector method:

  1. For each element ai of a, call factory on ai, and forward args... and kwargs... unchanged.
  2. Collect the results into a new vector, in the order of a, and return it.

A @propagatable struct with at least one @fprop- or @wprop-tagged field carries a generated method that dominates the scalar method. That method rebuilds the struct with its keyword constructor, sending each @fprop field through factory_child and each @wprop field through _wprop.

Arguments

  • a: Indicates no object should be constructed, or a vector whose elements are rebuilt one by one.
  • args...: Arbitrary positional arguments (ignored by the scalar method, forwarded by the vector method).
  • kwargs...: Arbitrary keyword arguments (ignored by the scalar method, forwarded by the vector method).

Returns

  • a: The input unchanged.
  • v::Vector: The element-wise rebuilds, for the vector method.

Examples

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

Related

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

Rebuild a continuous optimisation result with an updated fallback record 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. optimise is the one caller, and it hands in the FbChain it walked.

Related

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

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.BaseHierarchicalOptimisationResultType
abstract type BaseHierarchicalOptimisationResult <: AbstractResult

Abstract supertype for the core field block shared by hierarchical optimisation results.

Sits off the optimisation-result tree on purpose, exactly as BaseJuMPOptimisationResult does on the JuMP side. A core is not a thing optimise returns, so it must not satisfy methods bounded on the result family — factory(res::NonFiniteAllocationOptimisationResult, fb) included.

Its one subtype is HierarchicalResult, embedded as hr by each leaf.

Interfaces

A subtype is a field block, not a result. It declares no method, and it must not be given one that is bounded on the optimisation-result family, because the core is never what optimise returns.

Related

source
PortfolioOptimisers.HierarchicalOptimisationResultType
abstract type HierarchicalOptimisationResult <: NonJuMPOptimisationResult

Abstract supertype for the results of the estimators that embed a hierarchical optimiser.

The optimiser they embed is a HierarchicalOptimiser, held in their estimator's opt field.

The membership rule is exact: HierarchicalRiskParity, HierarchicalEqualRiskContribution and SchurComplementHierarchicalRiskParity each hold an opt::HierarchicalOptimiser. NestedClustered does not, and its result is not in this family.

The family is deliberately not called ClusteringOptimisationResult: ClusteringOptimisationEstimator has four subtypes and the fourth is NestedClustered, so that name would claim a set this type does not hold.

Two of the three members embed HierarchicalResult as hr; SchurComplementHierarchicalRiskParityResult keeps a flat field block, which is why the property forwarding lives on the leaves rather than here.

Interfaces

The family adds no method to NonJuMPOptimisationResult. Because the field block is not shared, a leaf that embeds HierarchicalResult declares its own property forwarding, so that the w and retcode properties OptimisationResult requires resolve through hr.

Related

source