Investable universe

PortfolioOptimisers.optimise — Method
optimise(opt::OptimisationEstimator, args...; kwargs...) -> OptimisationResult
optimise(opt::OptimisationResult, args...; kwargs...) -> OptimisationResult

Run a portfolio optimisation with the estimator opt, and return an OptimisationResult.

When the solve of opt returns an OptimisationFailure, the fallback in opt.fb runs next, and the chain continues until one attempt succeeds or no fallback is left. A fallback can also be a precomputed result, which is then the answer.

A result passed as opt is returned unchanged.

Arguments

  • opt: Optimisation estimator (for example a JuMPOptimisationEstimator subtype), or a result to pass through.
  • args: Positional arguments forwarded to the solve of the estimator, usually the ReturnsResult. A result ignores them.
  • kwargs: Keyword arguments forwarded to the solve of the estimator. A result ignores them.

Returns

Related

source
PortfolioOptimisers.optimise — Method
optimise(
    opt::OptimisationEstimator,
    args...;
    kwargs...
) -> Union{HierarchicalRiskParityResult{HierarchicalResult{__T_pr, __T_clr, __T_wb, __T_fees, __T_retcode, __T_w, __T_imsk}, <:AbstractBaseRiskMeasure, <:Scalariser, Nothing} where {__T_pr, __T_clr, __T_wb, __T_fees, __T_retcode, __T_w, __T_imsk}, HierarchicalRiskParityResult{HierarchicalResult{__T_pr, __T_clr, __T_wb, __T_fees, __T_retcode, __T_w, __T_imsk}, <:AbstractVector{var"#s7444"}, <:Scalariser, Nothing} where {__T_pr, __T_clr, __T_wb, __T_fees, __T_retcode, __T_w, __T_imsk, var"#s7444"<:AbstractBaseRiskMeasure}}

Solve an optimisation estimator, and walk its fallback chain when a solve fails.

The answer is the first attempt that succeeds, or the last failure when every attempt fails. The fb field of that answer records the (estimator, result) pair of each failed attempt, in the order they ran (see FbChain). When no fallback was needed, fb is nothing. A fallback that is a precomputed result ends the chain: it has nothing to solve, and it is the answer whatever its return code.

This is a fold-less entry point, so a time-dependent schedule has no fold to select an entry from. The estimator is reset to its fold-less values before the solve (see reset_time_dependent_estimator). A scheduled fallback resets to its default, or to nothing when it has none, before the chain is walked. Inside a fold loop the reset changes nothing, because the loop resolves every schedule before it optimises.

It is a batch fit, so assert_batch_entry refuses an Online anywhere in the tree of the estimator before any solve. The wrapper resolves only at the warm-up of the online arm of the fold loop, and a plain optimise runs no warm-up. The read-out of a stepped estimator, optimise(opt), never meets this refusal, because the warm-up that seeded its buffer replaced the wrapper.

Algorithm

  1. Refuse an Online in the tree of opt with assert_batch_entry.
  2. Reset every time-dependent schedule of opt to its fold-less value with reset_time_dependent_estimator, giving current_opt.
  3. Solve current_opt with _optimise, giving res. A precomputed result gives itself.
  4. Stop when res.retcode is an OptimisationSuccess, when current_opt is a precomputed result, or when current_opt.fb is nothing.
  5. Otherwise record (current_opt, res) in the chain fb, take current_opt.fb as the new current_opt, warn that the fallback runs, and return to step 3.
  6. Return res when fb is empty. Otherwise return res rebuilt with fb through factory.

Arguments

  • opt::OptimisationEstimator: The optimisation estimator to use.
  • args: Additional positional arguments passed to the optimisation function.
  • kwargs: Additional keyword arguments passed to the optimisation function.

Validation

  • No field in the tree of opt holds an Online. An ArgumentError naming the field is thrown otherwise.

Returns

  • res::OptimisationResult: The answer of the chain, carrying the failed attempts in fb.

Related

source
PortfolioOptimisers._optimise — Function
_optimise(opt, args...; kwargs...)

Solve one optimisation estimator once, with no fallback.

optimise calls it for each attempt of the fallback chain, and it is the method that a new optimisation estimator writes. Each estimator type writes its own method, and the method returns the result type of that estimator. A precomputed result in the chain answers itself, because it has nothing to solve.

Arguments

  • opt: Optimisation estimator (for example MeanRisk or RiskBudgeting), or a precomputed result.
  • args: The data that the estimator solves over: a ReturnsResult for a continuous optimiser, or a FiniteAllocationInput for a finite allocator.
  • kwargs: The keyword arguments that the estimator reads. A JuMP head reads str_names and save, which name the model variables and keep the model on the result. Every method ignores the keywords it does not read. No method reads dims, because a ReturnsResult holds its observations along the rows.

Returns

  • res::OptimisationResult: The result of the estimator. Its retcode decides whether optimise runs the fallback.

Related

source
PortfolioOptimisers.optimise — Method
optimise(
    td::Union{TimeDependent{<:AbstractVector{<:Union{var"#s7444", var"#s7443"} where {var"#s7444"<:NonFiniteAllocationOptimisationEstimator, var"#s7443"<:NonFiniteAllocationOptimisationResult}}}, TimeDependent{<:TimeDependentOptimiserCallable}, TimeDependent{<:PreviousWeightsFunction}, TimeDependent{<:Union{Function, Type}}},
    args...;
    kwargs...
) -> Any

Optimise with a TimeDependent schedule standing in for the optimiser, outside any fold loop.

There are no folds to index, so the schedule resolves to its default, and that optimiser runs (see reset_time_dependent_estimator). A fold loop never reaches this method, because the loop resolves the entry of each fold first.

Validation

Related

source
PortfolioOptimisers.port_opt_view — Method
port_opt_view(opt::AbstractOptimisationEstimator, i, args...) -> AbstractOptimisationEstimator

Return an optimisation estimator unchanged under an asset-subset view.

This is the fallback for an optimisation estimator with no view method of its own. An estimator declared through @propagatable gets a generated method that views each asset-indexed field it carries, and a head such as JuMPOptimiser writes its own. This method serves the rest, so an asset-indexed field of such an estimator keeps the width of the full universe.

Arguments

  • opt: The optimisation estimator.
  • i: The asset index of the subset: an asset subset of a fold, a cluster of a nested optimisation, or the Investable Mask.
  • args...: Ignored. A caller that views a tracking estimator passes the unreduced returns matrix here.

Returns

  • opt: The estimator, unchanged.

Related

source
PortfolioOptimisers.port_opt_view — Method
port_opt_view(
    res::NonFiniteAllocationOptimisationResult,
    _::Colon,
    args...
) -> NonFiniteAllocationOptimisationResult

A precomputed optimisation result cannot be restricted to an asset subset.

Its weights were solved over the full universe, and a sub-portfolio of them has no defined meaning, so an asset-subset view of a result throws. A TimeDependent schedule that holds a result is therefore refused by asset-subsampling cross-validation (MultipleRandomised), whose fold loop views the optimiser to the asset subset of each fold before the swap. The all-assets view (Colon) passes the result through unchanged.

Validation

  • i must be Colon(). Any other index throws an ArgumentError.

Returns

  • res: The result, unchanged.

Related

source