Orthogonal Uncertainty Sets: private API
PortfolioOptimisers.latest_orthogonality_weights — Function
latest_orthogonality_weights(::Nothing, name::Symbol, rr::AbstractLoadingsRegressionResult)
latest_orthogonality_weights(w::MatNum, name::Symbol, ::AbstractLoadingsRegressionResult)Last row of a cross-sectional weight history, checked as a metric.
Algorithm
- On a
nothinghistory, throw. The block declares the field and this fit left it unset, which the message says. - On a history, take its last row, the weights of the latest observation. The uncertainty set is built for the next decision, so it reads the newest cross-section and not an average of the sample.
Arguments
w: Weight history,observations × assets, ornothing.name: Name of the field the history came from, which the refusals quote.rr: Fitted loadings block, quoted by the refusals.
Validation
!isempty(w), else anIsEmptyError.- Every entry of the last row is finite and
> 0, else aDomainError. A weight of zero excluded its asset from the fit, and an excluded asset gives the metric a singular direction. The case is not a point-in-time gap the Investable Mask removes: an asset can be investable, with a finite return and a stated moment, and still sit outside the estimation universe of the latest cross-section, so its weight is zero while its loadings and variance are finite. The two metrics that read no weight history,InverseIdiosyncraticVarianceMetricandIdentityMetric, are the way round it.
Returns
w::VecNum: Weights of the latest observation, one entry per asset.
Related
PortfolioOptimisers.cs_diagnostic_weight_history — Function
cs_diagnostic_weight_history(A::Nothing, name::AbstractString, what::AbstractString)
cs_diagnostic_weight_history(A::MatNum, name::AbstractString, what::AbstractString)Return a weight history of a factor model block, or refuse an absent one by name.
Arguments
A: The field of the block the metric names, ornothing.name: Name of that field, which the refusal states.what: What the field holds, which the refusal states.
Returns
A::MatNum: The history.
Related
PortfolioOptimisers.orthogonal_factor_span — Function
orthogonal_factor_span(
ue::OrthogonalUncertaintySet,
pr::AbstractPriorResult
) -> Tuple{Any, Any, Any}
Weighted factor span of the prior's loadings block, the geometry both sets are built from.
Algorithm
- Refuse when
pr.rrisnothing. The set reads the loadings off the prior result, and a prior that fitted no factor model carries none. - Read the effective loadings
rr.L, which reads back asrr.Mwhen no Factor Family was re-based, so a re-based model is already reduced to a full-rank basis here. Refuse a row that is not finite: a singular value decomposition of such a row is not a span but a LAPACK error. The fit never meets theNaNrows a point-in-time Asset Panel writes outside the Investable Mask, because the optimiser's builders hand it the prior reduced to that mask and the standalone verbs reduce to it first throughinvestable_ucs_reduction. A non-finite row that reaches here therefore sits on an asset the prior calls investable, whosemuand variance are finite while its loadings are not, and the message says so. - Read the cross-sectional weights through
orthogonality_weightsand take their element-wise square root, or leave anothing. - Scale the rows of the loadings by that square root, take a thin
LinearAlgebra.svd, and count the singular values abovemaximum(size) * eps * s[1], the toleranceLinearAlgebra.rankapplies. Keep that many left singular vectors.
Step 4 counts the rank after the family re-basis of step 2, because the selected universe can still leave the exposures numerically dependent, and a dependent direction that survives would widen the span the penalty spares.
Arguments
ue: Orthogonal uncertainty set estimator.pr: Prior result the optimisation is solving on.
Validation
!isnothing(pr.rr), else anIsNothingErrornaming the field and the estimator that returned no block.all(isfinite, rr.L), else anIsNonFiniteErrorcounting the assets whose loadings are not finite. Every such asset is inside the Investable Mask ofpr, because the verbs that call this fit reduce to the mask first.
Returns
rr::AbstractLoadingsRegressionResult: The loadings block the span came from.w_sqrt::Option{<:VecNum}: Element-wise square root of the metric, ornothingonIdentityMetric.Q::MatNum: Orthonormal basis of the weighted factor span, $N \times r_{\mathbf{B}}$.
Related
PortfolioOptimisers.orthogonal_mu_set — Function
orthogonal_mu_set(
ue::OrthogonalUncertaintySet,
pr::AbstractPriorResult,
rr::AbstractLoadingsRegressionResult,
w_sqrt::Union{Nothing, AbstractVector{<:Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}}},
Q::AbstractMatrix{<:Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}}
) -> Union{NormBallUncertaintySet{var"#s185", <:AbstractMatrix{var"#s137"}, Int64, MuUncertaintySetClass, Nothing} where {var"#s185"<:Number, var"#s137"<:(Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar})}, NormBallUncertaintySet{var"#s185", var"#s1851", Int64, MuUncertaintySetClass, <:AbstractArray{var"#s137", N}} where {var"#s185"<:Number, var"#s137"<:(Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}), var"#s1851"<:AbstractMatrix{var"#s137"}, var"#s137"<:(Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}), N}}
Builds the mean NormBallUncertaintySet on the Orthogonal Subspace, from a span already taken.
Algorithm
- Form the orthogonal projector
I - Q * Q'and divide its rows by the metric square root, giving $\mathbf{A}$, the projector read back in the asset coordinates. - Take the symmetric eigendecomposition of
A' * Aand keep the trailingN - size(Q, 2)eigenvectors. The count is exact:Qis orthonormal, soI - Q * Q'has rankN - size(Q, 2), the metric scaling is an invertible diagonal, andLinearAlgebra.eigenon aSymmetricorders the eigenvalues from small to large. No tolerance decides the rank here: an eigenvalue tolerance can sit close enough to the eigenvalue it must cut that the rule flips with the reduction order of the machine and states a subspace one dimension too wide. Step 4 oforthogonal_factor_spanstill reads a tolerance, because the rank of the loadings is a property of the data and not of a projector. - Orthonormalise
A * V₊with a reducedLinearAlgebra.qr, givingG, and read the dimensionrof the Orthogonal Subspace off its columns. - When
ris0, return the set with a radius of zero and a map of one zero column. The map keeps a column because the type admits a rank-zero map and a consumer that reads a size finds one either way, and the zero radius leaves the nominal mean. - Otherwise take the scaling $\mathbf{\Lambda}$ through
orthogonal_scaling, formL = G * sqrt(Λ)with a symmetric square root, and size the radius withk_norm_ballatrdegrees of freedom. - Carry
pr.muintoval, so a set fitted on one prior and handed to another optimisation carries the centre its geometry was calibrated on.
Arguments
ue: Orthogonal uncertainty set estimator.pr: Prior result the span came from.rr: Loadings block the span came from.w_sqrt: Element-wise square root of the metric, ornothing.Q: Orthonormal basis of the weighted factor span.
Returns
ucs::NormBallUncertaintySet: Mean set on the Orthogonal Subspace, of order2.
Related
PortfolioOptimisers.orthogonal_sigma_set — Function
orthogonal_sigma_set(
ue::OrthogonalUncertaintySet,
pr::AbstractPriorResult,
rr::AbstractLoadingsRegressionResult,
w_sqrt::Union{Nothing, AbstractVector{<:Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}}},
Q::AbstractMatrix{<:Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}}
) -> Union{CompactCovarianceUncertaintySet{var"#s185", var"#s1851", <:AbstractMatrix{var"#s137"}, Nothing} where {var"#s185"<:Number, var"#s137"<:(Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}), var"#s1851"<:AbstractVector{var"#s137"}, var"#s137"<:(Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar})}, CompactCovarianceUncertaintySet{var"#s185", var"#s1851", var"#s1852", <:AbstractMatrix{var"#s137"}} where {var"#s185"<:Number, var"#s137"<:(Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}), var"#s1851"<:AbstractVector{var"#s137"}, var"#s137"<:(Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}), var"#s1852"<:AbstractMatrix{var"#s137"}, var"#s137"<:(Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar})}}
orthogonal_sigma_set(
ue::OrthogonalUncertaintySet,
pr::AbstractPriorResult,
rr::AbstractLoadingsRegressionResult,
w_sqrt::Union{Nothing, AbstractVector{<:Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}}},
Q::AbstractMatrix{<:Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}},
rd
) -> Union{CompactCovarianceUncertaintySet{var"#s185", var"#s1851", <:AbstractMatrix{var"#s137"}, Nothing} where {var"#s185"<:Number, var"#s137"<:(Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}), var"#s1851"<:AbstractVector{var"#s137"}, var"#s137"<:(Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar})}, CompactCovarianceUncertaintySet{var"#s185", var"#s1851", var"#s1852", <:AbstractMatrix{var"#s137"}} where {var"#s185"<:Number, var"#s137"<:(Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}), var"#s1851"<:AbstractVector{var"#s137"}, var"#s137"<:(Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}), var"#s1852"<:AbstractMatrix{var"#s137"}, var"#s137"<:(Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar})}}
Builds the covariance CompactCovarianceUncertaintySet on the Orthogonal Subspace, from a span already taken.
Algorithm
- Take the element-wise inverse of the metric square root as the diagonal metric $\mathbf{C}$, or a vector of ones on
IdentityMetric. - Hand the weighted factor span
Qto the set as the basis it spares. A rank of zero leaves a basis with no column, which the type admits and which leaves the penalty on every direction. - Settle the radius with
k_compactand carrypr.sigmaas the nominal covariance. A stated number passes through unchanged; a rule ofAbstractCompactRadiusAlgorithmis handed the confidence level, the metric, the prior result, the loadings block,CandQ, which is everything a radius of this set can be sized from.
The set spares the span and penalises its complement, which is the same subspace the mean set lives in. The two axes are therefore built from one decomposition, and the estimator computes it once.
Arguments
ue: Orthogonal uncertainty set estimator.pr: Prior result the span came from.rr: Loadings block the span came from.w_sqrt: Element-wise square root of the metric, ornothing.Q: Orthonormal basis of the weighted factor span.rd: Returns data the set was fitted beside, ornothing. Only aVarianceFractionholding an optimiser reads it.
Returns
ucs::CompactCovarianceUncertaintySet: Covariance set that spares the weighted factor span.
Related