Near optimal centering: private API

PortfolioOptimisers.NearOptimalSetupType
struct NearOptimalSetup{__T_w_opt, __T_rk_opt, __T_rt_opt, __T_rt_min, __T_rt_max, __T_rt_ends, __T_w_min, __T_w_max, __T_r, __T_opt, __T_attrs, __T_w_min_retcode, __T_w_opt_retcode, __T_w_max_retcode} <: AbstractResult

Intermediate result type storing the setup data for Near Optimal Centering.

Holds pre-computed portfolio weights, risk and return targets, and sub-problem return codes needed to formulate and solve the NOC optimisation problem.

Fields

  • w_opt: Optimal portfolio weights.
  • rk_opt: Optimal risk target.
  • rt_opt: Optimal return target.
  • rt_min: Minimum return target.
  • rt_max: Maximum return target.
  • rt_ends: Per-term return spans for a return-frontier sweep, as i => (rt_min_i, rt_max_i) pairs, or nothing when no return term declares a frontier bound. The aggregate rt_min/rt_max pair above serves the barrier; these serve the sweep, and the two are different quantities because a term's own span must be read off a portfolio that maximised that term alone.
  • w_min: Minimum risk portfolio weights.
  • w_max: Maximum return portfolio weights.
  • r: Risk measure or vector of risk measures.
  • opt: JuMP optimiser configuration.
  • attrs: Processed JuMP optimiser attributes for the model-assembly pipeline.
  • w_min_retcode: Return code for the minimum-risk sub-problem.
  • w_opt_retcode: Return code for the optimal-objective sub-problem.
  • w_max_retcode: Return code for the maximum-risk sub-problem.

Related

source
PortfolioOptimisers.near_optimal_centering_td_defaultsFunction
near_optimal_centering_td_defaults(

) -> @NamedTuple{r::StandardDeviation{RiskMeasureSettings{Float64, Nothing, Bool}, Nothing, Nothing}, obj::MinimumRisk}

Return the static defaults of the NearOptimalCentering 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.near_optimal_centering_risksFunction
near_optimal_centering_risks(scalariser, r, pr, fees, slv, w_min, w_opt, w_max)

Compute the scaled risk values for the minimum, optimal, and maximum portfolios.

Used internally by Near Optimal Centering to evaluate the risk at the three anchor portfolios (minimum-risk, optimal, maximum-risk) using the given risk measure(s) and scalarisation strategy.

Arguments

  • scalariser: Risk scalarisation strategy (e.g. SumScalariser, LogSumExpScalariser).
  • r: Risk measure or vector of risk measures.
  • pr: Prior result containing asset data.
  • fees: Optional fees configuration.
  • slv: Solver or vector of solvers.
  • w_min: Minimum-risk portfolio weights.
  • w_opt: Optimal portfolio weights (vector or vector of vectors).
  • w_max: Maximum-risk portfolio weights.

Returns

  • (risk_min, risk_opt, risk_max): Tuple of risk values at the three anchor portfolios.

Related

source
PortfolioOptimisers.near_optimal_centering_setupFunction
near_optimal_centering_setup(noc::NearOptimalCentering, rd::ReturnsResult; dims::Int = 1)

Compute all prerequisite data for Near Optimal Centering.

Solves the minimum-risk, optimal-objective, and maximum-risk sub-problems (unless pre-computed weights are provided), then computes the risk and return targets for the NOC problem.

Arguments

  • noc::NearOptimalCentering: NOC estimator configuration.
  • rd::ReturnsResult: Returns data.
  • dims::Int: Observation dimension (default 1).

Returns

Related

source
PortfolioOptimisers.return_term_endsFunction
return_term_ends(swept, ret, nb_r, nb_opt, rd, pr, fees, w_min, w_ini)

Solve one maximum-return corner per swept return term and read off that term's span.

The low end of every span is the shared minimum-risk portfolio w_min, which near_optimal_centering_setup already has. The high end of term i's span comes from a portfolio that maximised term i alone, which is why this costs k extra solves. Reading it off the aggregate maximum-return corner instead would make the span an artefact of the other terms' scale, and can leave rt_min > rt_max.

Returns

  • A vector of i => (rt_min_i, rt_max_i) pairs, one per swept term.

Related

source
PortfolioOptimisers.set_near_optimal_centering_constraints!Function
set_near_optimal_centering_constraints!(model::JuMP.Model, wb::WeightBounds)

Add Near Optimal Centering logarithmic barrier constraints to the JuMP model.

Introduces log variables for portfolio weights, upper bound distances, risk, and return, then adds exponential cone constraints implementing the analytic centre formulation.

