ℓ1 Uncertainty Sets

PortfolioOptimisers.L1UncertaintySetType
struct L1UncertaintySet{__T_eps, __T_sd, __T_mu} <: AbstractUncertaintySetResult

$\ell_1$ (cross-polytope) uncertainty set on the characteristic vector.

The set is $\mathcal{S} = \{\hat{\boldsymbol{\mu}} + \boldsymbol{e} : \lVert \boldsymbol{e} \oslash \boldsymbol{\sigma} \rVert_1 \leq \epsilon\}$, with a single error budget shared across every asset and both signs. Produced by CharacteristicUncertaintySet and consumed by ArithmeticReturn. It bounds a mean/characteristic vector alone, and has no covariance analogue.

Mathematical definition

The worst case of a linear characteristic over the set collapses to a scaled infinity norm (Lemmas 1 and 8 of [4]):

\[\underset{\boldsymbol{\mu} \in \mathcal{S}}{\min}\, \boldsymbol{\mu}^{\intercal} \boldsymbol{w} = \hat{\boldsymbol{\mu}}^{\intercal} \boldsymbol{w} - \epsilon \lVert \boldsymbol{\sigma} \odot \boldsymbol{w} \rVert_{\infty}\,.\]

Where:

  • $\hat{\boldsymbol{\mu}}$: Estimated characteristic vector.
  • $\epsilon$: Radius of the set.
  • $\boldsymbol{\sigma}$: Per-asset scaling (sd); $\boldsymbol{1}$ when sd is nothing.
  • $\odot$, $\oslash$: Element-wise product and division.

Because the right-hand side is concave and positively homogeneous, this is an LP once the infinity norm is epigraphed — no conic solver is needed.

Fields

  • eps: Radius of the $\ell_1$ uncertainty set on the characteristic vector. Larger values admit more estimation error, and therefore activate more assets.
  • sd: Per-asset scaling vector for the $\ell_1$ uncertainty set (the estimated standard deviations). nothing leaves the set unscaled, so every element of the characteristic vector is assumed to suffer the same estimation error.
  • mu: Characteristic vector the $\ell_1$ set is a neighbourhood of. nothing defers to the consumer's own characteristic. When it is set, it takes precedence over the returns estimator's field and over the prior.

Constructors

L1UncertaintySet(;    eps::Number,    sd::Option{<:VecNum} = nothing,    mu::Option{<:VecNum} = nothing) -> L1UncertaintySet

Keywords correspond to the struct's fields.

Validation

  • isfinite(eps) and eps >= 0.
  • If sd is provided: !isempty(sd) and all(sd .> 0).
  • If mu is provided: !isempty(mu) and all(isfinite, mu).
  • If both sd and mu are provided: length(mu) == length(sd).

Examples

julia> L1UncertaintySet(; eps = 0.1)L1UncertaintySet  eps ┼ Float64: 0.1   sd ┼ nothing   mu ┴ nothing

Related

References

  • [4] R. Zhou and D. P. Palomar. Understanding the Quintile Portfolio. IEEE Transactions on Signal Processing 68, 4030–4040 (2020).
source
PortfolioOptimisers.SignedL1UncertaintySetType
struct SignedL1UncertaintySet{__T_ep, __T_en, __T_sd, __T_mu} <: AbstractUncertaintySetResult

Signed $\ell_1$ uncertainty set on the characteristic vector, with a separate error budget per sign.

The set is $\mathcal{A}_2 = \{\hat{\boldsymbol{\mu}} + \boldsymbol{e} : \boldsymbol{1}^{\intercal} [\boldsymbol{e} \oslash \boldsymbol{\sigma}]_{+} \leq \epsilon_{+},\, -\boldsymbol{1}^{\intercal} [\boldsymbol{e} \oslash \boldsymbol{\sigma}]_{-} \leq \epsilon_{-}\}$. It bounds a mean/characteristic vector alone, and has no covariance analogue. [4] introduces it in order to decouple the long-short problem into two independent problems (its equations 27 and 28), which its Remark 12 then recombines only when the two legs happen to have complementary support; modelling the worst case below directly keeps the problem coupled, so that caveat does not arise.

Mathematical definition

