Asset selection: private API
Functions
PortfolioOptimisers.tail_mask — Function
tail_mask(
scores::AbstractVector{<:Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}},
k::Integer,
bib::Bool,
tail::Symbol
) -> BitVector
Return the mask of the k assets furthest into the tail end of the score ordering.
tail is :best or :worst; which raw direction that is comes from bib, the bigger_is_better flag of the score. The count saturates at length(scores).
Assets tied with the k-th score are included only when the whole tied block fits within k. Otherwise the block straddles the cut and is excluded — the "trust neither" tie policy, which is why the returned mask may hold fewer than k assets. RankRule states the admitted set in closed form.
Algorithm
- Read
n, the number of scores. Returnnfalses whenkis not positive, andntrues whenkis at leastn. The second case is the saturation of the count. - Choose the comparison
ahead. It is>whentailandbibagree that a larger score lies further into the tail, and<otherwise. - Sort the scores under
aheadwithsortperm, givingperm, and readcut, the score at positionkof that order. - Count the scores strictly
aheadofcut, givingn_ahead, and the scores equal tocut, givingn_eq. - Set
keep_tieston_ahead + n_eq == k. The tied block at the cut fits insidekonly then, becausecutsits at positionkand son_ahead + n_eq >= kalways holds. - Return the mask that is
truefor every score strictlyaheadofcut, and for a score equal tocutwhenkeep_tiesistrue.
Arguments
scores: Per-asset score vectorassets × 1.k: Number of assets to take from thetailend.bib:bigger_is_betterflag of the score.tail::bestor:worst, the end to take from.
Returns
keep::BitVector: Maskassets × 1that istruefor every asset in the tail. It holds at mostkassets, and fewer when a tied block straddles the cut.
Related
PortfolioOptimisers.tail_action_mask — Function
tail_action_mask(
best::Union{Nothing, Integer},
worst::Union{Nothing, Integer},
action::Symbol,
scores::AbstractVector{<:Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}},
bib::Bool
) -> BitVector
Union the two tail masks and apply the rule's action.
Algorithm
- Start from a mask of
length(scores)falses. - When
bestis notnothing, take the:besttail of sizebestwithtail_maskand union it into the mask. - When
worstis notnothing, take the:worsttail of sizeworstwithtail_maskand union it into the mask. - Return the mask when
actionis:keep, and its complement whenactionis:drop.
Arguments
best: Number of assets to take from the best end, ornothing.worst: Number of assets to take from the worst end, ornothing.action::keepreturns the union,:dropreturns its complement.scores: Per-asset score vectorassets × 1.bib:bigger_is_betterflag of the score.
Returns
keep::BitVector: Maskassets × 1that istruefor every asset the rule admits.
Related
PortfolioOptimisers.groups_argbest — Function
groups_argbest(
groups,
scores::AbstractVector{<:Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}},
bib::Bool
) -> BitVector
Keep the single best-scoring member of each redundancy group.
A group whose best score is tied keeps nobody: under the library's "if we cannot tell them apart, trust neither" policy, two indistinguishable assets are both discarded — the same stance find_uncorrelated_indices takes on an exactly-tied correlated pair. A singleton group is trivially unambiguous and always survives.
Algorithm
- Start from a keep-mask of
length(scores)falses. - Choose the comparison
better. It is>whenbibistrue, and<otherwise. - Take the next group
gofgroups, and skip it when it is empty. - Walk the members of
gfrom the first, holding inbestthe index whose score no later member beats underbetter. - Count the members of
gwhose score equalsscores[best]. Set the mask atbestonly when that count is one, so a group with a tied best keeps nobody. - Repeat steps 3 to 5 over the remaining groups, then return the mask.
Arguments
groups: Vector of index vectors partitioning the assets.scores: Per-asset scores.bib: Whether a larger score is better.
Returns
keep::BitVector: One survivor per unambiguous group.
Related
PortfolioOptimisers.correlation_components — Function
correlation_components(
rho::AbstractMatrix{<:Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}},
t::Number
) -> Vector{Vector{Int64}}
Return the connected components of the graph whose edges are the pairs of rho at or above t.
A union-find pass over the strict lower triangle, so components are transitive and every asset lands in exactly one of them (a singleton when it has no over-threshold partner).
Algorithm
- Read
n, the number of rows ofrho, and setparent[i]toifor every asset. Each asset starts as its own component. - Take the next entry of the strict lower triangle of
rho, which holds each pair once. - When that entry is at least
t, find the root of each member of the pair withfind, and point the larger root at the smaller one.findcompresses the path it walks, so a later lookup on that chain is one step. - Repeat steps 2 and 3 over the remaining pairs.
- Group the assets by their final root into
groups, keyed by that root. - Return the values of
groups.
The threshold is compared against rho as it is given, so a caller that wants the absolute value takes it before this call.
Arguments
rho: Correlation matrixassets × assets.t: Threshold value.
Returns
groups::Vector{Vector{Int}}: The components, each a vector of asset indices in ascending order. The components themselves come out of aDict, so their order is not defined.groups_argbestreads them as a set and does not depend on it.
Related
PortfolioOptimisers.drop_scores — Function
drop_scores(
scores::AbstractVector{<:Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}},
bib::Bool
) -> Any
Convert per-asset scores into drop scores, where higher means "discard me first".
A risk measure with bigger_is_better == false (lower risk is better) already reads as a drop score; one with bigger_is_better == true is negated. Downstream of this call a lower number is always better, whatever the measure's own orientation was.
Mathematical definition
\[\begin{align} d_{i} &= \begin{cases} -s_{i} & \text{a larger score is better} \\ s_{i} & \text{otherwise} \end{cases}\,. \end{align}\]
Where:
- $d_{i}$: Drop score of asset $i$. The asset with the higher drop score is discarded first.
- $s_{i}$: Score of asset $i$, the risk measure evaluated on that asset's own return series.
The map is order-reversing in the first case and order-preserving in the second, so it never changes which of two assets is preferred. It changes only the direction that carries that preference.
Arguments
scores: Per-asset score vectorassets × 1.bib:bigger_is_betterflag of the score that producedscores.
Returns
d::VecNum: Drop score vectorassets × 1, in which a higher number means "discard me first".
Related
PortfolioOptimisers.assert_scoreable — Function
assert_scoreable(score::AbstractBaseRiskMeasure)
Validate that score can be evaluated on a single asset's return series.
Scoring asset i is score(X[:, i]), which is exactly the precomputed-returns path supports_precomputed_returns governs. A WeightsInput measure — Variance and StandardDeviation among them — consumes portfolio weights instead, and cannot score an asset.
Arguments
score: The risk measure a selector scores its assets with.
Validation
supports_precomputed_returns(score), else anArgumentErroris thrown. The message names the measure, and adds a pointer toSCM()when the measure is aVarianceor aStandardDeviation.
Returns
nothing.
Related
PortfolioOptimisers.assert_selection_action — Function
assert_selection_action(action::Symbol)
Validate the action field shared by the ordinal selection rules.
Arguments
action: Theactionfield of an ordinal selection rule.
Validation
action in (:keep, :drop), else anArgumentErroris thrown naming the value it got.
Returns
nothing.
Related
PortfolioOptimisers.assert_tail_counts — Function
assert_tail_counts(
best::Union{Nothing, Integer},
worst::Union{Nothing, Integer},
name::Symbol
)
Validate the best/worst tail sizes shared by the ordinal selection rules.
Arguments
best: Number of assets to take from the best end, ornothing.worst: Number of assets to take from the worst end, ornothing.name: Name of the rule being constructed, written into every exception message.
Validation
- At least one of
best,worstis notnothing, else anIsNothingErroris thrown. - Every count that is given is
>= 0, else aDomainErroris thrown. - The larger of the two counts is
> 0, else aDomainErroris thrown. A rule that takes no asset is rejected.
Returns
nothing.
Related
PortfolioOptimisers.assert_correlation_threshold — Function
assert_correlation_threshold(t::Number)
Validate a correlation threshold.
Arguments
t: Threshold value.
Validation
-1 <= t <= 1, else aDomainErroris thrown. The bound is the range of a correlation coefficient, so a threshold outside it can never be met or can never be missed.
Returns
nothing.
Related