Weight finalisers
PortfolioOptimisers.RelativeErrorWeightFinaliser — Type
struct RelativeErrorWeightFinaliser <: JuMPWeightFinaliserFormulationMinimises the L1 norm of relative weight deviations when enforcing weight bounds.
Mathematical definition
\[\begin{align} \underset{\boldsymbol{w}}{\min} &\quad \left\lVert \boldsymbol{w} \oslash \boldsymbol{w}_{0} - \boldsymbol{1} \right\rVert_{1}\,, \\ \textrm{s.t.} &\quad \boldsymbol{1}^\intercal \boldsymbol{w} = \boldsymbol{1}^\intercal \boldsymbol{w}_{0}\,, \\ &\quad \boldsymbol{l} \leq \boldsymbol{w} \leq \boldsymbol{u}\,. \end{align}\]
Where:
- $\boldsymbol{w}$: Portfolio weights vector $N \times 1$.
- $\boldsymbol{w}_{0}$: Portfolio weights vector $N \times 1$ that the optimisation produced, which the finaliser repairs.
- $\boldsymbol{l}$, $\boldsymbol{u}$: Lower and upper weight bounds. An absent bound is dropped from the programme rather than set to an infinity.
- $\oslash$: Elementwise division. A zero entry of $\boldsymbol{w}_{0}$ is replaced by
epsbefore the division, so the ratio stays finite.
Constructors
RelativeErrorWeightFinaliser() -> RelativeErrorWeightFinaliserExamples
julia> RelativeErrorWeightFinaliser()RelativeErrorWeightFinaliser()Related
PortfolioOptimisers.SquaredRelativeErrorWeightFinaliser — Type
struct SquaredRelativeErrorWeightFinaliser <: JuMPWeightFinaliserFormulationMinimises the L2 norm of relative weight deviations when enforcing weight bounds.
Mathematical definition
\[\begin{align} \underset{\boldsymbol{w}}{\min} &\quad \left\lVert \boldsymbol{w} \oslash \boldsymbol{w}_{0} - \boldsymbol{1} \right\rVert_{2}\,, \\ \textrm{s.t.} &\quad \boldsymbol{1}^\intercal \boldsymbol{w} = \boldsymbol{1}^\intercal \boldsymbol{w}_{0}\,, \\ &\quad \boldsymbol{l} \leq \boldsymbol{w} \leq \boldsymbol{u}\,. \end{align}\]
Where:
- $\boldsymbol{w}$: Portfolio weights vector $N \times 1$.
- $\boldsymbol{w}_{0}$: Portfolio weights vector $N \times 1$ that the optimisation produced, which the finaliser repairs.
- $\boldsymbol{l}$, $\boldsymbol{u}$: Lower and upper weight bounds. An absent bound is dropped from the programme rather than set to an infinity.
- $\oslash$: Elementwise division. A zero entry of $\boldsymbol{w}_{0}$ is replaced by
epsbefore the division, so the ratio stays finite.
The second-order cone bounds the norm itself, so the objective value is the L2 norm and not its square. The name records the squared-error criterion, whose minimiser is the same because the square is monotonic on a non-negative norm. RelativeErrorWeightFinaliser differs in the norm, not in the power.
Constructors
SquaredRelativeErrorWeightFinaliser() -> SquaredRelativeErrorWeightFinaliserExamples
julia> SquaredRelativeErrorWeightFinaliser()SquaredRelativeErrorWeightFinaliser()Related
PortfolioOptimisers.AbsoluteErrorWeightFinaliser — Type
struct AbsoluteErrorWeightFinaliser <: JuMPWeightFinaliserFormulationMinimises the L1 norm of absolute weight deviations when enforcing weight bounds.
Mathematical definition
\[\begin{align} \underset{\boldsymbol{w}}{\min} &\quad \left\lVert \boldsymbol{w} - \boldsymbol{w}_{0} \right\rVert_{1}\,, \\ \textrm{s.t.} &\quad \boldsymbol{1}^\intercal \boldsymbol{w} = \boldsymbol{1}^\intercal \boldsymbol{w}_{0}\,, \\ &\quad \boldsymbol{l} \leq \boldsymbol{w} \leq \boldsymbol{u}\,. \end{align}\]
Where:
- $\boldsymbol{w}$: Portfolio weights vector $N \times 1$.
- $\boldsymbol{w}_{0}$: Portfolio weights vector $N \times 1$ that the optimisation produced, which the finaliser repairs.
- $\boldsymbol{l}$, $\boldsymbol{u}$: Lower and upper weight bounds. An absent bound is dropped from the programme rather than set to an infinity.
Constructors
AbsoluteErrorWeightFinaliser() -> AbsoluteErrorWeightFinaliserExamples
julia> AbsoluteErrorWeightFinaliser()AbsoluteErrorWeightFinaliser()Related
PortfolioOptimisers.SquaredAbsoluteErrorWeightFinaliser — Type
struct SquaredAbsoluteErrorWeightFinaliser <: JuMPWeightFinaliserFormulationMinimises the L2 norm of absolute weight deviations when enforcing weight bounds.
Mathematical definition
\[\begin{align} \underset{\boldsymbol{w}}{\min} &\quad \left\lVert \boldsymbol{w} - \boldsymbol{w}_{0} \right\rVert_{2}\,, \\ \textrm{s.t.} &\quad \boldsymbol{1}^\intercal \boldsymbol{w} = \boldsymbol{1}^\intercal \boldsymbol{w}_{0}\,, \\ &\quad \boldsymbol{l} \leq \boldsymbol{w} \leq \boldsymbol{u}\,. \end{align}\]
Where:
- $\boldsymbol{w}$: Portfolio weights vector $N \times 1$.
- $\boldsymbol{w}_{0}$: Portfolio weights vector $N \times 1$ that the optimisation produced, which the finaliser repairs.
- $\boldsymbol{l}$, $\boldsymbol{u}$: Lower and upper weight bounds. An absent bound is dropped from the programme rather than set to an infinity.
The second-order cone bounds the norm itself, so the objective value is the L2 norm and not its square. The name records the squared-error criterion, whose minimiser is the same because the square is monotonic on a non-negative norm. AbsoluteErrorWeightFinaliser differs in the norm, not in the power.
Constructors
SquaredAbsoluteErrorWeightFinaliser() -> SquaredAbsoluteErrorWeightFinaliserExamples
julia> SquaredAbsoluteErrorWeightFinaliser()SquaredAbsoluteErrorWeightFinaliser()Related
PortfolioOptimisers.IterativeWeightFinaliser — Type
struct IterativeWeightFinaliser{__T_iter} <: WeightFinaliserIteratively projects weights into the feasible region defined by weight bounds.
Each pass clips the weights to the bounds, then redistributes the clipped mass over the entries that lie strictly inside the bounds, in proportion to their own weights. The pass ends by rescaling the vector to the budget it started with, so the sum is preserved. Passes run until the bounds hold or until iter passes are done. An absent bound is read as typemin or typemax of the weight element type.
The redistribution keeps the ratios of the free weights, so the answer differs from the Euclidean projection of EuclideanWeightFinaliser. The loop can fail to reach the bounds. It stalls when no weight lies strictly inside its bounds, for example [0.6, 0.4, 0.0] under ub = 0.4, and it can diverge on long-short bounds. If the last pass still breaks a bound, or is not finite, the finaliser returns the Euclidean projection of the input instead, which is [0.4, 0.4, 0.2] in that example. A loop that reaches the bounds keeps its own answer.
A bound set that cannot hold the budget has no feasible vector: four assets summing to 1 under lb = 0.3 return their lower bounds, and finalise_weight_bounds reports an OptimisationFailure.
Fields
iter: Maximum number of iterations.
Constructors
IterativeWeightFinaliser(; iter::Integer = 100) -> IterativeWeightFinaliserKeywords correspond to the struct's fields.
Validation
iter > 0.
Examples
julia> IterativeWeightFinaliser()IterativeWeightFinaliser iter ┴ Int64: 100Related
PortfolioOptimisers.JuMPWeightFinaliser — Type
struct JuMPWeightFinaliser{__T_slv, __T_sc, __T_so, __T_alg} <: WeightFinaliserUses a JuMP optimisation model to enforce weight bounds.
The programme keeps the budget of the input weights and holds every weight between the bounds, and alg states which deviation it minimises over that set. An absent bound adds no constraint. A failed solve raises a warning and falls back to a default IterativeWeightFinaliser.
Fields
slv: Solver or vector of solvers.
sc: Constraint scale factor.
so: Objective scale factor.
alg: Weight finaliser error formulation algorithm.
Constructors
JuMPWeightFinaliser(; slv::Slv_VecSlv, sc::Number = 1.0, so::Number = 1.0, alg::JuMPWeightFinaliserFormulation = RelativeErrorWeightFinaliser()) -> JuMPWeightFinaliserKeywords correspond to the struct's fields.
Validation
- If
slvis aVecSlv:!isempty(slv). sc > 0,so > 0.
Examples
julia> JuMPWeightFinaliser(; slv = Solver(; solver = nothing))JuMPWeightFinaliser slv ┼ Solver │ name ┼ String: "" │ solver ┼ nothing │ settings ┼ nothing │ check_sol ┼ @NamedTuple{}: NamedTuple() │ add_bridges ┴ Bool: true sc ┼ Float64: 1.0 so ┼ Float64: 1.0 alg ┴ RelativeErrorWeightFinaliser()Related
PortfolioOptimisers.JuMPWeightFinaliserFormulation — Type
abstract type JuMPWeightFinaliserFormulation <: AbstractAlgorithmAbstract supertype for JuMP-based weight finaliser formulations.
Defines the interface for norm types used when adjusting portfolio weights to satisfy bounds via a JuMP model.
Interfaces
In order to implement a new formulation that works seamlessly with the library, subtype JuMPWeightFinaliserFormulation and implement the following method:
set_clustering_weight_finaliser_alg!
set_clustering_weight_finaliser_alg!(model::JuMP.Model, alg::MyFormulation, wi::VecNum) -> Nothing: Adds the deviation objective to a model that already carries the decision vectorw, the budget equality and the weight bounds.
Arguments
model: The JuMP model, built byopt_weight_bounds.alg: The concrete subtype instance.wi: The weights the optimisation produced, which the model repairs.
Returns
nothing. The method works by adding variables, constraints and the objective tomodel.
Related
PortfolioOptimisers.WeightFinaliser — Type
abstract type WeightFinaliser <: AbstractAlgorithmAbstract supertype for weight finaliser strategies.
A WeightFinaliser enforces weight bounds after the optimisation has produced unconstrained weights.
Interfaces
In order to implement a new strategy that works seamlessly with the library, subtype WeightFinaliser and implement the following method:
opt_weight_bounds
opt_weight_bounds(wf::MyFinaliser, wb::WeightBounds, w::VecNum) -> VecNum: Moveswinto the boundswb, keeping the budget it already carries.
Arguments
wf: The concrete subtype instance.wb: The weight bounds. Either bound may benothing.w: The weights the optimisation produced.
Returns
w::VecNum: The repaired weight vector.finalise_weight_boundsthen pairs it with a return code.
Related
PortfolioOptimisers.set_clustering_weight_finaliser_alg! — Function
set_clustering_weight_finaliser_alg!(model::JuMP.Model,
alg::JuMPWeightFinaliserFormulation,
wi::VecNum)Add the deviation objective of alg to the weight finalisation model.
opt_weight_bounds has already added the decision vector w, the budget equality and the weight bounds. This method adds the epigraph variable t, the cone that bounds the deviation of w from wi, and the objective Min so * t. The cone is a NormOneCone for the two L1 formulations and a SecondOrderCone for the two L2 formulations.
Arguments
model: JuMP model, which must already carrywand the two scale expressions.alg: The deviation formulation, one of the fourJuMPWeightFinaliserFormulationsubtypes.wi: The weights the optimisation produced, which the model repairs.
Returns
nothing.
Details
- The two relative formulations divide by
wi, so they first replace each zero entry ofwiin place witheps(eltype(wi)). The caller's vector carries that substitution afterwards.
Related
PortfolioOptimisers.opt_weight_bounds — Function
opt_weight_bounds(wf::JuMPWeightFinaliser, wb::WeightBounds, wi::VecNum) -> VecNum
opt_weight_bounds(wf::IterativeWeightFinaliser, wb::WeightBounds, w::VecNum) -> VecNum
opt_weight_bounds(wf::EuclideanWeightFinaliser, wb::WeightBounds, w::VecNum) -> VecNum
opt_weight_bounds(wf::EntropicWeightFinaliser, wb::WeightBounds, w::VecNum) -> VecNumMove a weight vector into the bounds wb, keeping the budget it already carries.
The bounds themselves are not changed. Weights that already satisfy the bounds are returned unchanged, without a solve.
The JuMPWeightFinaliser method builds the programme of its alg (see set_clustering_weight_finaliser_alg!) and solves it. A failed solve warns and falls back to a default IterativeWeightFinaliser. The IterativeWeightFinaliser method clips and redistributes instead, and returns the Euclidean projection if its passes end with a bound still broken. The EuclideanWeightFinaliser method returns the Euclidean projection (euclidean_weight_projection). The EntropicWeightFinaliser method returns the entropic projection (entropic_weight_projection), or the Euclidean one where the entropic one is not defined.
Arguments
wf: Weight finaliser algorithm.wb: Weight bounds.wi,w: The weights the optimisation produced.
Returns
w::VecNum: The repaired weight vector.
Related