Base asset selection: private API
Types
PortfolioOptimisers.AbstractAssetSelector — Type
abstract type AbstractAssetSelector <: AbstractReturnsPreprocessingEstimatorAbstract supertype for returns-level preprocessing estimators that restrict the asset universe.
An asset selector answers one question on the training window — which asset columns survive? — and that answer is its fitted state. apply_preprocessing replays the fitted universe on unseen windows, so a selector is safe inside cross-validation: the selection is made on train data alone and never re-decided on test data.
Concrete subtypes implement a single method, select_assets; the family shares one fit_preprocessing and one apply_preprocessing.
The funnel reduces the training window to its Coverage Universe before it calls select_assets, so a selector ranks among the assets that are live throughout that window and never among an asset that is not yet listed, is delisted, or is missing a quote. A selector therefore needs no finiteness guard of its own, and CompleteAssetSelector is the identity on the reduced window.
Selectors restrict columns only. Observation filtering is a price-level concern (MissingDataFilter), because a fitted transformation cannot decide which rows of an unseen window to drop without breaking the weights/returns alignment assert_universe_aligned enforces.
See docs/adr/0029-asset-selection-is-returns-preprocessing.md for the design rationale.
Related
Functions
PortfolioOptimisers.find_complete_indices — Function
find_complete_indices(X::AbstractMatrix; dims::Int = 1) -> VecIntReturn the indices of columns (or rows) in matrix X that do not contain any missing or NaN values.
This function scans the specified dimension of the input matrix and returns the indices of columns (or rows) that are complete, i.e., contain no missing or NaN values.
Internal machinery — the caller-facing form is CompleteAssetSelector, which wraps the dims = 1 (complete-column) mode as a fit/apply estimator. The dims = 2 (complete-row) mode has no estimator form: dropping observations is a price-level concern (MissingDataFilter).
Algorithm
- Orient
Xwithdims_oriented, so that the axis to test is axis 2 in both modes.dims = 2transposes the matrix, anddims = 1leaves it alone. - Read the column count
Nof the oriented matrix. - For each column of the oriented matrix, test whether it holds a
missingentry or aNaNentry. Collect the positions of the columns that do, givingto_remove. One entry is enough to remove the whole column. - Return
setdiff(1:N, to_remove), the positions of the complete columns, in ascending order.
Arguments
X: Data matrixobservations × assetsif thedimskeyword does not exist ordims = 1,assets × observationswhendims = 2.dims: Dimension along which to perform the computation.
Validation
dims in (1, 2).
Returns
res::VecInt: Indices of columns (or rows) inXthat are complete.
Examples
julia> X = [1.0 2.0 NaN; 4.0 missing 6.0];julia> PortfolioOptimisers.find_complete_indices(X)1-element Vector{Int64}: 1julia> PortfolioOptimisers.find_complete_indices(X; dims = 2)Int64[]Related