Skip to content
18

Subset resampling

PortfolioOptimisers.BaseSubsetResamplingOptimisationEstimator Type
julia
abstract type BaseSubsetResamplingOptimisationEstimator <: NonFiniteAllocationOptimisationEstimator

Abstract supertype for subset resampling portfolio optimisation estimators.

Related Types

source
PortfolioOptimisers.SubsetResamplingResult Type
julia
struct SubsetResamplingResult{__T_pr, __T_wb, __T_fees, __T_ress, __T_idx, __T_retcode, __T_w, __T_fb} <: NonJuMPOptimisationResult

Result type for Subset Resampling portfolio optimisation.

Fields

  • pr: Prior result.

  • wb: Weight bounds.

  • fees: Fees estimator or result.

  • ress: Vector of sub-optimisation results for each subset.

  • idx: Index vector.

  • retcode: Optimisation return code.

  • w: Aggregated optimal portfolio weights.

  • fb: Fallback result or estimator.

Related

source
PortfolioOptimisers.factory Method
julia
factory(
    sr::SubsetResamplingResult,
    fb::Union{Nothing, NonFiniteAllocationOptimisationEstimator, NonFiniteAllocationOptimisationResult}
) -> SubsetResamplingResult

Rebuild a SubsetResamplingResult with an updated fallback optimiser fb.

source
PortfolioOptimisers.SubsetResampling Type
julia
struct SubsetResampling{__T_pe, __T_wb, __T_fees, __T_sets, __T_scale, __T_opt, __T_wf, __T_ex, __T_subset_size, __T_n_subsets, __T_max_comb, __T_rng, __T_seed, __T_fb, __T_brt, __T_strict} <: BaseSubsetResamplingOptimisationEstimator

Subset Resampling portfolio optimiser.

SubsetResampling applies a resampling strategy by optimising a base optimiser (opt) over randomly drawn subsets of assets, then aggregating the results into a final portfolio weight vector. This improves robustness of portfolio weights to estimation error.

Fields

  • pe: Prior estimator.

  • wb: Weight bounds estimator or weight bounds.

  • fees: Fees estimator.

  • sets: Sets used to map estimator values to features.

  • scale: Optional scaling vector for subset optimiser weights.

  • opt: Base portfolio optimiser applied to each asset subset.

  • wf: Weight finaliser.

  • ex: Parallel execution strategy.

  • subset_size: Size of each random subset.

  • n_subsets: Number of random subsets.

  • max_comb: Maximum number of unique asset subsets.

  • rng: Random number generator.

  • seed: Seed for the random number generator.

  • fb: Fallback result or estimator.

  • brt: Whether to use bootstrap returns.

  • strict: Whether to strictly enforce weight bounds.

Constructors

julia
SubsetResampling(;
    pe::TD{<:PrE_Pr} = EmpiricalPrior(),
    wb::TD_Option{<:WbE_Wb} = nothing,
    fees::TD_Option{<:FeesE_Fees} = nothing,
    sets::TD_Option{<:AssetSets} = nothing,
    scale::TD_Option{<:VecNum} = nothing,
    opt::OptE_TD,
    wf::TD{<:WeightFinaliser} = IterativeWeightFinaliser(),
    ex::FLoops.Transducers.Executor = FLoops.ThreadedEx(),
    subset_size::TD{<:SubsetSizeE} = 0.5,
    n_subsets::TD{<:NumberSubsetsE} = 100,
    max_comb::Integer = 1000,
    rng::Random.AbstractRNG = Random.default_rng(),
    seed::Option{<:Integer} = nothing,
    fb::TDO_Option{<:OptE_Opt} = nothing,
    brt::Bool = false,
    strict::Bool = false
) -> SubsetResampling

Keywords correspond to the struct's fields.

Time-dependent fields

pe, wb, fees, sets, scale, opt, wf, subset_size, n_subsets and fb may hold a TimeDependent per-fold schedule. The optimiser-valued positions opt and fb are bind = :outermost only: SubsetResampling's internal loop is over randomly drawn asset subsets, not time folds, so there is no inner fold loop for a :nearest optimiser schedule to bind to and it is rejected at construction. The fold loop that reaches the SubsetResampling resolves its schedules; a fold-less solve resets pe/wf/subset_size/n_subsets to their static defaults, wb/fees/sets/scale/fb to nothing, and requires an opt schedule to carry its own default. max_comb, rng and seed are execution control and stay static.

Validation

  • If scale is provided and static: all elements must be non-empty, > 0, and finite.

  • opt must pass assert_internal_optimiser (a schedule delegates to its entries and default).

  • If wb is a WeightBoundsEstimator: !isnothing(sets).

  • If fees is a FeesEstimator: !isnothing(sets).

  • If subset_size is an Integer: subset_size >= 1.

  • If subset_size is a Float: 0 < subset_size < 1.

  • If n_subsets is an Integer: n_subsets >= 2.

  • max_comb > 0 and finite.

  • opt and fb schedules: bind !== :nearest; vector-schedule entries of every time-dependent field are validated per entry through the constructor.