\[\underset{\boldsymbol{\mu} \in \mathcal{A}_2}{\min}\, \boldsymbol{\mu}^{\intercal} \boldsymbol{w} = \hat{\boldsymbol{\mu}}^{\intercal} \boldsymbol{w} - \epsilon_{+} \left[\underset{i}{\max}\, (-\sigma_i w_i)\right]_{+} - \epsilon_{-} \left[\underset{i}{\max}\, (\sigma_i w_i)\right]_{+}\,.\]

Where:

  • $\epsilon_{+}$, $\epsilon_{-}$: Radii of the positive- and negative-error sides (ep, en).
  • $[\cdot]_{+}$, $[\cdot]_{-}$: Element-wise positive and negative parts.

Still concave and LP-representable, with one epigraph variable per sign.

Setting $\epsilon_{+} = \epsilon_{-}$ does not recover $\mathcal{S}$: the joint set shares one budget across both signs, giving $\max(t_{+}, t_{-})$, whereas this one spends a budget per sign, giving $\epsilon_{+} t_{+} + \epsilon_{-} t_{-}$. The two worst cases agree only when $\boldsymbol{w}$ is single-signed.

Fields

  • ep: Radius of the positive-error side of the signed $\ell_1$ uncertainty set.
  • en: Radius of the negative-error side of the signed $\ell_1$ uncertainty set.
  • sd: Per-asset scaling vector for the $\ell_1$ uncertainty set (the estimated standard deviations). nothing leaves the set unscaled, so every element of the characteristic vector is assumed to suffer the same estimation error.
  • mu: Characteristic vector the $\ell_1$ set is a neighbourhood of. nothing defers to the consumer's own characteristic. When it is set, it takes precedence over the returns estimator's field and over the prior.

Constructors

SignedL1UncertaintySet(;    ep::Number,    en::Number,    sd::Option{<:VecNum} = nothing,    mu::Option{<:VecNum} = nothing) -> SignedL1UncertaintySet

Keywords correspond to the struct's fields.

Validation

  • isfinite(ep) and ep >= 0.
  • isfinite(en) and en >= 0.
  • If sd is provided: !isempty(sd) and all(sd .> 0).
  • If mu is provided: !isempty(mu) and all(isfinite, mu).
  • If both sd and mu are provided: length(mu) == length(sd).

Examples

julia> SignedL1UncertaintySet(; ep = 0.1, en = 0.2)SignedL1UncertaintySet  ep ┼ Float64: 0.1  en ┼ Float64: 0.2  sd ┼ nothing  mu ┴ nothing

Related

References

  • [4] R. Zhou and D. P. Palomar. Understanding the Quintile Portfolio. IEEE Transactions on Signal Processing 68, 4030–4040 (2020).
source
PortfolioOptimisers.L1UncertaintySetAlgorithmType
struct L1UncertaintySetAlgorithm{__T_method, __T_scaled, __T_paired} <: AbstractUncertaintySetAlgorithm

Shape algorithm selecting a joint $\ell_1$ uncertainty set.

scaled picks between the two sets of [4]: false gives $\mathcal{S}$ (its equation 5) and true gives $\mathcal{A}_1$ (its equation 18). It defaults to false because $\mathcal{S}$ is the base construction of the paper, the one whose closed forms give the $1/N$ and quintile portfolios. SignedL1UncertaintySetAlgorithm defaults the other way, because the paper defines its set only in the scaled form.

Fields

  • scaled: Whether to scale the uncertainty set by the estimated standard deviations. false assumes every characteristic suffers the same estimation error; true assumes assets with larger variance suffer larger estimation error, which yields inverse-volatility weights.
  • paired: paired: Which closed form calibrates the radius when method is an AbstractUncertaintyEpsAlgorithm. The number of assets a radius activates depends on the sign structure of the problem it is used in, which an uncertainty set cannot observe, so the caller must say. false takes the long-only ladder, for a problem with w >= 0 and bgt = 1 (Corollaries 4 and 11 of [4]). true takes the paired ladder, for a dollar-neutral problem with bgt = 0 and sbgt = 1/2, where assets activate in long/short pairs (Corollary 7). Using the wrong one mis-calibrates the radius; it does not make the optimisation incorrect. Inert when method is a number.

Constructors

