Budget Constraints: private API
PortfolioOptimisers.BudgetConstraintEstimator — Type
abstract type BudgetConstraintEstimator <: JuMPConstraintEstimatorAbstract supertype for all budget constraint estimators.
Related
PortfolioOptimisers.Num_BgtCE — Type
const Num_BgtCE = Union{<:Number, <:BudgetConstraintEstimator}Union of scalar budget values and BudgetConstraintEstimator instances.
PortfolioOptimisers.BudgetEstimator — Type
abstract type BudgetEstimator <: BudgetConstraintEstimatorAbstract supertype for estimators that specify the portfolio budget range (sum of weights).
Related
PortfolioOptimisers.BudgetCostEstimator — Type
abstract type BudgetCostEstimator <: BudgetConstraintEstimatorAbstract supertype for estimators that specify transaction cost budgets.
Related
PortfolioOptimisers.Num_BgtRg — Type
const Num_BgtRg = Union{<:Number, <:BudgetRange}Alias for a scalar budget value or budget range.
Matches either a plain number (fixed budget, e.g. 1.0) or a BudgetRange (interval budget constraint). Used for dispatch in budget constraint generation.
Related
PortfolioOptimisers.set_budget_costs! — Function
set_budget_costs!(args...)Set transaction cost budget constraints in the JuMP model.
No-op fallback when no cost budget is specified.
Arguments
args...: Arguments (ignored).
Returns
nothing.
Related
PortfolioOptimisers.set_budget_constraints! — Function
set_budget_constraints!(args...)
set_budget_constraints!(model::JuMP.Model, val::Number, w::VecNum)
set_budget_constraints!(model::JuMP.Model, bgt::BudgetRange, w::VecNum)
set_budget_constraints!(model::JuMP.Model, bgt::BudgetCosts, w::VecNum)
set_budget_constraints!(model::JuMP.Model, bgt::BudgetMarketImpact, w::VecNum)Add budget constraints to the JuMP optimisation model.
The fall-through method does nothing. The concrete methods add the appropriate portfolio budget constraint based on the type of budget specification provided.
Mathematical definition
Fixed / range:
\[\begin{align} k \cdot \mathrm{lb} &\leq \sum_i w_i \leq k \cdot \mathrm{ub}\,. \end{align}\]
Where:
- $\boldsymbol{w}$: Portfolio weights vector $N \times 1$.
- $k$: Budget scaling / homogenisation variable.
- $\mathrm{lb}$, $\mathrm{ub}$: Lower and upper budget bounds.
Linear cost budget (BudgetCosts):
\[\begin{align} \sum_i w_i + \boldsymbol{v}_p^\intercal \boldsymbol{w}_p + \boldsymbol{v}_n^\intercal \boldsymbol{w}_n \in [k\,\mathrm{lb},\; k\,\mathrm{ub}]\,. \end{align}\]
Where:
- $\boldsymbol{w}$: Portfolio weights vector $N \times 1$.
- $k$: Budget scaling / homogenisation variable.
- $\boldsymbol{w}_p$, $\boldsymbol{w}_n$: Positive and negative weight increments.
- $\boldsymbol{v}_p$, $\boldsymbol{v}_n$: Cost coefficient vectors for positive and negative changes.
- $\mathrm{lb}$, $\mathrm{ub}$: Lower and upper budget bounds.
Power-law market-impact budget (BudgetMarketImpact):
\[\begin{align} \sum_i w_i + \boldsymbol{v}_p^\intercal \boldsymbol{w}_p^{1/\beta} + \boldsymbol{v}_n^\intercal \boldsymbol{w}_n^{1/\beta} \in [k\,\mathrm{lb},\; k\,\mathrm{ub}]\,. \end{align}\]
Where:
- $\boldsymbol{w}$: Portfolio weights vector $N \times 1$.
- $k$: Budget scaling / homogenisation variable.
- $\boldsymbol{w}_p$, $\boldsymbol{w}_n$: Positive and negative weight increments.
- $\boldsymbol{v}_p$, $\boldsymbol{v}_n$: Market-impact cost coefficient vectors.
- $\beta \in (0, 1)$: Reciprocal of the market impact exponent, so the realised power law is $1/\beta$.
- $\mathrm{lb}$, $\mathrm{ub}$: Lower and upper budget bounds.
The power is raised through a three-dimensional power cone, one per asset per sign, so the model stays convex. BudgetMarketImpact states the full system.
Arguments
model::JuMP.Model: The JuMP optimisation model.val::Number: Fixed budget scalar.bgt: Budget constraint specification (BudgetRange,BudgetCosts, orBudgetMarketImpact).w: Portfolio weight vector.
Returns
nothing.
Related
PortfolioOptimisers.set_long_short_budget_constraints! — Function
set_long_short_budget_constraints!(args...)Set budget constraints for long and short portfolio positions in the JuMP model.
Various overloads handle different budget types (fixed, range), dispatching on the presence or absence of long/short budget configurations.
Arguments
args...: JuMP model and budget parameters.
Returns
nothing.
Related
PortfolioOptimisers.set_cost_budget_constraints! — Function
set_cost_budget_constraints!(model, vp, vn, val_or_bgt, w, cp, cn)Charge the trading costs against the portfolio budget.
Registers the cost_bgt_expr expression and the constraint that the weights and their costs must together meet the budget. Two overloads handle the two budget shapes: a fixed value pins the sum, and a BudgetRange bounds it on either side.
The charged quantity is a positional argument, not a field read from the model, because the two cost families charge different quantities. BudgetCosts charges the raw increments wp and wn; BudgetMarketImpact charges the power-cone variables wip and win, which bound the increments raised to 1/beta. Both pass the same coefficient vectors.
Arguments
model::JuMP.Model: The JuMP optimisation model.vp: Cost coefficients for positive trades; a vector or a scalar.vn: Cost coefficients for negative trades; a vector or a scalar.val_or_bgt: Fixed budget value orBudgetRange.w: Portfolio weight vector.cp: The positive-side quantity the coefficients charge.cn: The negative-side quantity the coefficients charge.
Returns
nothing.
Related
PortfolioOptimisers.set_gross_budget_constraints! — Method
set_gross_budget_constraints!(model::JuMP.Model, gbgt::Option{<:Num_BgtRg})Constrain the gross exposure (leverage) sum(lw) + sum(sw), independently of the net exposure.
A number pins it; a BudgetRange bounds it on either side. Whether the constraint pins the realised gross exposure norm(w, 1) or merely bounds it depends on xbgt — see short_mip_threshold_constraints.
Arguments
model::JuMP.Model: JuMP optimisation model.gbgt: Gross budget specification, ornothingfor no constraint.
Returns
nothing.
Related
PortfolioOptimisers.set_gross_budget_constraints! — Method
set_gross_budget_constraints!(model::JuMP.Model, gbgt::Option{<:Num_BgtRg})Constrain the gross exposure (leverage) sum(lw) + sum(sw), independently of the net exposure.
A number pins it; a BudgetRange bounds it on either side. Whether the constraint pins the realised gross exposure norm(w, 1) or merely bounds it depends on xbgt — see short_mip_threshold_constraints.
Arguments
model::JuMP.Model: JuMP optimisation model.gbgt: Gross budget specification, ornothingfor no constraint.
Returns
nothing.
Related
PortfolioOptimisers.assert_gross_budget_admissible — Function
assert_gross_budget_admissible(bgt, sbgt, gbgt, wb)
Assert that a gross budget is admissible alongside the net and short budgets.
bgt and sbgt constrain the net and gross exposures only together: pinning both gives 1'w == bgt and norm(w, 1) == bgt + 2 * sbgt. gbgt exists for the combination they cannot reach — gross pinned with net free — so it is rejected when they already determine the gross exposure, and when the weight bounds forbid short positions (whereupon gross and net coincide and bgt already owns the constraint).
Only the statically-decidable contradictions are caught. Ranges may still conflict at solve time, surfacing as infeasibility, and a WeightBoundsEstimator is not resolved until then. TimeDependent schedules are reached through assert_time_dependent_substitution.
Related
PortfolioOptimisers.set_exact_budget_constraints! — Function
set_exact_budget_constraints!(
model::Model,
sp::AbstractMIPSpace,
ind::AbstractMIPIndicators,
wx::AbstractVector{<:Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}},
ss,
_::WeightsFromParts
)
Pin the long/short decomposition, so the budgets built on lw/sw hold exactly.
lw and sw carry the long and short parts of the weights, and bgt, sbgt and gbgt are all stated in terms of them. Whether those budgets pin the realised exposure or merely bound it depends on how the head related the parts to the weights, so this dispatches on the head's AbstractDecompositionContract. Both methods take the sign from ind, whichever bundle carries one — a dedicated sign bit, or the long/short bits of a builder that already needed them for thresholds or cardinality.
Mathematical definition
Both contracts emit the sign pair, which forces sw = 0 on the long side and lw = 0 on the short side:
\[\begin{align} lw_i - M\, g^l_i &\leq 0\,, & sw_i - M\, g^s_i &\leq 0\,. \end{align}\]
Under PartsBoundWeights that leaves the held side free to overstate itself (lw_i may exceed w_i), so two more constraints close the slack:
\[\begin{align} lw_i - w_i - M(1 - b^l_i) &\leq 0\,, & sw_i + w_i - M(1 - b^s_i) &\leq 0\,. \end{align}\]
Where:
- $g^l_i$, $g^s_i$: Long and short gates (
long_gate,short_gate), which relax to continuous variables when the budget is free. - $b^l_i$, $b^s_i$: Long and short binaries (
long_bin,short_bin). The slack-closing pair keys on these rather than the gates, because it must key on a bit that is exactly 0 or 1 even when the gates relax. - $w_i$: Weight expression for position $i$ in the space of
sp. - $M$: Big-M constant.
Together they give lw_i == max(w_i, 0) and sw_i == max(-w_i, 0): b^l_i = 1 turns the first into lw_i <= w_i, which against the head's lw_i >= w_i is an equality; both bits zero gives lw_i == sw_i == 0, hence w_i == 0.
Under WeightsFromParts the pair alone is enough and the slack-closing constraints are not emitted: w = lw - sw is an identity, so sw_i = 0 already leaves lw_i == w_i.
Arguments
model::JuMP.Model: The JuMP optimisation model.sp::AbstractMIPSpace: Weight space the constraints act on.ind::AbstractMIPIndicators: Indicator bundle supplying the sign.wx::VecNum: Weight expression in the space ofsp.ss: Big-M expression, as registered byset_mip_ss_expr!.dc::AbstractDecompositionContract: The head's contract. There is deliberately no method fornothing— a model with no head contract has no short side, so there is no decomposition to pin and a caller that got here is confused.
Returns
nothing.
Related