Base Uncertainty Sets: private API
PortfolioOptimisers.UcSE_UcS — Type
const UcSE_UcS = Union{<:AbstractUncertaintySetResult, <:AbstractUncertaintySetEstimator}Alias for a union of uncertainty set result and estimator types.
Related
PortfolioOptimisers.Num_UcSK — Type
const Num_UcSK = Union{<:AbstractUncertaintyKAlgorithm, <:Number}Alias for a union of uncertainty scaling algorithm and numeric types.
Related
PortfolioOptimisers.Num_UcSEps — Type
const Num_UcSEps = Union{<:AbstractUncertaintyEpsAlgorithm, <:Number}Alias for a union of $\ell_1$ uncertainty radius algorithm and numeric types. A plain number is the radius itself; an algorithm defers its computation to the data.
Related
PortfolioOptimisers.Num_CptRad — Type
const Num_CptRad = Union{<:AbstractCompactRadiusAlgorithm, <:Number}Field bound for the compact covariance radius: the radius itself, or a rule of AbstractCompactRadiusAlgorithm that computes one.
The union names one family and no other, so a rule of any other family is refused at construction, where the caller wrote it. It admits no plain Function, because a rule of this family reads seven arguments the site settles — the metric, the loadings block, the diagonal metric and the span among them — and a closure over a caller's own data would have to restate every one of them to be called at all.
Related
PortfolioOptimisers.ucs_prior — Function
ucs_prior(pe::AbstractLowOrderPriorEstimator, X::MatNum,
F::Option{<:MatNum} = nothing; dims::Int = 1, kwargs...)
ucs_prior(::Nothing, X::MatNum, F::Option{<:MatNum} = nothing; kwargs...)Fits the prior an uncertainty set calibrates itself on, or refuses by name when the set holds none.
The one door through which every returns-data verb of the four families — DeltaUncertaintySet, NormalUncertaintySet, ARCHUncertaintySet and CharacteristicUncertaintySet — fits its pe, so the refusal is written once rather than once per verb per family. A set whose pe is nothing is calibrated on a prior result it is handed, and nothing says that one thing: it does not resolve to an empirical prior over X at the fit, because that would calibrate the same estimator on two different priors depending on the call site. The returns-data form therefore raises and points at the prior-result form, ucs(ue, pr), and at pe.
Arguments
pe: The set's own prior estimator, ornothing.X: Data matrix (e.g., returns).F: Optional factor matrix. Used by the prior estimator.dims: Dimension along which to perform the computation.kwargs...: Additional keyword arguments passed to the prior estimator.
Validation
peis notnothing. AnArgumentErrornaming the prior-result form is thrown otherwise.
Returns
pr::AbstractPriorResult: The fitted prior.
Related
PortfolioOptimisers.ucs_selector — Function
ucs_selector(risk_ucs::Nothing, prior_ucs::Nothing)
ucs_selector(risk_ucs::UcSE_UcS, prior_ucs::Any)
ucs_selector(risk_ucs::Nothing, prior_ucs::UcSE_UcS)Chooses between the uncertainty set a risk measure carries and the one a prior carries, so that the risk measure's own set outranks the prior's.
The function is a selector. It states the table below and it carries no # Algorithm section, because each of its three methods returns one of its arguments and takes no step. The three methods are exhaustive over the argument pairs the callers form, and the first row is the only one that gives nothing.
risk_ucs | prior_ucs | Result |
|---|---|---|
nothing | nothing | nothing |
a UcSE_UcS | anything | risk_ucs |
nothing | a UcSE_UcS | prior_ucs |
Arguments
risk_ucs: Risk measure uncertainty set estimator or result, ornothing.prior_ucs: Prior result uncertainty set estimator or result, ornothing.
Returns
ucs::Option{<:UcSE_UcS}: The selected set or estimator, by the table above.
Related
PortfolioOptimisers.investable_ucs_reduction — Function
investable_ucs_reduction(pr::AbstractPriorResult, rd) -> (imsk, pr, rd)
investable_ucs_reduction(::Nothing, pr::AbstractPriorResult, rd) -> (nothing, pr, rd)
investable_ucs_reduction(imsk::BitVector, pr::AbstractPriorResult, rd) -> (imsk, pr_view, rd_view)Reduce a prior result, and the returns data beside it, to the Investable Mask before a set is fitted on them standalone.
A Prior Result lives on the full asset universe, and an asset outside its Investable Mask carries NaN in its moments and in every block a factor fit wrote, so a set fitted on the whole result meets a NaN where its arithmetic needs a number. Inside an optimiser the result arrives already reduced, because every optimisation family reduces once at its entry, and the mask this verb derives is then nothing. Standalone, the result arrives whole, and this verb takes the same view the optimiser takes, so the two routes fit the same set. expand_investable_ucs writes the fitted set back onto the full universe, and the pair is the reduce-and-expand shape every prior result takes.
Three methods, and the branch is dispatch rather than a condition, as it is in investable_reduction. The first derives the mask; the nothing method is the all-investable path and returns its arguments untouched; the BitVector method takes the two views.
Algorithm
- Derive the Investable Mask from the prior result with
investable_mask. - Return
nothingand the two arguments unchanged when the mask isnothing. - Otherwise take a
port_opt_viewof the prior result atfindall(imsk), and of the returns data when it is notnothing, and return them beside the mask.
Arguments
pr: Prior result.rd: Returns data the set is fitted beside, ornothing.
Returns
(imsk, pr, rd): The Investable Mask and the two reduced to it, ornothingand the two unchanged.
Related
PortfolioOptimisers.expand_investable_ucs — Method
expand_investable_ucs(set::AbstractUncertaintySetResult, ::Nothing, pr::AbstractPriorResult) -> setWrite a set fitted on the Investable Mask back onto the full asset universe.
The nothing method is the all-investable path of investable_ucs_reduction and returns the set untouched, so a set fitted inside an optimiser, on a result that arrived reduced, pays nothing here. Each built set that a prior-result route produces adds its own BitVector method beside its port_opt_view, because the expansion is the inverse of that view: it writes the set's asset-axis blocks into a zero frame of the full width, and carries the full pr.mu or pr.sigma as val, NaN frame and all. The two rows of a view then commute, port_opt_view(expand_investable_ucs(set, imsk, pr), findall(imsk)) recovers set, which is what lets a set fitted standalone on a point-in-time prior be handed back to an optimiser on the full universe.
The method is a passthrough, so it carries no # Algorithm section.
Arguments
set: Fitted uncertainty set.imsk: The Investable Mask, ornothing.pr: Prior result.
Returns
set::AbstractUncertaintySetResult: The set on the full asset universe.
Related
PortfolioOptimisers.expand_investable_ucs — Method
expand_investable_ucs(
set::BoxUncertaintySet{<:AbstractVector{<:Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}}, <:AbstractVector{<:Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}}},
imsk::BitVector,
pr::AbstractPriorResult
) -> Union{BoxUncertaintySet{var"#s185", <:AbstractArray{var"#s137", N}, Nothing} where {var"#s137"<:(Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}), N, var"#s185"<:AbstractArray{var"#s137", N}, var"#s137"<:(Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}), N}, BoxUncertaintySet{var"#s185", var"#s1851", <:AbstractArray{var"#s137", N}} where {var"#s137"<:(Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}), N, var"#s185"<:AbstractArray{var"#s137", N}, var"#s137"<:(Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}), N, var"#s1851"<:AbstractArray{var"#s137", N}, var"#s137"<:(Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}), N}}
Write a vector BoxUncertaintySet fitted on the Investable Mask back onto the full asset universe.
The expansion is the inverse of port_opt_view: the view slices the two bounds and the centre by the asset index and touches nothing else, so a frame written outside the mask is dropped without a trace and the view recovers the fitted set. The frame is NaN, the moment's own: a bound on mu is in the units of mu and lives where mu lives, and outside the mask the prior states NaN for it. The centre is the full pr.mu.
Algorithm
- Write
set.lbandset.ubat the rows the mask keeps into twoNaNframes oflength(imsk)entries, throughexpand_vector. - Build a
BoxUncertaintySetfrom the two, withpr.muasval.
Arguments
set: Vector box uncertainty set fitted on the reduced prior.imsk: The Investable Mask of the full prior.pr: Prior result.
Returns
set::BoxUncertaintySet: The set on the full asset universe.
Related
PortfolioOptimisers.expand_investable_ucs — Method
expand_investable_ucs(
set::BoxUncertaintySet{<:AbstractMatrix{<:Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}}, <:AbstractMatrix{<:Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}}},
imsk::BitVector,
pr::AbstractPriorResult
) -> Union{BoxUncertaintySet{var"#s185", <:AbstractArray{var"#s137", N}, Nothing} where {var"#s137"<:(Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}), N, var"#s185"<:AbstractArray{var"#s137", N}, var"#s137"<:(Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}), N}, BoxUncertaintySet{var"#s185", var"#s1851", <:AbstractArray{var"#s137", N}} where {var"#s137"<:(Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}), N, var"#s185"<:AbstractArray{var"#s137", N}, var"#s137"<:(Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}), N, var"#s1851"<:AbstractArray{var"#s137", N}, var"#s137"<:(Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}), N}}
Write a matrix BoxUncertaintySet fitted on the Investable Mask back onto the full asset universe.
The expansion is the inverse of port_opt_view: the view slices the two bounds on both axes and the centre by the asset index, so a frame written outside the mask is dropped without a trace and the view recovers the fitted set. The frame is NaN, the moment's own: a bound on sigma lives where sigma lives, and outside the mask the prior states NaN for its row and column. The centre is the full pr.sigma.
Algorithm
- Write
set.lbandset.ubat(imsk, imsk)into twoNaNframes oflength(imsk)rows and columns, through the covariance method ofexpand_moment. - Build a
BoxUncertaintySetfrom the two, withpr.sigmaasval.
Arguments
set: Matrix box uncertainty set fitted on the reduced prior.imsk: The Investable Mask of the full prior.pr: Prior result.
Returns
set::BoxUncertaintySet: The set on the full asset universe.
Related
PortfolioOptimisers.expand_investable_ucs — Method
expand_investable_ucs(
set::EllipsoidalUncertaintySet{<:AbstractMatrix{<:Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}}, <:Any, <:SigmaUncertaintySetClass},
imsk::BitVector,
pr::AbstractPriorResult
) -> Union{EllipsoidalUncertaintySet{Matrix{T}, <:Number, SigmaUncertaintySetClass, Nothing} where T<:(Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}), EllipsoidalUncertaintySet{Matrix{T}, var"#s185", SigmaUncertaintySetClass, <:AbstractArray{var"#s137", N}} where {T<:(Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}), var"#s185"<:Number, var"#s137"<:(Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}), N}}
Write a covariance EllipsoidalUncertaintySet fitted on the Investable Mask back onto the full asset universe.
The expansion is the inverse of port_opt_view: the view slices the shape matrix at the fourth-moment index of the selected assets and the centre at the plain one, so a zero block written outside the mask is dropped without a trace and the view recovers the fitted set. The frame is zero and not NaN, because the shape matrix is geometry: the same set converts into a NormBallUncertaintySet whose map must be finite, and a zero row of that map moves nothing on an asset the prior could not estimate. The centre is the full pr.sigma.
Algorithm
- Take the positions the investable pairs occupy in the vectorised covariance with
coverage_pair_index, which orders them asfourth_moment_index_generatordoes. - Allocate a zero frame of
length(imsk)^2rows and columns, and writeset.sigmaat those positions on both axes. - Build an
EllipsoidalUncertaintySetfrom it, carryingkandclassthrough unchanged andpr.sigmaasval.
Arguments
set: Covariance ellipsoidal uncertainty set fitted on the reduced prior.imsk: The Investable Mask of the full prior.pr: Prior result.
Returns
set::EllipsoidalUncertaintySet: The set on the full asset universe.
Related
PortfolioOptimisers.expand_investable_ucs — Method
expand_investable_ucs(
set::EllipsoidalUncertaintySet{<:AbstractMatrix{<:Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}}, <:Any, <:MuUncertaintySetClass},
imsk::BitVector,
pr::AbstractPriorResult
) -> Union{EllipsoidalUncertaintySet{Matrix{T}, <:Number, MuUncertaintySetClass, Nothing} where T<:(Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}), EllipsoidalUncertaintySet{Matrix{T}, var"#s185", MuUncertaintySetClass, <:AbstractArray{var"#s137", N}} where {T<:(Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}), var"#s185"<:Number, var"#s137"<:(Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}), N}}
Write a mean EllipsoidalUncertaintySet fitted on the Investable Mask back onto the full asset universe.
The expansion is the inverse of port_opt_view: the view slices the shape matrix on both axes and the centre by the asset index, so a zero row and column written outside the mask are dropped without a trace and the view recovers the fitted set. The frame is zero and not NaN, because the shape matrix is geometry: the same set converts into a NormBallUncertaintySet whose map must be finite, and a zero row of that map moves nothing on an asset the prior could not estimate. The centre is the full pr.mu.
Algorithm
- Allocate a zero frame of
length(imsk)rows and columns, and writeset.sigmaat(imsk, imsk). - Build an
EllipsoidalUncertaintySetfrom it, carryingkandclassthrough unchanged andpr.muasval.
Arguments
set: Mean ellipsoidal uncertainty set fitted on the reduced prior.imsk: The Investable Mask of the full prior.pr: Prior result.
Returns
set::EllipsoidalUncertaintySet: The set on the full asset universe.
Related
PortfolioOptimisers.vec_quantile_bounds — Function
vec_quantile_bounds(mus::MatNum, q::Number, kwargs)Element-wise lower and upper quantile bounds for a vector-valued statistic.
Shared by the bootstrap box ucs and mu_ucs mean constructions. The sample axis is the second one: the body reads mus[j, :], so mus is $N \times M$, one row per component and one column per sample. A caller that passes the transpose gets bounds of length $M$, which the BoxUncertaintySet constructor accepts, so the axis is a contract this method cannot check.
Algorithm
- Read
N = size(mus, 1), the number of components, and allocatelbandubof that length and ofeltype(mus). - For each component
j, read the rowmu_j = mus[j, :], theMsampled values of that component. - Write the
qquantile ofmu_jintolb[j]and the1 - qquantile intoub[j]. - Return
lbandub. They satisfylb .<= ubentrywise, and they bracket the sample mean of each component.
Arguments
mus: Sampled values, $N \times M$, one row per component.q: Significance level, already halved by the caller.kwargs: Splatted intoStatistics.quantile.
Returns
lb::Vector: Element-wise lower bound, length $N$.ub::Vector: Element-wise upper bound, length $N$.
Related
PortfolioOptimisers.ellipsoidal_set — Function
ellipsoidal_set(diagonal::Bool, method, q::Number, samples, cov::MatNum,
class::AbstractUncertaintySetClass,
val::Option{<:ArrNum} = nothing)Assemble an EllipsoidalUncertaintySet from an already-computed asymptotic covariance cov.
Shared by every ellipsoidal ucs, mu_ucs and sigma_ucs construction across estimator families. k_ucs absorbs the trailing arguments its own algorithm does not read, so samples may be the deviation matrix, a 1:n_sim range, or nothing, whichever the caller has.
The order of the two steps below is load-bearing. The diagonal is taken before the radius is fitted, so under the diagonal = true default an empirical radius is a quantile of Mahalanobis distances measured against the diagonal shape and not against the full one, and neither shape reliably gives the larger radius. Taking the diagonal afterwards would pair a radius calibrated on one shape with a different shape, and the set would not hold the coverage its significance level names.
Algorithm
- When
diagonalistrue, replacecovwithLinearAlgebra.Diagonal(cov), discarding the estimation-error correlations between entries. The result is stored as aDiagonal, not as a dense matrix. - Compute
k = k_ucs(method, q, samples, cov), the radius, measured against whichever shape step 1 left. - Build an
EllipsoidalUncertaintySetfromcov,k,classandval.
Arguments
diagonal: Whether to restrictcovto its diagonal before the radius is fitted.method: Radius algorithm, or the radius itself as aNumber.q: Significance level.samples: Sampled estimation errors, or whatever containermethodreads. An algorithm that runs no simulation absorbs it.cov: Asymptotic covariance of the statistic, which becomes the shape matrix.class: Axis tag, which fixes the size of the shape matrix and the index a view applies.val: Quantity the set is a neighbourhood of — the fitted characteristic vector on the mean axis, the fitted covariance on the covariance axis. Every caller has it in hand, because every one of them fits a prior before it calls here.
Returns
ucs::EllipsoidalUncertaintySet: The assembled set.
Related
PortfolioOptimisers.box_quantile_bounds — Function
box_quantile_bounds(::Type{TE}, get_ij, N::Integer, q::Number, kwargs) where {TE}Element-wise lower and upper quantile bounds for a symmetric $N \times N$ statistic.
Shared by the box ucs and sigma_ucs constructions across estimator families. The get_ij accessor is what lets one body serve them all: it bridges the Wishart sample container, a vector of matrices, and the bootstrap one, a three-dimensional array. Positive-definite projection, if any, is applied by the caller.
Algorithm
- Allocate
lbandub, bothN × Nand of element typeTE. - For each ordered pair with
j <= i, reads_ij = get_ij(i, j), the sampled values of that entry. - Write the
qquantile ofs_ijinto bothlb[i, j]andlb[j, i], and the1 - qquantile into bothub[i, j]andub[j, i]. Writing each quantile to both positions makes the two bounds symmetric by construction, and it costs one quantile per pair rather than two. - Return
lbandub. They satisfylb .<= ubentrywise, becauseqis the smaller quantile level of the same sample, and the sample mean of the statistic lies between them.
Arguments
TE: Element type of the two bounds.get_ij: Accessor.get_ij(i, j)returns the vector of sampled values for entry $(i, j)$.N: Side of the statistic.q: Significance level, already halved by the caller.kwargs: Splatted intoStatistics.quantile.
Returns
lb::Matrix{TE}: Element-wise lower bound, symmetric.ub::Matrix{TE}: Element-wise upper bound, symmetric.
Related