L1UncertaintySetAlgorithm(;    method::Num_UcSEps = ActiveAssetsUncertaintyAlgorithm(),    scaled::Bool = false,    paired::Bool = false) -> L1UncertaintySetAlgorithm

Keywords correspond to the struct's fields.

Validation

  • If method is a Number: isfinite(method) and method >= 0.

Examples

julia> L1UncertaintySetAlgorithm()L1UncertaintySetAlgorithm  method ┼ ActiveAssetsUncertaintyAlgorithm         │   active ┴ Float64: 0.2  scaled ┼ Bool: false  paired ┴ Bool: false

Related

References

  • [4] R. Zhou and D. P. Palomar. Understanding the Quintile Portfolio. IEEE Transactions on Signal Processing 68, 4030–4040 (2020).
source
PortfolioOptimisers.SignedL1UncertaintySetAlgorithmType
struct SignedL1UncertaintySetAlgorithm{__T_mp, __T_mm, __T_scaled} <: AbstractUncertaintySetAlgorithm

Shape algorithm selecting a signed $\ell_1$ uncertainty set.

The two ladders are fixed by the construction of [4] and need no paired flag: $\epsilon_{-}$ governs the long leg and is calibrated against the top of the ranking, $\epsilon_{+}$ governs the short leg and is calibrated against the bottom (its Corollary 13). scaled defaults to true because the paper defines $\mathcal{A}_2$ only in the volatility-scaled form, and states Corollary 13 in that form alone. L1UncertaintySetAlgorithm defaults the other way, because its base set carries no scaling.

Fields

  • scaled: Whether to scale the uncertainty set by the estimated standard deviations. false assumes every characteristic suffers the same estimation error; true assumes assets with larger variance suffer larger estimation error, which yields inverse-volatility weights.

Constructors

SignedL1UncertaintySetAlgorithm(;    mp::Num_UcSEps = ActiveAssetsUncertaintyAlgorithm(),    mm::Num_UcSEps = ActiveAssetsUncertaintyAlgorithm(),    scaled::Bool = true) -> SignedL1UncertaintySetAlgorithm

Keywords correspond to the struct's fields.

Validation

  • If mp/mm is a Number: isfinite and >= 0.

Examples

julia> SignedL1UncertaintySetAlgorithm()SignedL1UncertaintySetAlgorithm      mp ┼ ActiveAssetsUncertaintyAlgorithm         │   active ┴ Float64: 0.2      mm ┼ ActiveAssetsUncertaintyAlgorithm         │   active ┴ Float64: 0.2  scaled ┴ Bool: true

Related

References

  • [4] R. Zhou and D. P. Palomar. Understanding the Quintile Portfolio. IEEE Transactions on Signal Processing 68, 4030–4040 (2020).
source
PortfolioOptimisers.CharacteristicUncertaintySetType
struct CharacteristicUncertaintySet{__T_pe, __T_alg} <: AbstractUncertaintySetEstimator

Fits an $\ell_1$ uncertainty set on the characteristic vector, mean-only and with a calibrated radius.

pe supplies both the characteristic vector $\hat{\boldsymbol{\mu}}$ and, when the shape algorithm is scaled, the per-asset scaling $\hat{\boldsymbol{\sigma}} = \sqrt{\mathrm{diag}(\hat{\mathbf{\Sigma}})}$. The sets are the robust best-characteristic sets of [4]. Maximising the worst-case characteristic over one of them recovers the heuristic $1/N$, quintile, and inverse-volatility portfolios as exact solutions of a robust optimisation problem, with the radius controlling how many assets are held — which is why this library ships no dedicated quintile optimiser. Compose the set with MeanRisk instead:

MeanRisk(; r = NoRisk(), obj = MaximumReturn(),         opt = JuMPOptimiser(; slv = slv, bgt = 1.0,                             ret = ArithmeticReturn(; ucs = CharacteristicUncertaintySet())))

Fields

  • pe: Prior estimator the set fits on the returns it is handed, or nothing. With nothing the set holds no prior of its own and is calibrated on the prior result it is handed — inside an optimiser, the prior the optimiser is solving on, so its centre is the objective's own — through the prior-result arm of the ucs triple; the returns-data form then refuses by name. The default, EmpiricalPrior(), fits an empirical prior on the returns.

