Base clustering optimisation
PortfolioOptimisers.HierarchicalResult — Type
struct HierarchicalResult{__T_pr, __T_clr, __T_wb, __T_fees, __T_retcode, __T_w, __T_imsk} <: BaseHierarchicalOptimisationResultShared 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 vectorassets × 1.
imsk: The Investable Mask the optimisation reduced on:trueat every asset whose prior moments were finite. It isnothingwhen every asset was investable, and that sentinel is what skips both the reduction and the expansion.investable_maskderives 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) -> HierarchicalResultKeywords 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
PortfolioOptimisers.HierarchicalRiskParityResult — Type
struct HierarchicalRiskParityResult{__T_hr, __T_r, __T_sca, __T_fb} <: HierarchicalOptimisationResultResult 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
hr: Shared hierarchical result core, seeHierarchicalResult.
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 asexpected_risk(res.r, res.w, res.pr; sca = res.sca).
sca: The scalariser the optimisation ran under, taken fromopt.sca. Pass it back asexpected_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 attemptoptimisemade before this one, in the order they ran, ornothingwhen the estimator it was asked of answered (seeFbChain).
Constructors
HierarchicalRiskParityResult(; hr::HierarchicalResult, r::BaseRM_VecBaseRM, sca::Scalariser, fb::Option{<:OptE_Opt_FbChain}) -> HierarchicalRiskParityResultKeywords correspond to the struct's fields.
Related
PortfolioOptimisers.HierarchicalEqualRiskContributionResult — Type
struct HierarchicalEqualRiskContributionResult{__T_hr, __T_ri, __T_ro, __T_scai, __T_scao, __T_fb} <: HierarchicalOptimisationResultResult 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
hr: Shared hierarchical result core, seeHierarchicalResult.
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 attemptoptimisemade before this one, in the order they ran, ornothingwhen the estimator it was asked of answered (seeFbChain).
Constructors
HierarchicalEqualRiskContributionResult(; hr::HierarchicalResult, ri::BaseRM_VecBaseRM, ro::BaseRM_VecBaseRM, scai::Scalariser, scao::Scalariser, fb::Option{<:OptE_Opt_FbChain}) -> HierarchicalEqualRiskContributionResultKeywords correspond to the struct's fields.
Related
PortfolioOptimisers.HierarchicalOptimiser — Type
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} <: BaseClusteringOptimisationEstimatorBase 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::priortakes the prior result'sX,:datatakes the raw returns result'sX. Ignored when no returns result is available, in which case the prior result'sXis used.
strict: Whether to strictly enforce weight bounds.
cache: OptionalReturnsBufferState, the fold context of the online step. It isnothinguntilpartial_fit!writes one, andoptimise(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.factorycarries it unchanged andport_opt_viewslices 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) -> HierarchicalOptimiserKeywords 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
wbis aWeightBoundsEstimator:!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 viafactory.
View parameters
When port_opt_view is called on this type, the following @vprop-tagged fields are automatically subset to the selected indices:
pe: Recursively viewed viaport_opt_view.wb: Recursively viewed viaport_opt_view.fees: Recursively viewed viaport_opt_view.sets: Sliced to the selected indices viaport_opt_view.
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: falseRelated
PortfolioOptimisers.factory — Method
factory(a::Union{Nothing, <:AbstractEstimator, <:AbstractAlgorithm,
<:AbstractResult}, args...; kwargs...) -> a
factory(a::AbstractVector{<:Union{Nothing, <:AbstractEstimator, <:AbstractAlgorithm,
<:AbstractResult}}, args...; kwargs...) -> VectorNo-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:
- Return
aunchanged, and dropargs...andkwargs.... 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:
- For each element
aiofa, callfactoryonai, and forwardargs...andkwargs...unchanged. - 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 ┴ nothingRelated
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
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
PortfolioOptimisers.factory — Method
factory(a::Union{Nothing, <:AbstractEstimator, <:AbstractAlgorithm,
<:AbstractResult}, args...; kwargs...) -> a
factory(a::AbstractVector{<:Union{Nothing, <:AbstractEstimator, <:AbstractAlgorithm,
<:AbstractResult}}, args...; kwargs...) -> VectorNo-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:
- Return
aunchanged, and dropargs...andkwargs.... 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:
- For each element
aiofa, callfactoryonai, and forwardargs...andkwargs...unchanged. - 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 ┴ nothingRelated
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
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
PortfolioOptimisers.BaseHierarchicalOptimisationResult — Type
abstract type BaseHierarchicalOptimisationResult <: AbstractResultAbstract 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
PortfolioOptimisers.HierarchicalOptimisationResult — Type
abstract type HierarchicalOptimisationResult <: NonJuMPOptimisationResultAbstract 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
PortfolioOptimisers.needs_previous_weights — Method
needs_previous_weights(opt::HierarchicalOptimiser) -> Any
Return whether the HierarchicalOptimiser requires previous portfolio weights (based on fee structure and time-dependent constraints).
Related