Base Cross Validation (a): private API
PortfolioOptimisers.CrossValidationResult — Type
abstract type CrossValidationResult <: AbstractResultAbstract supertype for all cross-validation result types.
Related
PortfolioOptimisers.CrossValidationAlgorithm — Type
abstract type CrossValidationAlgorithm <: AbstractAlgorithmAbstract supertype for all cross-validation algorithm types.
Related
PortfolioOptimisers.CVER — Type
CVER = Union{<:CVE_Onl, <:CrossValidationResult}Union of all cross-validation schemes, plain or online, and result types.
Related
PortfolioOptimisers.OptimisationCrossValidationEstimator — Type
abstract type OptimisationCrossValidationEstimator <: CrossValidationEstimatorAbstract supertype for cross-validation estimators used in portfolio optimisation. Subtypes implement different splitting strategies (sequential or non-sequential) for out-of-sample testing of optimisation pipelines.
Related
PortfolioOptimisers.SequentialCrossValidationEstimator — Type
abstract type SequentialCrossValidationEstimator <: OptimisationCrossValidationEstimatorAbstract supertype for sequential optimisation cross-validation estimators. Sequential schemes produce time-ordered, non-overlapping folds (e.g. walk-forward).
Related
PortfolioOptimisers.NonSequentialCrossValidationEstimator — Type
abstract type NonSequentialCrossValidationEstimator <: OptimisationCrossValidationEstimatorAbstract supertype for non-sequential optimisation cross-validation estimators. A non-sequential scheme makes folds that are not a timeline, such as the folds of a k-fold or a combinatorial split.
Related
PortfolioOptimisers.OptimisationCrossValidationResult — Type
abstract type OptimisationCrossValidationResult <: CrossValidationResultAbstract supertype for all optimisation cross-validation result types.
Related
PortfolioOptimisers.SequentialCrossValidationResult — Type
abstract type SequentialCrossValidationResult <: OptimisationCrossValidationResultAbstract supertype for sequential optimisation cross-validation results.
Related
PortfolioOptimisers.NonSequentialCrossValidationResult — Type
abstract type NonSequentialCrossValidationResult <: OptimisationCrossValidationResultAbstract supertype for non-sequential optimisation cross-validation results.
Related
PortfolioOptimisers.OptCVER — Type
OptCVERUnion of all optimisation cross-validation estimators and results.
Related
PortfolioOptimisers.NonSeqCVER — Type
NonSeqCVERUnion of all non-sequential cross-validation estimators and results.
folds_are_time_ordered answers false for every member, so the fold loop runs their folds in parallel.
Related
PortfolioOptimisers.SeqCVER — Type
SeqCVERUnion of all sequential cross-validation estimators and results.
Related
PortfolioOptimisers.NonOptimisationCrossValidationEstimator — Type
abstract type NonOptimisationCrossValidationEstimator <: CrossValidationEstimatorAbstract supertype for cross-validation estimators used in non-optimisation contexts (e.g. resampling for hierarchical clustering or phylogeny methods).
Related
PortfolioOptimisers.NonOptimisationSequentialCrossValidationEstimator — Type
abstract type NonOptimisationSequentialCrossValidationEstimator <: NonOptimisationCrossValidationEstimatorAbstract supertype for sequential non-optimisation cross-validation estimators. Sequential schemes produce time-ordered, non-overlapping folds.
Related
PortfolioOptimisers.NonOptimisationNonSequentialCrossValidationEstimator — Type
abstract type NonOptimisationNonSequentialCrossValidationEstimator <: NonOptimisationCrossValidationEstimatorAbstract supertype for non-sequential non-optimisation cross-validation estimators. A non-sequential scheme makes folds that are not a timeline, such as randomly sampled or combinatorial folds.
Related
PortfolioOptimisers.NonOptimisationCrossValidationResult — Type
abstract type NonOptimisationCrossValidationResult <: CrossValidationResultAbstract supertype for result types produced by non-optimisation cross-validation routines.
Related
PortfolioOptimisers.NonOptimisationSequentialCrossValidationResult — Type
abstract type NonOptimisationSequentialCrossValidationResult <: NonOptimisationCrossValidationResultAbstract supertype for sequential non-optimisation cross-validation result types.
Related
PortfolioOptimisers.NonOptimisationNonSequentialCrossValidationResult — Type
abstract type NonOptimisationNonSequentialCrossValidationResult <: NonOptimisationCrossValidationResultAbstract supertype for non-sequential non-optimisation cross-validation result types.
Related
PortfolioOptimisers.AbstractPredictionResult — Type
abstract type AbstractPredictionResult <: AbstractResultAbstract supertype for all prediction result types.
All concrete prediction result types from cross-validation should subtype AbstractPredictionResult.
Related
PortfolioOptimisers.VecPredRes — Type
VecPredRes = AbstractVector{<:PredictionResult}Alias for a vector of single-fold prediction results.
Represents a collection of PredictionResult objects from cross-validation folds.
Related
PortfolioOptimisers.PredRes_MultiPredRes — Type
PredRes_MultiPredRes = Union{<:PredictionResult, <:MultiPeriodPredictionResult}Alias for a single-fold or multi-period prediction result.
Matches either a PredictionResult or a MultiPeriodPredictionResult.
Related
PortfolioOptimisers.VecMPredRes — Type
VecMPredRes = AbstractVector{<:MultiPeriodPredictionResult}Alias for a vector of multi-period prediction results.
Represents a collection of MultiPeriodPredictionResult objects.
Related
PortfolioOptimisers.VecVecPredRes — Type
VecVecPredRes = AbstractVector{<:VecPredRes}Alias for a vector of vectors of prediction results.
Represents the outer collection of cross-validation paths, where each inner vector contains prediction results from a single path.
Related
PortfolioOptimisers.VecPredRes_MultiPredRes — Type
VecPredRes_MultiPredRes = AbstractVector{<:PredRes_MultiPredRes}Alias for a vector of single-fold or multi-period prediction results.
Represents a collection of PredRes_MultiPredRes elements.
Related
PortfolioOptimisers.mapreduce_RetMtx — Function
mapreduce_RetMtx(rd, sym = :X)Concatenate the series of a field over the folds of a path.
A field holds one series for a single portfolio, or one series per member for a population. The folds are concatenated in the order of rd.
Algorithm
- For one series per fold, concatenate the series of every fold with
vcat. - For one series per member, concatenate the series of member
iover every fold, for each memberiof the first fold.
Arguments
rd: Vector ofPredictionReturnsResultobjects, one per fold.sym: Name of the field to concatenate,:Xby default.
Returns
- The concatenated series, or one concatenated series per member.
PortfolioOptimisers.quantile_by_measure — Function
quantile_by_measure(ppred::PopulationPredictionResult, r::BaseRM_VecBaseRM, q::Real;
r_kwargs::NamedTuple = (;), q_kwargs::NamedTuple = (;),
sign::Integer = 1)Select the successful path in ppred whose expected risk under r is closest to the q-th quantile of the risk distribution across all successful paths.
A path whose measure is not finite takes no part. It is dropped before the quantile, so one failed path cannot make the quantile non-finite and cannot be the answer.
sort_by_measure calls bigger_is_better for its direction, so it throws on a vector of measures that disagree on polarity. This function takes an explicit sign instead. The caller gives the one fact that bigger_is_better cannot infer, so a mixed vector is admitted.
Algorithm
- Keep the successful members of
ppredwithsuccessful_members. - Compute
signtimes the expected risk of each member underr, givingrks. - Drop the members whose
rksis not finite. - Compute the
q-th quantile ofrkswithStatistics.quantile, givingrkq. - Return the first member whose
abs(rks[i] - rkq)is the smallest.
Arguments
ppred::PopulationPredictionResult: Population prediction result.r::BaseRM_VecBaseRM: Risk measure for computing path risks, or a vector of them. A vector is scalarised byr_kwargs.sca, defaulting toSumScalariser.q::Real: Quantile level in[0, 1].r_kwargs::NamedTuple = (;): Keyword arguments forwarded toexpected_risk.q_kwargs::NamedTuple = (;): Keyword arguments forwarded toStatistics.quantile.sign::Integer = 1: Orientation of the risk scale. Use1when a larger risk is worse,-1when it is better. This is what lets a mixed vector through, see below.
Validation
- At least one successful member must have a finite measure. With none,
Statistics.quantilereceives an empty vector and throws.
Returns
- The member closest to the
q-th quantile: aMultiPeriodPredictionResult, or aPredictionResultwhen the population holds single folds.
Related
PortfolioOptimisers.reconstruct_rd — Method
reconstruct_rd(res::NonFiniteAllocationOptimisationResult, rd::ReturnsResult, X, hw = nothing, w = res.w)Reconstruct a PredictionReturnsResult from an optimisation result and returns data.
It collapses the benchmark returns, the implied volatilities and the implied volatility risk premium adjustment of rd with the weights of the fold, and pairs them with the portfolio series X.
A benchmark matrix collapses as collapse_benchmark states: against the weight path when the fold carries a HeldWeightsResult, and against the target weights when it does not. iv and ivpa are rates, so they collapse as convex combinations, against the weights of synthetic_asset_weights.
The fold does not collapse the panel of the carrier. A square feature matrix needs the weights of every synthetic asset at once for its second contraction, and only one weight vector is known here. rebuild_returns_result instead computes the collapse for the whole synthetic universe from the original rd.pnl and the fold weights pred[f].res.w.
Algorithm
- Collapse
rd.Bwithcollapse_benchmark, fromwandhw. - When
rd.ivis given orrd.ivpais a vector, compute the convex weightscwofwwithsynthetic_asset_weights, one vector per member under a population. - Collapse
rd.ivtord.iv * cw, and a vectorrd.ivpatodot(rd.ivpa, cw). A scalarivpastays as it is. - Under a population, repeat a scalar
ivpaonce per member. - Build the
PredictionReturnsResultfromnx,X, the factor block,nb, the collapsed values andts.
Arguments
res::NonFiniteAllocationOptimisationResult: Fitted optimisation result.rd::ReturnsResult: Original returns data.X: Portfolio returns (vector or vector of vectors).hw: Held Weights record of the fold, ornothing.w: The weights the fold's series was formed from. It defaults tores.w, and a fold that viewed its window at the Investable Mask passes the view instead, so the collapse reads the same asset axisrdcarries.
Returns
PredictionReturnsResultwith updated benchmark returns, implied volatilities and implied volatility risk premium adjustment.
Related
PortfolioOptimisers.investable_fold_view — Function
investable_fold_view(imsk::Nothing, w, rd::ReturnsResult, fees::Option{<:Fees})
investable_fold_view(imsk::BitVector, w, rd::ReturnsResult, fees::Option{<:Fees})View a fold's weights and test window at the Investable Mask, and pass its fees through.
An optimisation reduces to the Investable Mask at its entry and expands the solved weights back to the caller's universe, so the weight of an asset that the fit found non-investable is 0. The fold views the weights and the window at the mask together, before anything reads the window. A dead column is therefore never read, and filter_held_gaps runs over the investable columns alone.
The fees are not viewed. A result carries the objects of the universe it solved on, so res.fees is on the investable universe already, and a second view would index its per-asset rates by positions of the full universe. The function returns the fees unchanged so that the fold receives the three values it scores with from one call.
Algorithm
- With no mask, give
(w, rd, fees)unchanged. - With a mask, give the weights viewed at the mask with
investable_weights_view,rdviewed at the columnsfindall(imsk)withport_opt_view, andfeesunchanged.
Arguments
imsk: The Investable Mask, ornothing.w: The fold's target weights, or a population of them.rd: The returns result to use.fees:Feesthe fold is charged, on the investable universe, ornothing.
Returns
(w, rd, fees): The weights and the window reduced to the investable assets, or unchanged, and the fees as given.
Related
PortfolioOptimisers.fold_fees — Function
fold_fees(res::OptimisationResult, fees::Nothing, X::MatNum)
fold_fees(res::OptimisationResult, fees::Fees, X::MatNum)Resolve the fee a fold-taking consumer charges: the result's own, or a caller's viewed at the result's Investable Mask.
The three fold-taking consumers, calc_net_asset_returns, risk_contribution and factor_risk_contribution on a PredictionResult, take an optional fees, so a caller can score a stored fold under a fee of their own. The two fees are on different universes. The fit reduced the fee of the result, so its five per-asset fields are on the investable axis and its two liquidation carriers are on the complement. A caller's fee is on the caller's universe, as a caller's rd is, so it takes the same view that a fee takes at the fit.
Without the view, a per-asset rate on the full universe met the reduced weights with a BoundsError, and a carrier on the full universe was charged as though every position had been liquidated.
Algorithm
- With no caller fee, give the fee of the result through
extract_fees. - With a caller fee, view it with
investable_fees_view. The per-asset fields are sliced to the mask and the carriers to its complement, which is found from the width ofX. The carriers are removed when the mask isnothing, because no asset left.
Arguments
res::OptimisationResult: The fold's optimisation result, carrying the mask and its own fee.fees: A caller'sFeeson the caller's universe, ornothingto charge the result's own.X: The fold's expanded record,observations × assetson the caller's universe. Only its width is read.
Returns
fees::Option{<:Fees}: The fee on the two axes the result's mask leaves, ornothing.
Related
PortfolioOptimisers.threads_weights — Function
threads_weights(pws::Nothing, pred::PredictionResult)
threads_weights(pws::AbstractPreviousWeightsSource, pred::PredictionResult)Say whether a fold's prediction carries weights the next fold can be handed.
previous_weights reads the weights, and this function says whether the fold has any to read. The sequential loops, run_folds and online_folds, hand a fold on only when this holds, so a failed fold is never read and the last threadable fold is read instead.
The weights that are read decide the test. The target weights are finite exactly when every return code is an OptimisationSuccess. The held weights are finite when the drift ran, and held_start_weights lets it run on a failed fold that was handed previous weights. So under a source, a failed fold that held its book is threaded, and only a fold with nothing to hold is skipped.
Algorithm
- With no source, hold when the fold's return code is a success, every member's under a population.
- With a source, hold when the fold's held weights are all finite, every member's under a population.
Arguments
pws: Previous-weights source of the scheme, ornothing.pred: Prediction result of the fold.
Returns
Bool: Whether the fold's weights can be threaded.
Related
previous_weightsheld_start_weightsrun_foldsonline_foldsPreviousWeights: The fallback that turns a failed fold into a threadable one.
PortfolioOptimisers.fold_solved — Function
fold_solved(retcode::OptimisationReturnCode)
fold_solved(retcode::VecOptRetCode)Say whether a fold's return code, or every member's under a population, is an OptimisationSuccess.
Related
PortfolioOptimisers.held_weight_members — Function
held_weight_members(w::VecNum)
held_weight_members(w::VecVecNum)Iterate the held weights of a fold one member at a time: a single vector is a population of one.
Related
PortfolioOptimisers.held_start_weights — Function
held_start_weights(retcode::OptimisationSuccess, w::VecNum, w_prev)
held_start_weights(retcode::OptimisationFailure, w::VecNum, w_prev::Nothing)
held_start_weights(retcode::OptimisationFailure, w::VecNum, w_prev::VecNum)
held_start_weights(retcode::OptimisationReturnCode, w::VecVecNum, w_prev)
held_start_weights(retcode::VecOptRetCode, w::VecVecNum, w_prev::Nothing)
held_start_weights(retcode::VecOptRetCode, w::VecVecNum, w_prev::VecNum)
held_start_weights(retcode::VecOptRetCode, w::VecVecNum, w_prev::VecVecNum)Name the weights a fold's drift starts from: its own on a solved fold, the previous weights on a failed one.
A fold that could not rebalance holds what it held. So under a Weight Drift or a Previous-Weights Source, a failed fold drifts the weights it was handed and not its NaN target. The return code decides, read per member under a population, and the previous weights are one vector for every member or one vector per member. A population solved under one return code, such as the frontier of one JuMPOptimisationResult, reads that code for every member. A failed fold or member with no previous weights keeps its NaN weights, and held_weights_result records NaN for it without a drift.
Algorithm
- On an
OptimisationSuccess, givew. - On an
OptimisationFailureover one vector, givew_prev, orwwhen there is none. - Over a population with one return code, repeat that code once per member.
- Over a population with no
w_prev, givew. - Over a population with one
w_prevvector, repeat it once per member. - Over a population with one
w_prevper member, give each member its own vector on a success and its entry ofw_prevon a failure.
Arguments
retcode: Return code of the fold, or one per member of the population.w: Target weights of the fold, on the universe the fold is scored on.w_prev: Previous weights the fold was handed, on the same universe, ornothing.
Validation
- A per-member
w_prevhas one entry per member ofw, else aDimensionMismatchis raised.
Returns
VecNum_VecVecNum: The start weights,w0of the fold'sHeldWeightsResult.
Related
PortfolioOptimisers.fold_factor_returns — Function
fold_factor_returns(imsk, rd::Nothing, pred::PredictionResult)
fold_factor_returns(imsk, rd::ReturnsResult, pred::PredictionResult)Resolve the returns result a fold's factor loadings are fitted from, on the live assets of the fold.
The fold-taking factor_risk_contribution reads rd by dispatch. A caller's rd is on the caller's universe, as it is for the value-level method, so it is viewed at the Investable Mask of the result. With nothing, the function builds a returns result from the fold itself. The nx of the fold is on the reduced axis already.
Algorithm
- On a caller's
rd, view it atimskwithinvestable_returns_view. - On
nothing, view the asset returnshw.Xof the fold atimsk, and build aReturnsResultfrom them, thenxof the fold and the factor blocknf,Fthatreconstruct_rdkept.
Arguments
imsk: The result's Investable Mask, ornothing.rd: Returns result on the caller's universe, ornothing.pred: Single-fold prediction result carrying aHeldWeightsResult.
Returns
rd::ReturnsResult: The returns result on the live assets.
Related
PortfolioOptimisers.collapse_benchmark — Method
collapse_benchmark(B::Nothing, w::VecNum_VecVecNum, hw)
collapse_benchmark(B::VecNum, w::VecNum, hw)
collapse_benchmark(B::VecNum, w::VecVecNum, hw)
collapse_benchmark(B::MatNum, w::VecNum, hw::Nothing)
collapse_benchmark(B::MatNum, w::VecVecNum, hw::Nothing)
collapse_benchmark(B::MatNum, w::VecNum, hw::HeldWeightsResult)
collapse_benchmark(B::MatNum, w::VecVecNum, hw::HeldWeightsResult)Collapse a fold's benchmark asset returns into a benchmark return series.
A benchmark that is already a series passes through. A benchmark matrix is contracted with the weights of the fold, and dispatch on the pair (B, w) chooses the method.
The Held Weights record of the fold chooses the weights. Without one, the matrix collapses against the target weights, which is what a fold that ran no drift held. With one, it collapses row by row against the weight path, as the portfolio series does. A caller that compares the two series, for a tracking error for instance, then compares two series formed the same way.
Algorithm
- On
nothing, givenothing. - On a benchmark series, give it back, repeated once per member under a population.
- On a matrix with no record, give
B * w, once per member under a population. - On a matrix with a record, give
vec(sum(B ⊙ U; dims = 2))for the fold's weight pathU, once per member under a population.
Arguments
B: Benchmark returns of the fold:nothing, a series, or an observations × assets matrix.w: Target weights of the fold, or a population of them.hw: Held Weights record of the fold, ornothing.
Returns
- The benchmark return series, or a vector of them under a population, or
nothing.
Related
PortfolioOptimisers.ruined_retcodes — Function
ruined_retcodes(retcode::VecOptRetCode, ruined::VecInt)Set the return code of every ruined member of a population to an OptimisationFailure.
The failure payload names the member and the reason, so a reader of res.retcode finds why the member left the run. A member that is not named keeps the code its own optimisation gave it.
Algorithm
- Walk the codes with their positions, and replace the code of a named member with a failure that states the reason.
Arguments
retcode: Return codes of the population, one per member.ruined: Indices of the members whose drifted wealth is not positive.
Returns
VecOptRetCode: The codes, with the ruined members failed.
Related
PortfolioOptimisers.mark_ruined_members — Function
mark_ruined_members(res::NonFiniteAllocationOptimisationResult, ruined::Nothing)
mark_ruined_members(res::NonFiniteAllocationOptimisationResult, ruined::VecInt)Rebuild a fold's optimisation result so that its ruined members carry a failure code.
A failure code is enough to drop the member. The library reads a vector of return codes with any(x -> isa(x, OptimisationFailure), …), and the cross-validation path keeps a path only when isa(y.res.retcode, OptimisationSuccess) holds, so a failed member takes its path out of the run.
Algorithm
- With no ruined member, and with an empty set of them, give
resunchanged. Nothing is rebuilt on the ordinary path. - Otherwise rebuild
resthroughset_retcode, with the codesruined_retcodesmakes.
Arguments
res: Optimisation result of the fold.ruined: Indices of the members whose drifted wealth is not positive, ornothing.
Returns
NonFiniteAllocationOptimisationResult: The result, rebuilt only when a member was ruined.
Related
PortfolioOptimisers.warn_ruined_members — Function
warn_ruined_members(wd::AbstractWeightDrift, args...)
warn_ruined_members(wd::Nothing, ruined::Nothing, n::Integer)
warn_ruined_members(wd::Nothing, ruined::VecInt, n::Integer)Warn once when a drift dropped members of a population, and the return series did not.
When the series of a fold is drifted, calc_net_returns(w::VecVecNum, X::MatNum, fees, wd::AbstractWeightDrift, obs) runs the same drift over the same window and warns. A fold that drifts only its held weights runs no such call, so this function warns instead. Either way the fold warns once.
Algorithm
- With a drifted series, say nothing. The series already warned.
- With no ruined member, say nothing.
- Otherwise warn, and name the count and the members.
Arguments
wd: Weight drift of the scheme, ornothing.ruined: Indices of the ruined members, ornothing.n: Number of members of the population.
Returns
nothing.
Related
PortfolioOptimisers.cv_nobs — Function
cv_nobs(rd::AbstractReturnsResult) -> Any
Return the number of observations (rows) cross-validation folds index into.
Arguments
data: Returns-level or price-level data (Prices_RR).
Returns
T::Integer: The number of observation rows.
Related
PortfolioOptimisers.cv_live_assets — Function
cv_live_assets(rd::AbstractReturnsResult) -> Any
Return the positions of the assets in the Coverage Universe of a cross-validation window.
This is the sibling of cv_nobs for the asset axis. A fold that draws a subset of assets draws it from these positions, so it never draws a column that could not have been traded.
The two data-level methods differ only in how they reach the numeric matrix. A returns carrier holds it directly, and a price carrier holds a TimeArray. The two mask-level methods take the nothing sentinel of an all-covered window and the mask of a window with gaps.
Algorithm
- Derive the Coverage Universe of the window's asset matrix and its panel with
coverage_mask. - Return every position of the asset axis on the
nothingsentinel. - Return
findall(cmsk)otherwise.
Arguments
data: Returns-level or price-level data (Prices_RR).cmsk: The Coverage Universe, ornothing.N: The number of assets of the window.
Validation
- At least one asset must be in the Coverage Universe of the window.
coverage_maskthrows anIsEmptyErroron a window in which every asset is dead.
Returns
live::Vector{Int}: The positions of the covered assets, in increasing order.
Related
PortfolioOptimisers.cv_timestamps — Function
cv_timestamps(rd::AbstractReturnsResult) -> Any
Return the timestamp vector aligned with the observation rows of data, or nothing when it has none.
Arguments
data: Returns-level or price-level data (Prices_RR).
Returns
ts: Timestamp vector, ornothing.
Related