The programme of a programme Allocation Set: private API
PortfolioOptimisers.calibrated — Function
calibrated(x)
calibrated(x::AbstractVector)Whether a penalty slot or a norm-ceiling slot holds a Calibration Rule.
A Calibration Rule resolves against the prior result, so a calibrated slot reads the head's rows. The test reads the slot itself and every slot of the term it holds, which calibration_slots lists. A vector is calibrated when one of its entries is.
Returns
::Bool:truewhen the slot, or a slot of its term, holds a Calibration Rule.
Related
PortfolioOptimisers.resolve_allocation_set_rows — Function
resolve_allocation_set_rows(
_::ProgrammeAllocationSet,
_::AbstractPriorResult,
_::Nothing
)
Resolves the slots of a ProgrammeAllocationSet that read the head's rows, at every step.
This is the second stage of the set's resolution. resolve_allocation_set resolves the slots keyed by name once per fold. This function resolves the rest on the prior result pr that is fitted on the rows carrier rd, as processed_jump_optimiser_attributes and assemble_jump_model! resolve them for a batch head. A set that reads no rows has no prior, and its slots come back as they are.
Algorithm
The method on a prior result runs these steps.
- Read
strictfrom the currentProjectionStep. - When
lcseis keyed by exposure, buildlcsrfrom it throughlinear_constraintswith the prior's factor regressionpr.rrand the rows. Otherwiselcsrislcse. - Fit the centrality rows
ctrand the phylogeny resultplron the prior and the rows. - Resolve the return floor
retagainst the prior. - Resolve the Calibration Rules of the norm ceilings
l2c,linfcandlpc, and of the penaltiesl1,l2,lpandlinf, against the prior and the set's solver. - Return the resolved slots and
rd.
Arguments
set: The programme set, resolved once per fold.pr: The prior result fitted onrd, ornothingwhen the set reads no rows.rd: The rows carrier the head holds, aReturnsResult.
Validation
- A prior result with no carrier. An
IsNothingErroris thrown. The prior is fitted on the carrier, so this pair does not occur in the library.
Returns
attrs::NamedTuple:lcsr,ctr,plr,ret,l2c,lpc,linfc,l1,l2,lp,linf, and the rows carrierrd, which isnothingwhen the set reads no rows.
Related
PortfolioOptimisers.add_allocation_set_constraints! — Function
add_allocation_set_constraints!(model::JuMP.Model, set::BoundedAllocationSet, w::AbstractVector, X)
add_allocation_set_constraints!(model::JuMP.Model, set::ProgrammeAllocationSet, w::AbstractVector, X)Adds the constraints of a resolved Allocation Set to a JuMP head's model during its assembly.
This is the arm of the Allocation Set Constraint that a FollowTheLeader rule appends to its held optimiser. The head's builders have already registered their named entries: the weight bounds, the budgets, and the turnover and tracking-error terms under their indices. So this function adds the set's rows under other names than the bare projection model uses. It adds the bounds, the budget of one, and the short and gross budgets as anonymous rows. It adds every other kind through the same builders as set_allocation_set_constraints!, in the same order. A builder that takes a prefix gets :aset_. A builder that takes an index gets the first index the model has not used. The function registers the head's w under the prefix, so the entries of a set's risk ceiling never collide with the head's own risk measures.
The set's penalties and the p · tr(W) term of its semidefinite phylogeny go into the Objective Penalty, which the head's objective builder adds to the head's objective. The tracking errors read the head's rows carrier X and its row count. The set's prior is fitted on that carrier, as the leader's prior is. The leader's model trades only the Investable Mask of its own prior, so assert_set_prior_priced refuses a set prior that prices fewer assets than the leader's.
Some builders register their entries under one fixed name per model: a MIP kind, the exact long-short pin, a norm ceiling, a penalty and an integer phylogeny. State such a kind on the set or on the held optimiser, not on both. When it is on both, the second registration fails with an error that names the entry.
Algorithm
- Add the bounds and the budgets as anonymous rows with
add_allocation_set_bounds!. - On a programme set, fit the set's prior on
Xwithallocation_set_prior, and add every other kind withassemble_allocation_set!under the prefix:aset_.
Arguments
model::JuMP.Model: The JuMP optimisation model.set: The Allocation Set, resolved once per fold.w: The Price-Adjusted Allocation the step trades from.X: The rows carrier the head holds through the period, aReturnsResult, ornothing.
Returns
nothing.
Related
PortfolioOptimisers.assemble_allocation_set! — Function
assemble_allocation_set!(
model::Model,
set::ProgrammeAllocationSet,
w::AbstractVector,
X::Union{Nothing, ReturnsResult},
pr::Union{Nothing, AbstractPriorResult},
prefix::Symbol
)
Adds every kind of a programme set other than the bounds and the budgets, in the order assemble_jump_model! runs them.
Both arms call it after they add the bounds. The bare projection model passes the empty prefix Symbol(""). A leader's model passes :aset_. Then the builders that take an index use the first free index, and the head's w is registered under the prefix.
Algorithm
- Check that the prior prices every asset in
Xwithassert_set_prior_priced. - Resolve the slots that read the rows with
resolve_allocation_set_rows. This giveslcsr,ctr,plr,ret,l2c,lpc,linfc,l1,l2,lp,linfandrd. - When
prefixis not empty, register the model'swunder it, with the ownerw_owner = Symbol(""). Thenweights_prefixkeeps the liftedW,variance_flagandrc_variancein the bare namespace, because the weights are the leader's. - Add the linear rows
lcsr, then the centrality rowsctr. - Add the MIP kinds, then the sub-group MIP kinds.
- Add the turnover ceilings, each with its reference replaced by
w, throughset_allocation_turnover!. - When the set has tracking errors, resolve each against
w, so that a benchmark that is not fixed takesw. Cut each benchmark series to the row count of the prior withprefix_tracking_benchmark, and add the rows. - Add the norm ceilings
l2c,lpcandlinfc. - Add the penalties
l1,l2,lpandlinfto the Objective Penalty. - Add the risk ceilings with
set_allocation_risk_ceiling!. - Add the return floor
retwithset_allocation_return_floor!. - Add the integer phylogeny rows and the semidefinite phylogeny rows of
plr. - Add the custom constraints.
Arguments
model::JuMP.Model: The JuMP optimisation model.set: The programme set, resolved once per fold.w: The Price-Adjusted Allocation the step trades from.X: The rows carrier the head holds through the period, aReturnsResult, ornothing.pr: The set's prior result onX, ornothingwhen the set reads no rows.prefix:Symbol("")on the bare projection model,:aset_in a leader's model.
Returns
nothing.
Related
PortfolioOptimisers.prefix_tracking_benchmark — Function
prefix_tracking_benchmark(tr, T::Integer)
prefix_tracking_benchmark(tr::TrackingError{<:ReturnsTracking}, T::Integer)
prefix_tracking_benchmark(trs::AbstractVector, T::Integer)Cuts a ReturnsTracking benchmark of a programme set to its first T entries when it is longer.
The head's rows are the first rows of the fold, up to the current period, so a benchmark series stated over the whole fold aligns with them by its first T entries. A benchmark shorter than the rows goes to the builder unchanged, and the builder throws a DimensionMismatch. A weights benchmark reads the rows themselves and is returned unchanged. A vector of tracking errors is cut entry by entry.
Arguments
tr: A tracking error, a vector of them, or any other value.T: The row count of the head's rows.
Returns
tr':trwith each returns benchmark cut toTentries.
Related
PortfolioOptimisers.set_allocation_turnover! — Function
set_allocation_turnover!(model::JuMP.Model, tn::Nothing, bare::Bool)
set_allocation_turnover!(model::JuMP.Model, tn::Turnover, bare::Bool)
set_allocation_turnover!(model::JuMP.Model, tns::VecTn, bare::Bool)Adds a programme set's turnover ceilings, whose reference is already the step's Price-Adjusted Allocation.
On the bare projection model the ceilings take the indices one to the number of ceilings. In a leader's model each ceiling takes the first index that the model has not used, so the set's terms do not replace the head's own.
Arguments
model::JuMP.Model: The JuMP optimisation model.tn: The turnover ceilings, oneTurnover, a vector of them, ornothing.bare:trueon the bare projection model,falsein a leader's model.
Returns
nothing.
Related
PortfolioOptimisers.set_allocation_return_floor! — Function
set_allocation_return_floor!(model::JuMP.Model, ret::Nothing, pr, bare::Bool; kwargs...)
set_allocation_return_floor!(model::JuMP.Model, ret::JuMPReturnsEstimator, pr::AbstractPriorResult, bare::Bool; kwargs...)
set_allocation_return_floor!(model::JuMP.Model, rets::VecJRE, pr::AbstractPriorResult, bare::Bool; kwargs...)Adds a programme set's return floor.
For each term, the per-index arm of set_return_constraints! writes the return expression on the prior's expected returns and the row of its settings.lb. The term's scale is set to one first. On the bare projection model the terms take the indices one to the number of terms. In a leader's model each term takes the first index the model has not used. The function does not use a term in the objective, as a scalarised return or the normalisation of a ratio, because the objective of the projection is the geometry's divergence.
Arguments
model::JuMP.Model: The JuMP optimisation model.ret: The return floor, one return estimator, a vector of them, ornothing.pr: The set's prior result.bare:trueon the bare projection model,falsein a leader's model.kwargs...: Forwarded toset_return_constraints!. The rows carrier arrives asrd.
Returns
nothing.
Related
PortfolioOptimisers.add_allocation_set_bounds! — Function
add_allocation_set_bounds!(
model::Model,
wb::WeightBounds,
sbgt,
gbgt
)
Adds an Allocation Set's weight bounds, its budget of one, and its short and gross budgets to a model that already names its own.
The rows are the inequalities that set_allocation_set_bounds! writes, registered under no name. The short and gross budgets read the model's long and short parts when the model holds them. Otherwise the function makes two anonymous vectors of parts and bounds them by w.
JuMP formulation
Variables
w,k: read from the model.lw,sw: long and short parts. They are read from the model when it holds them. Otherwise, when the set has a short or a gross budget, they are two anonymous vectors of $N$ variables, each bounded below by zero.
Constraints
Every row is registered under no name.
- $s_c (\boldsymbol{w} - k \boldsymbol{l}) \geq 0$, when an entry of $\boldsymbol{l}$ is finite.
- $s_c (\boldsymbol{w} - k \boldsymbol{u}) \leq 0$, when an entry of $\boldsymbol{u}$ is finite.
- $s_c \left(\sum_{i=1}^{N} w_i - k\right) = 0$.
- $s_c (\boldsymbol{w} - \boldsymbol{lw}) \leq 0$ and $s_c (\boldsymbol{w} + \boldsymbol{sw}) \geq 0$, when the function makes the parts.
- The rows of
anonymous_budget_rows!on $\sum_i sw_i$ for the short budget, and on $\sum_i (lw_i + sw_i)$ for the gross budget.
Where:
- $s_c$: Constraint scale. It multiplies both sides of a row, so a positive value leaves the feasible set unchanged.
- $k$: Budget scaling / homogenisation variable.
- $\boldsymbol{w}$: Portfolio weights vector $N \times 1$.
- $N$: Number of assets.
- $\boldsymbol{l}$, $\boldsymbol{u}$: Lower and upper weight bounds of the set, resolved.
- $\boldsymbol{lw}$, $\boldsymbol{sw}$: Long and short parts of $\boldsymbol{w}$, each $N \times 1$ and non-negative.
Arguments
model::JuMP.Model: The JuMP optimisation model.wb: The set's resolvedWeightBounds.sbgt: The short budget, a number, aBudgetRange, ornothing.gbgt: The gross budget, a number, aBudgetRange, ornothing.
Validation
Σ lb ≤ 1 ≤ Σ ubover the resolved bounds, throughassert_feasible_bounds.
Related
PortfolioOptimisers.anonymous_budget_rows! — Function
anonymous_budget_rows!(model::JuMP.Model, expr, bgt::Nothing)
anonymous_budget_rows!(model::JuMP.Model, expr, bgt::Number)
anonymous_budget_rows!(model::JuMP.Model, expr, bgt::BudgetRange)Adds one budget on an expression as rows under no name.
A number fixes the expression at k · bgt. A BudgetRange bounds it on each side that is set. nothing adds no row.
JuMP formulation
Variables
k: read from the model.
Constraints
Every row is registered under no name.
- $s_c (e - k b) = 0$, when the budget is a number.
- $s_c (e - k b_l) \geq 0$ and $s_c (e - k b_u) \leq 0$, when the budget is a range, each row only when its bound is set.
Where:
- $s_c$: Constraint scale. It multiplies both sides of a row, so a positive value leaves the feasible set unchanged.
- $k$: Budget scaling / homogenisation variable.
- $e$: The expression the budget bounds.
- $b$: The budget, when it is a number.
- $b_l$, $b_u$: Lower and upper bounds of the range.
Arguments
model::JuMP.Model: The JuMP optimisation model.expr: The expression the budget bounds.bgt: A number, aBudgetRange, ornothing.
Returns
nothing.
Related
PortfolioOptimisers.free_state_index — Function
free_state_index(model::Model, name::Symbol) -> Int64
Returns the first index i, counted from one, at which the Model State holds no entry name.
A builder keyed by an index uses it to add the set's term next to the head's own terms, which hold the indices from one up.
Returns
i::Int: The first free index.
Related
PortfolioOptimisers.set_allocation_set_bounds! — Function
set_allocation_set_bounds!(model::JuMP.Model, wb::WeightBounds, sbgt = nothing, gbgt = nothing)Adds an Allocation Set's weight bounds, its budget of one, and its short and gross budgets to the bare projection model.
set_weight_constraints! writes the bounds, the short budget and the gross budget, with no net budget. A negative lower bound then builds the long and short parts of w and leaves the long part free. Under JuMPOptimiser, a net budget with no short budget fixes the long part at the net budget, which forbids every short position. An Allocation Set lets the book hold short positions, so the function passes no net budget there. It adds Σw = k after that, through set_budget_constraints!.
Algorithm
- Check the bounds against the budget with
assert_feasible_bounds. - Add the bounds, the short budget and the gross budget with
set_weight_constraints!, with no net budget. - Add the budget
Σw = kwithset_budget_constraints!.
Arguments
model::JuMP.Model: The JuMP optimisation model.wb: The set's resolvedWeightBounds.sbgt: The short budget, a number, aBudgetRange, ornothing.gbgt: The gross budget, a number, aBudgetRange, ornothing.
Validation
Σ lb ≤ 1 ≤ Σ ubover the resolved bounds, throughassert_feasible_bounds.
Related
PortfolioOptimisers.set_projection_objective! — Function
set_projection_objective!(model::JuMP.Model, proj::EuclideanProjection, q::AbstractVector)
set_projection_objective!(model::JuMP.Model, proj::EntropicProjection, q::AbstractVector)
set_projection_objective!(model::JuMP.Model, proj::GramProjection, q::AbstractVector)
set_projection_objective!(model::JuMP.Model, proj::DiagonalProjection, q::AbstractVector)
set_projection_objective!(model::JuMP.Model, proj::TsallisProjection, q::AbstractVector)
set_projection_objective!(model::JuMP.Model, proj::LogBarrierProjection, q::AbstractVector)Sets the objective of the projection programme to the geometry's divergence from the raw step q, plus the Objective Penalty.
Each arm writes its divergence $f$ as a conic model and hands it to set_divergence_objective!, which adds the penalty and sets the objective.
Mathematical definition
\[\begin{align} f_{\mathrm{E}}(\boldsymbol{w}) &= \lVert \boldsymbol{w} - \boldsymbol{q} \rVert_2\,, \\ f_{\mathrm{E}}^{\pi}(\boldsymbol{w}) &= \frac{1}{2} \lVert \boldsymbol{w} - \boldsymbol{q} \rVert_2^2\,, \\ f_{\mathrm{G}}(\boldsymbol{w}) &= \lVert \mathbf{G} (\boldsymbol{w} - \boldsymbol{q}) \rVert_2\,, \\ f_{\mathrm{G}}^{\pi}(\boldsymbol{w}) &= \frac{1}{2} \lVert \mathbf{G} (\boldsymbol{w} - \boldsymbol{q}) \rVert_2^2\,, \\ f_{\mathrm{KL}}(\boldsymbol{w}) &= \sum_{i \in P} w_i \log \frac{w_i}{q_i}\,, \\ f_{\alpha}(\boldsymbol{w}) &= \frac{1}{1 - \alpha} \sum_{i \in P} \left( q_i^{\alpha - 1} w_i - \frac{w_i^{\alpha}}{\alpha} \right)\,, \\ f_{\mathrm{IS}}(\boldsymbol{w}) &= \sum_{i \in P} \left( \frac{w_i}{q_i} - \log w_i \right)\,. \end{align}\]
Where:
- $\boldsymbol{w}$: Portfolio weights vector $N \times 1$.
- $\boldsymbol{q}$: Raw step, the vector the rule's unconstrained step gives before the projection onto the Allocation Set.
- $\pi$: Objective Penalty, the sum of the set's penalties and of the other terms added to the objective before it.
- $f_{\mathrm{E}}$, $f_{\mathrm{E}}^{\pi}$: Divergence of
EuclideanProjection, without and with an Objective Penalty. - $f_{\mathrm{G}}$, $f_{\mathrm{G}}^{\pi}$: Divergence of
GramProjectionand ofDiagonalProjection, without and with an Objective Penalty. - $\mathbf{G}$: Upper Cholesky factor of the geometry's Gram matrix $\mathbf{A}$, so $\mathbf{G}^\intercal \mathbf{G} = \mathbf{A}$. Under
DiagonalProjectionit is $\mathrm{diag}(\sqrt{\boldsymbol{h}})$ and $\mathbf{A} = \mathrm{diag}(\boldsymbol{h})$. - $f_{\mathrm{KL}}$: Relative entropy, the divergence of
EntropicProjection. - $f_{\alpha}$: Tsallis divergence, the divergence of
TsallisProjection. - $\alpha$: Power of the Tsallis potential, in $(0, 1)$.
- $f_{\mathrm{IS}}$: Itakura–Saito divergence, the divergence of
LogBarrierProjection. - $P = \{i : q_i > 0\}$: Positive entries of the raw step. Under the entropic, Tsallis and log-barrier geometries every $w_i$ with $i \notin P$ is zero.
- $\Psi$: Potential of the Projection Geometry.
- $D_\Psi$: Bregman divergence of $\Psi$.
Each $f$ differs from the Bregman divergence $D_\Psi(\boldsymbol{w}, \boldsymbol{q})$ of its geometry's potential by a term that is constant in $\boldsymbol{w}$ on the budget $\sum_i w_i = 1$, so each has the minimiser of $D_\Psi$ and a penalty added to it weighs against $D_\Psi$ itself. $f_{\mathrm{E}}^{\pi}$ and $f_{\mathrm{G}}^{\pi}$ are these Bregman divergences, of $\tfrac{1}{2} \lVert \boldsymbol{w} \rVert_2^2$ and $\tfrac{1}{2} \boldsymbol{w}^\intercal \mathbf{A} \boldsymbol{w}$. The norm $f_{\mathrm{E}}$ has the same minimiser as $f_{\mathrm{E}}^{\pi}$ when no penalty is present, and $f_{\mathrm{G}}$ has the same minimiser as $f_{\mathrm{G}}^{\pi}$. A penalty $\pi$ added to the norm does not move the minimiser off a feasible $\boldsymbol{q}$ while the dual norm of $\nabla \pi(\boldsymbol{q})$ is at most one, because the subdifferential of a norm at zero is its dual unit ball. Added to the squared norm, it gives the proximal step.
JuMP formulation
Variables
w: read from the model.t_proj: created. It is a scalar under the Euclidean, Gram, diagonal and entropic arms, and a vector with one entry for each index in $P$ under the Tsallis and log-barrier arms.
Constraints
- Euclidean, Gram and diagonal arms: the row of
set_distance_cone!on $\boldsymbol{x} = s_c (\boldsymbol{w} - \boldsymbol{q})$ or $\boldsymbol{x} = s_c \mathbf{G} (\boldsymbol{w} - \boldsymbol{q})$. - Entropic arm,
proj_zero: $s_c w_i = 0$ for each $i \notin P$, when such an $i$ exists. - Entropic arm,
proj_rec: $s_c t \geq \sum_{i \in P} s_c w_i \log (w_i / q_i)$, the relative entropy cone over $(s_c t, s_c \boldsymbol{q}_P, s_c \boldsymbol{w}_P)$. - Tsallis arm, under no name: $t_j \leq w_j^{\alpha}$ for each $j \in P$, the power cone of power $\alpha$ over $(s_c w_j, s_c, s_c t_j)$.
- Log-barrier arm, under no name: $t_j \leq \log w_j$ for each $j \in P$, the exponential cone over $(s_c t_j, s_c, s_c w_j)$.
- Tsallis and log-barrier arms: the rows of
barrier_objective_entries, which fix $w_i = 0$ for each $i \notin P$.
The divergence each arm hands to set_divergence_objective! is $t$ under the Euclidean, Gram, diagonal and entropic arms, $\frac{1}{1 - \alpha} \left( \sum_{j \in P} q_j^{\alpha - 1} w_j - \frac{1}{\alpha} \sum_{j \in P} t_j \right)$ under the Tsallis arm, and $\sum_{j \in P} w_j / q_j - \sum_{j \in P} t_j$ under the log-barrier arm.
Where:
- $s_c$: Constraint scale. It multiplies both sides of a row, so a positive value leaves the feasible set unchanged.
- $t$, $t_j$: The entries of
t_proj. - $\boldsymbol{q}_P$, $\boldsymbol{w}_P$: The entries of $\boldsymbol{q}$ and $\boldsymbol{w}$ at the indices in $P$.
Arguments
model::JuMP.Model: The JuMP optimisation model.proj: The Projection Geometry.q: The raw step.
Validation
- Under
EntropicProjection,TsallisProjectionandLogBarrierProjection:all(>= 0, q)andsum(q) > 0. ADomainErroris thrown otherwise. - Under
GramProjection:proj.Ais notnothing. AnArgumentErroris thrown otherwise: the rule binds the matrix.
Related
PortfolioOptimisers.set_distance_cone! — Function
set_distance_cone!(model::Model, t, x, sc)
Bounds a projection's distance variable t below by the norm of the scaled deviation x, or by half its square when the model holds an Objective Penalty.
Without a penalty the function writes the second-order cone. Its minimum is sharp, and the solver finds it to a tight tolerance. With a penalty it writes the rotated second-order cone, because a penalty added to the norm does not move the minimiser off a feasible raw step while its gradient is small, and added to half the square it gives the proximal step. The penalty is present when the set's penalties, a custom objective term or the p · tr(W) term of a semidefinite phylogeny were added before the objective. set_projection_objective! states the two divergences.
JuMP formulation
Variables
t: read. It is the caller's distance variable.
Constraints
proj_soc: $(s_c t, \boldsymbol{x}) \in \mathcal{K}_{\mathrm{SOC}}$, that is $t \geq \lVert \boldsymbol{x} \rVert_2 / s_c$, when the model holds no Objective Penalty.proj_rsoc: $(s_c t, s_c, \boldsymbol{x}) \in \mathcal{K}_{\mathrm{RSOC}}$, that is $t \geq \lVert \boldsymbol{x} \rVert_2^2 / (2 s_c^2)$, when it holds one.
Where:
- $s_c$: Constraint scale. It multiplies both sides of a row, so a positive value leaves the feasible set unchanged.
- $\boldsymbol{x}$: The scaled deviation, $s_c (\boldsymbol{w} - \boldsymbol{q})$ or $s_c \mathbf{G} (\boldsymbol{w} - \boldsymbol{q})$, so the two rows give $t \geq \lVert \boldsymbol{w} - \boldsymbol{q} \rVert_2$ and $t \geq \tfrac{1}{2} \lVert \boldsymbol{w} - \boldsymbol{q} \rVert_2^2$ in the Euclidean geometry.
- $\mathcal{K}_{\mathrm{SOC}} = \{(u, \boldsymbol{v}) : u \geq \lVert \boldsymbol{v} \rVert_2\}$: Second-order cone.
- $\mathcal{K}_{\mathrm{RSOC}} = \{(u, v, \boldsymbol{z}) : 2 u v \geq \lVert \boldsymbol{z} \rVert_2^2,\, u \geq 0,\, v \geq 0\}$: Rotated second-order cone.
Arguments
model::JuMP.Model: The JuMP optimisation model.t: The distance variable.x: The scaled deviation, a vector of affine expressions.sc: The constraint scale.
Returns
nothing.
Related
PortfolioOptimisers.set_divergence_objective! — Function
set_divergence_objective!(model::Model, div, so)
Sets the projection programme's objective to the minimum of the geometry's divergence div plus the Objective Penalty, times the objective scale.
The penalty holds the set's penalties, its custom objective terms and the p · tr(W) term of its semidefinite phylogeny. It enters through add_penalty_to_objective!, which every JuMP head's objective also uses. With no penalty the objective is the divergence alone, which is the projection that the papers of the rules state.
JuMP formulation
Expressions
obj_expr: $d + \pi$. The function registers $d$ first and then adds the model'sopwhen it holds one.
Objective
Min: $s_o$ timesobj_expr.
Where:
- $d$: The divergence
divof the geometry. - $\pi$: The Objective Penalty
op, zero when the model holds none. - $s_o$: Objective scale. It multiplies the objective, so a positive value leaves the argument of the optimum unchanged.
Arguments
model::JuMP.Model: The JuMP optimisation model.div: The divergence, an affine expression or a variable.so: The objective scale.
Returns
nothing.
Related
PortfolioOptimisers.barrier_objective_entries — Function
barrier_objective_entries(
model::Model,
q::AbstractVector
) -> NTuple{4, Any}
Prepares the entries that a barrier objective is written over.
It refuses a raw step with a negative entry or with no positive entry. It fixes the weight of every zero entry of q at zero. It returns the positive indices, the model's w and the two scales.
JuMP formulation
Variables
w: read from the model.
Constraints
- Under no name: $s_c w_i = 0$ for each $i$ with $q_i = 0$.
Where:
- $s_c$: Constraint scale. It multiplies both sides of a row, so a positive value leaves the feasible set unchanged.
- $\boldsymbol{q}$: Raw step, the vector the rule's unconstrained step gives before the projection onto the Allocation Set.
Arguments
model::JuMP.Model: The JuMP optimisation model.q: The raw step.
Validation
all(>= 0, q). ADomainErroris thrown otherwise.sum(q) > 0. ADomainErroris thrown otherwise.
Returns
(pos, w, sc, so)::Tuple: The indices of the positive entries ofq, the model'sw, the constraint scale and the objective scale.
Related
PortfolioOptimisers.projection_solver — Function
projection_solver(proj::AbstractProjectionGeometry, set::ProgrammeAllocationSet)
projection_solver(proj::GramProjection, set::AbstractAllocationSet)
projection_solver(proj::GramProjection, set::ProgrammeAllocationSet)
projection_solver(proj::GramProjection, set::BoundedAllocationSet)
projection_solver(proj::AbstractProjectionGeometry, set::BoundedAllocationSet)Returns the solver a projection programme runs on.
A GramProjection carries its own solver, and the programme uses it on every set. Every other geometry uses the programme set's solver. On a BoundedAllocationSet every geometry other than the Gram one is a scalar root with no programme, so the function throws an ArgumentError that names the geometry. project does not call it in that case.
Returns
slv: The solver, or a vector of solvers.
Related
PortfolioOptimisers.allocation_set_ready — Function
allocation_set_ready(set::AbstractAllocationSet, X)
allocation_set_ready(set::ProgrammeAllocationSet, X)Tells whether the set's constraints can be built on the rows X of the step.
A programme set that fits its prior on the rows cannot be built while the head holds fewer than two rows, because a covariance of one observation does not exist. Every other set can always be built.
Returns
reason:nothingwhen the constraints can be built, and otherwise the reason for the Held Step as aString.
Related
PortfolioOptimisers.projection_programme — Function
projection_programme(
proj::AbstractProjectionGeometry,
set::AbstractAllocationSet,
q::AbstractVector,
w::AbstractVector
) -> Any
Projects the raw step q onto the Allocation Set in the geometry's divergence, as a JuMP programme.
A solved programme returns its weights. A programme that does not solve, or whose constraints cannot be built on the step's rows (allocation_set_ready), is a Held Step. Then record_held_step! writes the record to the current ProjectionStep, and the function returns a copy of w, the book the fund already holds.
A set that reads the rows fits its prior on the step's rows carrier, as a batch head does. The programme then runs on the prior's Investable Mask, also as a batch head does. It solves over the assets the prior prices, and gives a zero weight to every other asset. Under a time-varying panel, an asset without a listing for part of the window is outside the universe of a plain prior until the window no longer holds that part. So the programme gives it a zero, which is the one zero in the recursion's allocation that the rule's step did not make. A batch head gives the same zero. The asset comes back at the first step at which the prior prices it, and the rule's geometry decides whether the raw step then gives it weight, as for a zero in the Start Allocation. A set that reads no rows fits no prior and solves over the full universe.
Mathematical definition
\[\begin{align} \boldsymbol{w}^{+} &= \underset{\boldsymbol{w} \in \mathcal{W}}{\arg\min} \; D_\Psi(\boldsymbol{w}, \boldsymbol{q}) + \pi(\boldsymbol{w})\,. \end{align}\]
Where:
- $\boldsymbol{w}^{+}$: Projected allocation, the answer of the projection onto the Allocation Set.
- $\mathcal{W}$: Allocation Set. Under an Investable Mask it also holds $w_i = 0$ for every asset $i$ outside the mask.
- $D_\Psi$: Bregman divergence of $\Psi$.
- $\Psi$: Potential of the Projection Geometry.
- $\boldsymbol{q}$: Raw step, the vector the rule's unconstrained step gives before the projection onto the Allocation Set.
- $\pi$: Objective Penalty of the set, zero when the set has no penalty.
set_projection_objective! states the objective each geometry writes for $D_\Psi$.
Algorithm
- Read the rows
Xof the currentProjectionStep. - When
allocation_set_readygives a reason, record the Held Step with it and return a copy ofw. Stop. - Fit the set's prior
pronXwithallocation_set_prior, and read its Investable Maskimsk. - Reduce
set,Xandprto the mask withprogramme_investable_reduction. Viewqandwat the mask, which givesqandwr. - Make a bare model with the set's two scales and the row count of
X, zero when there are no rows. Registerk = 1, and the vectorwof weight variables. - Add the set's constraints with
set_allocation_set_constraints!, withwras the reference. - Add the set's custom objective terms with
add_custom_objective_term!, with the geometry as the objective and the set as the owner. - Set the objective with
set_projection_objective!. - Solve on
projection_solver. When the solve succeeds, return the solution with a zero at every asset outside the mask. Otherwise record the Held Step with the solver trials, and return a copy ofw.
JuMP formulation
Variables
w: created, with the base namew, one variable for each asset in the mask. It is registered in the Model State under the keyw.
Expressions
k: the constant one.
Where:
- $\boldsymbol{w}$: Portfolio weights vector $N \times 1$.
- $k$: Budget scaling / homogenisation variable.
Arguments
proj: The geometry.set: The set, resolved.q: The raw step.w: The Price-Adjusted Allocation the step trades from.
Returns
w'::Vector: The projected allocation, orwcopied on a Held Step.
Related
PortfolioOptimisers.programme_investable_reduction — Function
programme_investable_reduction(imsk::Nothing, set::AbstractAllocationSet, X::Option{<:ReturnsResult}, pr)
programme_investable_reduction(imsk::BitVector, set::AbstractAllocationSet, X::ReturnsResult, pr::AbstractPriorResult)
programme_investable_reduction(imsk::BitVector, set::AbstractAllocationSet, X, pr)Reduces the set, the rows carrier and the set's prior to the prior's Investable Mask.
The projection programme then runs on the assets the prior can price, as a batch head does with investable_reduction. The caller views the raw step and the Price-Adjusted Allocation at the same mask with investable_weights_view.
Dispatch selects one of three methods. A nothing mask means that every asset is investable, which is true at every step on a static panel and at every step of a set that reads no rows. That method returns its arguments unchanged. The BitVector method takes the views at findall(imsk). The third method refuses a mask with no carrier or no prior, because a mask comes from a prior fitted on a carrier, so this pair does not occur in the library. The set is viewed against the carrier's full returns matrix, because a view of a tracking estimator needs it. The Price-Adjusted Allocation is cut to the mask and is not renormalised, as the batch reduction cuts a turnover reference. So an asset the prior cannot price leaves the reference, and the programme allocates the budget of one over the investable assets. The function writes no warning for such an asset, because the Investable Mask of the read-out already shows it at every step.
Validation
- A mask with no carrier or no prior. An
IsNothingErroris thrown.
Returns
(set, X, pr)::Tuple: The three reduced to the mask, or unchanged.
Related
PortfolioOptimisers.projection_scale — Function
projection_scale(set::ProgrammeAllocationSet, f::Symbol)
projection_scale(set::BoundedAllocationSet, f::Symbol)Returns the constraint scale :sc or the objective scale :so that a projection programme registers on its model.
A programme set gives its own field. A bounded set carries no scale, so it gives one.
Related
PortfolioOptimisers.allocation_set_cobj — Function
allocation_set_cobj(set::ProgrammeAllocationSet)
allocation_set_cobj(set::BoundedAllocationSet)Returns the custom objective terms that a projection programme adds to its objective.
A programme set gives its cobj. A bounded set carries no objective term, so it gives nothing.
Related
PortfolioOptimisers.blend_projection — Function
blend_projection(proj::EuclideanProjection, set::BoundedAllocationSet, q::AbstractVector, w::AbstractVector)
blend_projection(proj::EuclideanProjection, set::AbstractAllocationSet, q::AbstractVector, w::AbstractVector)Projects the blend of an ExpertMixture onto the head's set a second time, when the set needs it.
On a BoundedAllocationSet dispatch returns the blend unchanged. The bounds and the budget define a convex set, so a convex blend of allocations in it is in it too, and the projection is the identity. On every other set the function calls project, which gives the repair that a turnover ceiling or a MIP kind needs.
Related