Constructors

CharacteristicUncertaintySet(;    pe::Option{<:AbstractLowOrderPriorEstimator} = EmpiricalPrior(),    alg::AbstractUncertaintySetAlgorithm = L1UncertaintySetAlgorithm()) -> CharacteristicUncertaintySet

Keywords correspond to the struct's fields.

Validation

Examples

The radius is calibrated, not given. Three assets whose sample means are $0.125$, $0.0625$ and $0.03125$ give the activation ladder $[0, 0.0625, 0.125]$, and the default active of 0.2 targets one active asset, so the radius is the midpoint of the first rung and the second:

julia> X = [0.1875 0.09375 0.0625            0.0625 0.03125 0.0];julia> mu_ucs(CharacteristicUncertaintySet(), X)L1UncertaintySet  eps ┼ Float64: 0.03125   sd ┼ nothing   mu ┴ Vector{Float64}: [0.125, 0.0625, 0.03125]

Related

References

  • [4] R. Zhou and D. P. Palomar. Understanding the Quintile Portfolio. IEEE Transactions on Signal Processing 68, 4030–4040 (2020).
source
PortfolioOptimisers.ActiveAssetsUncertaintyAlgorithmType
struct ActiveAssetsUncertaintyAlgorithm{__T_active} <: AbstractUncertaintyEpsAlgorithm

Calibrates the $\ell_1$ uncertainty radius to a target number of active assets.

The radius $\epsilon$ of an $\ell_1$ uncertainty set has no natural scale — it is a sum of characteristic differences, so on daily returns it is of order $10^{-3}$, and on annualised returns roughly $250$ times larger. This algorithm converts the quantity a caller can reason about (how many assets should the portfolio hold?) into the radius that produces it, by inverting the closed forms of [4]. The inversion is exact, and only for the bare problem those closed forms assume: the budget and sign constraints, and nothing else.

Fields

  • active: Target number of active assets on the unconstrained problem, as a count (integer >= 1) or a fraction of the universe (float in (0, 1)). This is a radius calibration, not a cardinality constraint: it selects the radius that would activate this many assets subject only to the budget and sign constraints. Any further constraint may change the realised count. Use card for a hard cardinality constraint.

Constructors

ActiveAssetsUncertaintyAlgorithm(;    active::Union{<:Integer, <:AbstractFloat} = 0.2) -> ActiveAssetsUncertaintyAlgorithm

Keywords correspond to the struct's fields.

Validation

  • If active is an Integer: active >= 1.
  • If active is an AbstractFloat: 0 < active < 1.

The type of active decides which rule applies, so the boundary is sharp: active = 1 is a count of one asset and is accepted, while active = 1.0 is the whole universe as a fraction and is rejected.

Examples

julia> ActiveAssetsUncertaintyAlgorithm()ActiveAssetsUncertaintyAlgorithm  active ┴ Float64: 0.2

Related

References

  • [4] R. Zhou and D. P. Palomar. Understanding the Quintile Portfolio. IEEE Transactions on Signal Processing 68, 4030–4040 (2020).
source
PortfolioOptimisers.port_opt_viewMethod
port_opt_view(
    risk_ucs::L1UncertaintySet,
    i,
    args...
) -> L1UncertaintySet

Return a view of an L1UncertaintySet restricted to the asset indices i.

The radius is a scalar budget shared across the universe, so it passes through unchanged; the per-asset scaling and the carried characteristic are sliced. The slice preserves the order of i, so the restricted set indexes the assets in the order the optimiser hands it.

Algorithm

  1. Take nothing_scalar_array_view(risk_ucs.sd, i), the per-asset scaling restricted to the selected assets, which passes a nothing through unchanged.
  2. Take nothing_scalar_array_view(risk_ucs.mu, i), the carried characteristic restricted to the same assets, which passes a nothing through unchanged.
  3. Build an L1UncertaintySet from risk_ucs.eps and the two views. The radius is not rescaled, because it budgets the total error across whichever assets the set covers.

Arguments

  • risk_ucs: $\ell_1$ uncertainty set.
  • i: Cluster or asset index.
  • args...: Additional positional arguments (ignored).

Returns

  • risk_ucs::L1UncertaintySet: The set restricted to i.

Examples