Mathematical definition

Draw M random subsets S1,,SM of assets (size sN). Optimise on each:

w=1Mm=1MeSm(wSm).

Where:

  • w: Final averaged portfolio weights.

  • M: Number of random subsets.

  • Sm: m-th randomly drawn asset subset (size sN).

  • wSm: Optimal weights from the optimiser applied to subset Sm.

  • eSm(): Embedding operator that places subset weights into full N-asset space (zero-filling excluded assets).

  • N: Total number of assets.

Propagated parameters

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

  • fees: Recursively updated via factory.

  • opt: Recursively updated via factory.

  • fb: Recursively updated via factory.

Related

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

Return true if any sub-estimator of opt requires previous portfolio weights (fees, base optimiser, or fallback).

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

Return true if the base optimiser or fallback carries time-dependent constraints.

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

Replace this meta-optimiser's own time-dependent fields with their static defaults.

Deliberately does not recurse into the wrapped optimisers: a standalone meta solve consumes inner per-fold schedules through its inner cross-validation leg, and its fold-less full-window inner solves reset themselves at their own _optimise seam. Only the meta's own fields (applied to the combined weights, resolved by an outer fold loop when one exists) are inert here. A bind = :nearest schedule in a field the meta hands across its own inner fold loop (see inner_fold_fields) is likewise left in place — resetting it here would replace it with its default before the inner cross-validation ever saw it.

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(
    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.port_opt_view Method
julia
port_opt_view(
    sr::SubsetResampling,
    i,
    X::AbstractMatrix{<:Union{var"#s29", var"#s28"} where {var"#s29"<:Number, var"#s28"<:AbstractJuMPScalar}},
    args...
) -> SubsetResampling{_A, _B, _C, _D, _E, _F, _G, var"#s179", _H, _I, var"#s1791", var"#s1792", _J, _K, Bool, Bool} where {_A, _B, _C, _D, _E, _F, _G, var"#s179"<:Transducers.Executor, _H, _I, var"#s1791"<:Integer, var"#s1792"<:AbstractRNG, _J, _K}

Return a cluster-sliced copy of SubsetResampling for asset index set i and returns matrix X.

source
PortfolioOptimisers.optimise Function
julia
optimise(sr::SubsetResampling{<:Any, <:Any, <:Any, <:Any, <:Any, <:Any, <:Any,
                 <:Any, <:Any, <:Any, <:Any, <:Any, <:Any, Nothing
             }, rd::ReturnsResult;
         dims::Int = 1, branchorder::Symbol = :optimal, str_names::Bool = false,
         save::Bool = true, kwargs...) -> SubsetResamplingResult

Run the Subset Resampling portfolio optimisation.

Arguments

  • sr: The subset resampling optimiser to use.

  • rd: The returns result to use.

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

  • branchorder: Passed to the internal optimiser. The branch order to use for the clusterisation.

  • str_names: Passed to the internal optimiser. Whether to use string names for the assets in the optimisation.

  • save: Passed to the internal optimiser. Whether to save the JuMP model in the optimisation result.

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

Related

source
PortfolioOptimisers.subset_resampling_finaliser Function
julia
subset_resampling_finaliser(N, n_subsets, asset_idx, ...)

Aggregate and finalise portfolio weights from subset resampling.

Combines optimised weights from multiple asset subsets, averaging over subsets to produce the final portfolio weights.

Arguments

  • N: Total number of assets.

  • n_subsets: Number of asset subsets used in resampling.

  • asset_idx: Matrix of asset indices for each subset.

  • Additional weight and parameter inputs.

Returns

  • Final aggregated portfolio weight vector.

Related

source
PortfolioOptimisers.subset_resampling_retcode Function
julia
subset_resampling_retcode(ress::VecOpt, retcode::OptimisationReturnCode)

Aggregate the subset optimisation return codes with the weight-finalisation return code.

Returns retcode unchanged when every subset optimisation succeeded; otherwise returns an OptimisationFailure whose res is a named tuple (; msg, opti, wb) carrying the failure summary, the subset optimisation return codes, and the weight-finalisation return code (including their solver trial diagnostics).

Related

source
PortfolioOptimisers.subset_resampling_td_defaults Function
julia
subset_resampling_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}, opt::NoDefault, wf::IterativeWeightFinaliser{Int64}, subset_size::Float64, n_subsets::Int64}

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

Shared by the constructor's test-substitution pass and time_dependent_field_defaults. The optimiser-valued field opt is required and has no static default, so it is marked NoDefault: a schedule there must carry its own default to be usable outside a fold loop. pe, wf, subset_size and n_subsets reset to their keyword defaults; fields whose static default is nothing (wb, fees, sets, scale, fb) are omitted.

Related

source