Arguments

  • model::JuMP.Model: JuMP optimisation model.
  • wb::WeightBounds: Weight bounds configuration.

Returns

  • Objective expression for the NOC barrier function.

Related

source
PortfolioOptimisers.set_near_optimal_objective_function!Function
set_near_optimal_objective_function!(alg, model, noc, attrs)

Set the Near Optimal Centering objective function in the JuMP model.

Formulates the NOC objective based on the algorithm variant. For UnconstrainedNearOptimalCentering, uses only the barrier function. For ConstrainedNearOptimalCentering, also adds objective penalties and custom objective terms.

The centring problem is a distance minimisation, so the objective it reports to a custom term is MinimumRisk — the objective actually being built, not noc.obj, which describes the reference-point sub-problems.

The unconstrained variant reaches neither add_custom_objective_term! nor add_penalty_to_objective!, so opt.cobj prices the anchor sub-problems and not the centring solve. No builder on that path contributes to the Objective Penalty either, so the accumulator is empty and the omitted fold changes no number today. The one case a user can observe is a Custom Objective Term that names itself and supplies no builder: it raises on the anchor solve, and raises nowhere when w_min, w_opt and w_max are all supplied and no anchor solve runs.

Arguments

  • alg: NOC algorithm variant (UnconstrainedNearOptimalCentering or ConstrainedNearOptimalCentering).
  • model::JuMP.Model: JuMP optimisation model.
  • noc::NearOptimalCentering: The outer optimisation estimator, passed on to custom objective terms.
  • attrs::ProcessedJuMPOptimiserAttributes: Pre-computed constraint and prior bundle.

Returns

  • nothing.

Related

source
PortfolioOptimisers.solve_noc!Function
solve_noc!(noc, model, rk_opt, rt_opt, opt, attrs, args...)

Solve the Near Optimal Centering problem given the model, risk, and return targets.

Sets model parameters for the risk and return targets, configures the NOC objective, and solves the JuMP model. Multiple overloads handle different algorithm variants and frontier sweep modes.

Arguments

  • noc::NearOptimalCentering: NOC estimator configuration.
  • model::JuMP.Model: JuMP optimisation model.
  • rk_opt: Risk target(s) for the NOC problem.
  • rt_opt: Return target(s) for the NOC problem.
  • opt::BaseJuMPOptimisationEstimator: JuMP optimiser configuration.
  • args...: Additional arguments (frontier bounds, flags, etc.).

Returns

  • (retcode, sol) or (retcodes, sols) depending on the overload.

Related

source
PortfolioOptimisers.assemble_near_optimal_centering_model!Method
assemble_near_optimal_centering_model!(alg, model, noc, setup, rd)

Run the model-assembly middle of the Near Optimal Centering variant alg.

The two variants share a head and a Result, and differ only in the middle and in the solve. This is the middle. ConstrainedNearOptimalCentering delegates to the shared assemble_jump_model!. UnconstrainedNearOptimalCentering runs the four steps of that sequence it needs — non-fixed fees, risk, scalarisation, return — and then the same assert_frontier_sweep_cap tail.

set_non_fixed_fees! runs before the risk build, as it does in assemble_jump_model!. It is what makes the model's return expression net of fees, and the barrier compares that expression against the noc_rt target, which near_optimal_centering_setup computes net of fees as well. A fixed fee still does not apply: it needs the cardinality binaries set_mip_constraints! produces, and that builder belongs to the middle this variant does not run.

UnconstrainedNearOptimalCentering lists every opt setting the resulting model reads and every setting it does not.

The unconstrained variant reads setup.opt, which near_optimal_centering_setup has already replaced with the no_bounds_optimiser copy. So opt.ret is the bound-free return estimator, and opt.pe, opt.fees and opt.sca are the processed values setup.attrs carries. The phylogeny argument is nothing because the variant applies no phylogeny constraints.

Arguments

Returns

  • nothing. Mutates model in place.

Related

source
PortfolioOptimisers.solve_near_optimal_centering!Method
solve_near_optimal_centering!(alg, model, noc, setup)

Run the solve tail of the Near Optimal Centering variant alg.

Reads the arguments each solve_noc! overload needs off setup, so the two variants share one _optimise head. The constrained variant sweeps both frontier registries, so it passes the two Val flags that select the sweeping overload; the unconstrained variant registers no frontier bound and passes neither.

Arguments

Returns

  • (retcode, sol) or (retcodes, sols), as solve_noc! returns.

Related