julia> ucs = L1UncertaintySet(; eps = 0.5, sd = [0.1, 0.2, 0.3], mu = [0.05, 0.03, 0.01]);julia> PortfolioOptimisers.port_opt_view(ucs, [1, 3])L1UncertaintySet  eps ┼ Float64: 0.5   sd ┼ SubArray{Float64, 1, Vector{Float64}, Tuple{Vector{Int64}}, false}: [0.1, 0.3]   mu ┴ SubArray{Float64, 1, Vector{Float64}, Tuple{Vector{Int64}}, false}: [0.05, 0.01]

Related

source
PortfolioOptimisers.port_opt_viewMethod
port_opt_view(
    risk_ucs::SignedL1UncertaintySet,
    i,
    args...
) -> SignedL1UncertaintySet

Return a view of a SignedL1UncertaintySet restricted to the asset indices i.

Both radii are scalar budgets shared across the universe, so they pass through unchanged; the per-asset scaling and the carried characteristic are sliced. The slice preserves the order of i, so the restricted set indexes the assets in the order the optimiser hands it.

Algorithm

  1. Take nothing_scalar_array_view(risk_ucs.sd, i), the per-asset scaling restricted to the selected assets, which passes a nothing through unchanged.
  2. Take nothing_scalar_array_view(risk_ucs.mu, i), the carried characteristic restricted to the same assets, which passes a nothing through unchanged.
  3. Build a SignedL1UncertaintySet from risk_ucs.ep, risk_ucs.en and the two views. Neither radius is rescaled, because each budgets the total error of its own sign across whichever assets the set covers.

Arguments

  • risk_ucs: Signed $\ell_1$ uncertainty set.
  • i: Cluster or asset index.
  • args...: Additional positional arguments (ignored).

Returns

  • risk_ucs::SignedL1UncertaintySet: The set restricted to i.

Examples

julia> ucs = SignedL1UncertaintySet(; ep = 0.4, en = 0.6, sd = [0.1, 0.2, 0.3],                                    mu = [0.05, 0.03, 0.01]);julia> PortfolioOptimisers.port_opt_view(ucs, [1, 3])SignedL1UncertaintySet  ep ┼ Float64: 0.4  en ┼ Float64: 0.6  sd ┼ SubArray{Float64, 1, Vector{Float64}, Tuple{Vector{Int64}}, false}: [0.1, 0.3]  mu ┴ SubArray{Float64, 1, Vector{Float64}, Tuple{Vector{Int64}}, false}: [0.05, 0.01]

Related

source
PortfolioOptimisers.mu_ucsFunction
mu_ucs(ue::CharacteristicUncertaintySet, X::MatNum,
       F::Option{<:MatNum} = nothing; dims::Int = 1, kwargs...)
mu_ucs(ue::CharacteristicUncertaintySet{Nothing}, pr::AbstractPriorResult; rd = nothing, kwargs...)

Construct an $\ell_1$ uncertainty set on the characteristic vector, from the set's own prior fitted on returns data or from a prior result the set is handed.

The two signatures are the two routes a set with a pe field takes and share one tail. The returns-data method fits ue.pe once through ucs_prior, which refuses a pe of nothing by name, and hands the result to the prior-result method of the same set with its pe set to nothing, which is where the two shapes are dispatched. The prior-result method is defined only for a set whose pe is nothing: inside an optimiser pr is the prior the optimiser is solving on, so the characteristic vector the radius is calibrated on is the objective's own mu.

The calibration runs on the ranking, and the set is returned in the universe's own order: mu and sd carry one entry per asset in the order the prior produced them, which is the order the optimiser indexes and the order port_opt_view slices. Only the ladders see the sorted vector, and a ladder needs no asset identity. The set carries $\hat{\boldsymbol{\mu}}$ in its mu field, so the consumer bounds the characteristic vector the radius was calibrated on.

Algorithm

The returns-data method runs step 1 and forwards; the two prior-result methods share steps 2 to 4 and differ in the fifth.

  1. Fit the prior with ucs_prior on ue.pe, X and F, giving pr, and forward to the prior-result method of the set with pe = nothing.
  2. Read alg = ue.alg, the shape algorithm.
  3. When alg.scaled, take sd = sqrt.(diag(pr.sigma)), the per-asset scaling; otherwise take nothing.
  4. Take idx = sortperm(pr.mu; rev = true), the ranking that sorts the characteristic non-increasing, and apply it to pr.mu and to sd.
  5. Resolve the radii with l1_resolve_eps against the sorted vectors, and build the set from them with mu = pr.mu and sd in the universe's order.

