Skip to content
18

Base clustering optimisation

PortfolioOptimisers.BaseClusteringOptimisationEstimator Type
julia
abstract type BaseClusteringOptimisationEstimator <: BaseOptimisationEstimator

Abstract supertype for base clustering optimisation estimators.

These are intermediate configuration types used in hierarchical/clustering optimisation pipelines.

Related

source
PortfolioOptimisers.ClusteringOptimisationEstimator Type
julia
abstract type ClusteringOptimisationEstimator <: NonFiniteAllocationOptimisationEstimator

Abstract supertype for clustering-based portfolio optimisation estimators.

Clustering optimisation estimators use asset clustering to decompose the portfolio optimisation problem. Subtypes include HRP, HERC, and SCHRP.

Related

source
PortfolioOptimisers.HierarchicalResult Type
julia
struct HierarchicalResult{__T_pr, __T_clr, __T_wb, __T_fees, __T_retcode, __T_w, __T_fb} <: NonJuMPOptimisationResult

Result type for hierarchical (clustering-based) portfolio optimisation.

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.

  • 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.

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.

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},
    _
) -> SubsetResamplingResult

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.HierarchicalOptimiser Type
julia
struct HierarchicalOptimiser{__T_pe, __T_cle, __T_slv, __T_wb, __T_fees, __T_sets, __T_wf, __T_brt, __T_cle_pr, __T_strict} <: 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 features.

  • wf: Weight finaliser.

  • brt: Whether to use bootstrap returns.

  • cle_pr: Whether to pass the prior result to the clustering estimator.

  • strict: Whether to strictly enforce weight bounds.

Constructors

julia
HierarchicalOptimiser(;
    pe::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{<:AssetSets} = nothing,
    wf::TD{<:WeightFinaliser} = IterativeWeightFinaliser(),
    brt::Bool = false,
    cle_pr::Bool = true,
    strict::Bool = false
) -> 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, cle_pr, strict) stays static.

Validation

  • If any field holds a TimeDependent: every vector entry is test-substituted through this constructor so type compatibility errors surface immediately.

Examples

julia
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()
         │           │   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 ┴ FullMoment()
         │       │   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

Related

source
PortfolioOptimisers.hierarchical_optimiser_td_defaults Function
julia
hierarchical_optimiser_td_defaults(

) -> @NamedTuple{pe::EmpiricalPrior{PortfolioOptimisersCovariance{Covariance{SimpleExpectedReturns{Nothing}, GeneralCovariance{SimpleCovariance, Nothing}, FullMoment}, MatrixProcessing{Posdef{UnionAll, @NamedTuple{}}, Nothing, Nothing, Nothing, NTuple{4, Symbol}}}, SimpleExpectedReturns{Nothing}, Nothing}, cle::ClustersEstimator{PortfolioOptimisersCovariance{Covariance{SimpleExpectedReturns{Nothing}, GeneralCovariance{SimpleCovariance, Nothing}, FullMoment}, MatrixProcessing{Posdef{UnionAll, @NamedTuple{}}, Nothing, Nothing, Nothing, NTuple{4, Symbol}}}, Distance{Nothing, CanonicalDistance}, HClustAlgorithm{Symbol}, OptimalNumberClusters{Nothing, SecondOrderDifference{StandardisedValue{MeanValue{Nothing}, StdValue{Nothing, Bool}}}}}, wb::WeightBounds{Float64, Float64}, wf::IterativeWeightFinaliser{Int64}}

Return the static defaults of the HierarchicalOptimiser fields that may hold a TimeDependent.

Shared by the constructor's test-substitution pass and time_dependent_field_defaults, so the fold-less value of a field is declared once. Fields whose static default is nothing are omitted.

Related

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

Return whether the HierarchicalOptimiser requires previous portfolio weights (based on fee structure and time-dependent constraints).

Related

source
PortfolioOptimisers.is_time_dependent Method
julia
is_time_dependent(
    opt::ClusteringOptimisationEstimator
) -> Any

Return true if the estimator's own problem-definition fields, the inner optimiser, or the fallback carry time-dependent constraints.

source
PortfolioOptimisers.reset_time_dependent_estimator Method
julia
reset_time_dependent_estimator(
    opt::ClusteringOptimisationEstimator
) -> NestedClustered

Replace time-dependent constraints with their static defaults, both on the estimator's own fields and by recursing into the inner optimiser and fallback.

NestedClustered overrides this with its own method resetting its own fields and inner estimators.

source
PortfolioOptimisers.assert_internal_optimiser Method
julia
assert_internal_optimiser(opt)

Assert that the inner (cluster-level) optimiser is valid for use in NCO.

Checks that the inner optimiser does not use pre-computed prior results or regression results, since these must be re-estimated for each cluster during NCO.

Arguments

  • opt: Inner optimisation estimator.

Returns

  • nothing on success; throws ArgCheck error otherwise.

Related

source
PortfolioOptimisers.unitary_expected_risks Method
julia
unitary_expected_risks(r, X, ...)

Compute the expected risk for unitary (equal-weight) portfolios within each cluster.

Returns a vector of risk values, one per cluster, where each risk is computed for the equal-weight portfolio within that cluster.

Arguments

  • r: Risk measure.

  • X: Asset return matrix.

  • Additional cluster and weight parameters.

Returns

  • Vector of expected risk values per cluster.

Related

source
PortfolioOptimisers.unitary_expected_risks! Method
julia
unitary_expected_risks!(wk, rk, r, ...)

Compute and store the expected risk for each cluster's unitary portfolio in-place.

Fills rk with the expected risk for the equal-weight portfolio within each cluster, and wk with the corresponding weights.

Arguments

  • wk: Output weight vector (in-place).

  • rk: Output risk vector (in-place).

  • r: Risk measure.

  • Additional cluster and weight parameters.

Returns

  • nothing (fills wk and rk in-place).

Related

source