source
PortfolioOptimisers.set_noc_anchor_parameters!Function
set_noc_anchor_parameters!(model, noc, attrs, rk_opts, rt_opts)

Register the two anchor parameters the centring barrier reads, and set the objective.

noc_rk and noc_rt are the risk and return of the near-optimal anchor the barrier centres on. A sweep moves them from point to point, so they are parameters rather than expressions — the model is assembled once and only their values change between solves.

Arguments

  • model::JuMP.Model: The JuMP optimisation model.
  • noc::NearOptimalCentering: Dispatch object for the objective.
  • attrs::ProcessedJuMPOptimiserAttributes: Pre-computed bundle.
  • rk_opts::VecNum: The anchor risks, one per sweep point.
  • rt_opts::VecNum: The anchor returns, one per sweep point.

Returns

  • (noc_rk, noc_rt): The two parameter references.

Related

source
PortfolioOptimisers.set_noc_anchor!Function
set_noc_anchor!(noc_rk, noc_rt, rk_opts, rt_opts, i)

Move the centring anchor onto sweep point i.

The frontier_sweep! hook of every swept NearOptimalCentering solve. The anchors are the MeanRisk solutions of the same sweep, computed by near_optimal_centering_setup, so anchor i belongs to sweep point i and the index is the flat one frontier_sweep_axes counts. This is the pairing that makes a swept centring solve centre on its own point rather than on some other point's optimum.

Arguments

  • noc_rk: The anchor-risk parameter.
  • noc_rt: The anchor-return parameter.
  • rk_opts::VecNum: The anchor risks, in flat sweep order.
  • rt_opts::VecNum: The anchor returns, in flat sweep order.
  • i::Integer: The flat index of the sweep point.

Returns

  • nothing.

Related

source
PortfolioOptimisers.get_overall_retcodeFunction
get_overall_retcode(w_min_retcode, w_opt_retcode, w_max_retcode, noc_retcode)

Compute the overall optimisation return code from individual sub-problem return codes.

Combines the return codes from the minimum, optimal, and maximum weight sub-problems with the near-optimal centering return code to determine the overall status.

Arguments

  • w_min_retcode: Return code from the minimum weight sub-problem.
  • w_opt_retcode: Return code from the optimal weight sub-problem.
  • w_max_retcode: Return code from the maximum weight sub-problem.
  • noc_retcode: Return code from the near-optimal centering sub-problem.

Returns

  • OptimisationSuccess() if every sub-problem succeeded; otherwise an OptimisationFailure whose res is a named tuple (; msg, w_min, w_opt, w_max, noc_opt) carrying the failure summary and the individual sub-problem return codes (including their solver trial diagnostics).

Related

source
PortfolioOptimisers.compute_ret_lbsMethod
compute_ret_lbs(ret_frontier::VecPair, rt_ends::VecPair)

Resolve a NearOptimalCentering return frontier from spans computed during setup.

NearOptimalCentering does not re-solve for its corners here, unlike MeanRisk: near_optimal_centering_setup has already paid for one minimum-risk solve and one maximum-return solve per swept term, so this only turns each span into its N sweep points.

Arguments

  • ret_frontier::VecPair: The :ret_frontier Model State entry.
  • rt_ends::VecPair: The per-term spans, as i => (rt_min_i, rt_max_i).

Returns

  • The return frontier with every span resolved into a range of sweep points.

Related

source
PortfolioOptimisers.compute_risk_ubsMethod
compute_risk_ubs(model::JuMP.Model, noc::NearOptimalCentering{<:Any, <:Any, <:Any, <:Any, <:Any, <:Any, <:Any, <:Any, <:Any, <:Any, <:Any, <:ConstrainedNearOptimalCentering}, pr::AbstractPriorResult, fees::Option{<:Fees}, w_min::VecNum, w_max::VecNum, args...)

Compute risk upper bounds for a constrained NearOptimalCentering frontier sweep.

Identifies risk frontier entries that are not yet resolved (i.e. not concrete weight vectors) and rebuilds them using the minimum and maximum portfolio weights.

Arguments

  • model::JuMP.Model: JuMP optimisation model containing risk_frontier.
  • noc::NearOptimalCentering{..., <:ConstrainedNearOptimalCentering}: Constrained Near Optimal Centering optimiser.
  • pr::AbstractPriorResult: Prior result with asset moments.
  • fees::Option{<:Fees}: Optional fees configuration.
  • w_min::VecNum: Minimum-risk portfolio weights.
  • w_max::VecNum: Maximum-risk (maximum-return) portfolio weights.

Returns

  • Updated risk frontier vector of (keys, vals) pairs.

Related

source