For an L1UncertaintySetAlgorithm step 5 resolves the single radius eps from alg.method, passing alg.paired, and builds an L1UncertaintySet.

For a SignedL1UncertaintySetAlgorithm step 5 resolves two radii against two ladders and builds a SignedL1UncertaintySet. en comes from alg.mm on the sorted ranking, and ep from alg.mp on the reversed, negated ranking, which is the same ladder read from the other end (Corollary 13 of [4]). Neither call passes paired, because the construction fixes both ladders. The consumer spends en against $\max_i (\sigma_i w_i)$ and ep against $\max_i (-\sigma_i w_i)$, so en prices the long leg and ep the short one, matching the end each was calibrated against.

Arguments

  • ue: Characteristic uncertainty set estimator.
  • X: Data matrix (e.g. returns).
  • F: Optional factor matrix. Used by the prior estimator.
  • dims: Dimension along which to perform the computation.
  • pr: Fitted prior result the set is calibrated on. pr.mu is read, and pr.sigma when alg.scaled.
  • rd: Returns result the three-argument form passes beside the prior. Not read.
  • kwargs...: Additional keyword arguments passed to the prior estimator.

Returns

  • mu_ucs::Union{<:L1UncertaintySet, <:SignedL1UncertaintySet}: The uncertainty set.

Examples

julia> X = [0.1875 0.09375 0.0625            0.0625 0.03125 0.0];julia> alg = SignedL1UncertaintySetAlgorithm(; scaled = false);julia> mu_ucs(CharacteristicUncertaintySet(; alg = alg), X)SignedL1UncertaintySet  ep ┼ Float64: 0.015625  en ┼ Float64: 0.03125  sd ┼ nothing  mu ┴ Vector{Float64}: [0.125, 0.0625, 0.03125]

Related

References

  • [4] R. Zhou and D. P. Palomar. Understanding the Quintile Portfolio. IEEE Transactions on Signal Processing 68, 4030–4040 (2020).
source
PortfolioOptimisers.ucsFunction
ucs(ue::CharacteristicUncertaintySet, X::MatNum, F::Option{<:MatNum} = nothing; kwargs...)
sigma_ucs(ue::CharacteristicUncertaintySet, X::MatNum, F::Option{<:MatNum} = nothing; kwargs...)
ucs(ue::CharacteristicUncertaintySet{Nothing}, pr::AbstractPriorResult; kwargs...)
sigma_ucs(ue::CharacteristicUncertaintySet{Nothing}, pr::AbstractPriorResult; kwargs...)

Always throw. CharacteristicUncertaintySet is mean-only.

All four methods are refusals rather than procedures, so none carries an # Algorithm section. The returns-data pair takes the same (X, F) signature as the rest of the family rather than a catch-all, so that the ReturnsResult forwarders in the base reach them without ambiguity, and the prior-result pair takes the signature the family's prior-result arm shares, so that the three-argument routing of a set with no prior of its own reaches the same refusal.

Arguments

  • ue: Characteristic uncertainty set estimator.
  • X: Data matrix (e.g. returns).
  • F: Optional factor matrix.
  • pr: Fitted prior result (ignored).
  • kwargs...: Additional keyword arguments (ignored).

Validation

  • Both methods always throw an ArgumentError. The $\ell_1$ set bounds a characteristic (mean) vector, [4] defines no covariance analogue, and there is therefore no covariance set to return. Each message names the fix: mu_ucs for the mean set, and NormalUncertaintySet, DeltaUncertaintySet or ARCHUncertaintySet for a covariance set.

Returns

  • Neither method returns. Both throw.

Related

References

  • [4] R. Zhou and D. P. Palomar. Understanding the Quintile Portfolio. IEEE Transactions on Signal Processing 68, 4030–4040 (2020).
source
PortfolioOptimisers.l1_resolve_epsFunction
l1_resolve_eps(method, mus::VecNum, sds::Option{<:VecNum}, paired::Bool)

Resolve a radius from a Num_UcSEps against the characteristic vector.

mus must be sorted in non-increasing order, with sds under the same permutation. The method that takes a Number is a passthrough: it returns the radius the caller gave, runs no procedure, and carries neither an # Algorithm nor a # Validation section. The method that takes an ActiveAssetsUncertaintyAlgorithm calibrates against the long-only ladder when paired is false, and against the paired ladder when it is true.

Mathematical definition

The paired ladder adds the ladder of the ranking to the ladder of the reversed, negated ranking, which is Lemma 6 of [4]:

\[\begin{align} F_m &= \sum_{i=1}^{m} \frac{\hat{\mu}_i - \hat{\mu}_m}{\sigma_i} + \sum_{j=1}^{m} \frac{\hat{\mu}_{N-m+1} - \hat{\mu}_{N-j+1}}{\sigma_{N-j+1}}\,, \quad m = 1,\, \ldots,\, \left\lfloor N/2 \right\rfloor\,. \end{align}\]

Where:

  • $F_m$: Activation threshold of the $m$-th long/short pair.
  • $\hat{\mu}_i$: $i$-th entry of the characteristic vector, sorted non-increasing.
  • $\sigma_i$: Per-asset scaling of the $i$-th entry of the characteristic vector; $1$ when the set is unscaled.
  • $N$: Number of assets.

A radius in $(F_q,\, F_{q+1})$ makes the top $q$ assets long and the bottom $q$ short, so it activates $2q$ assets (Corollary 7). Lemma 5 gives the reason the ladder stops at $\lfloor N/2 \rfloor$: an optimal dollar-neutral solution satisfies $w_i = -w_{N+1-i}$, so with an odd $N$ the middle asset pairs with itself, its weight solves $w = -w$, and it is never active. The largest count the paired branch can reach is therefore $2 \lfloor N/2 \rfloor$, which is $N-1$ when $N$ is odd.

Algorithm

  1. Read N = length(mus), the size of the universe.
  2. When paired is false, build the long-only ladder with l1_activation_ladder, convert method.active to a count with l1_active_count, and return the radius l1_eps_from_ladder resolves against them.
  3. Otherwise read half = N ÷ 2, the number of pairs the universe admits.
  4. Add the ladder of mus to the ladder of the reversed, negated ranking and keep the first half entries, giving ladder, the paired ladder.
  5. Halve the target: an Integer active counts assets and gives max(active ÷ 2, 1) pairs; an AbstractFloat active is a fraction of the universe and gives clamp(round(Int, active * N / 2), 1, half) pairs. Both name pairs, so a count and the matching fraction agree whenever the count is even. An odd count truncates while the matching fraction rounds to nearest, so the two can differ by one pair: active = 7 gives three pairs and active = 7/N gives four.
  6. Return the radius l1_eps_from_ladder resolves against ladder and the pair count.

Arguments

  • method: A radius (Number) or an ActiveAssetsUncertaintyAlgorithm.
  • mus: Characteristic vector, sorted in non-increasing order.
  • sds: Per-asset scaling under the same permutation, or nothing.
  • paired: Whether to calibrate against the paired ladder rather than the long-only one.

Validation

  • N ÷ 2 >= 1 when paired is true, otherwise an ArgumentError is thrown. A single asset admits no long/short pair, so no paired ladder exists to calibrate against.

Returns

  • eps::Number: The resolved radius.

Examples

julia> PortfolioOptimisers.l1_resolve_eps(0.25)0.25julia> alg = ActiveAssetsUncertaintyAlgorithm(; active = 2);julia> mus = [0.125, 0.0625, 0.03125, 0.0];julia> PortfolioOptimisers.l1_resolve_eps(alg, mus, nothing, false)0.09375julia> PortfolioOptimisers.l1_resolve_eps(alg, mus, nothing, true)0.046875

Related

References

  • [4] R. Zhou and D. P. Palomar. Understanding the Quintile Portfolio. IEEE Transactions on Signal Processing 68, 4030–4040 (2020).
source

References

[4]
R. Zhou and D. P. Palomar. Understanding the Quintile Portfolio. IEEE Transactions on Signal Processing 68, 4030–4040 (2020).