Base Cross Validation
PortfolioOptimisers.PredictionReturnsResult — Type
struct PredictionReturnsResult{__T_nx, __T_X, __T_nf, __T_F, __T_nb, __T_B, __T_ts, __T_iv, __T_ivpa} <: AbstractReturnsResultStores the portfolio returns data associated with a cross-validation prediction. Packages asset returns, factor returns, benchmark returns, timestamps, implied volatilities, and the implied volatility risk premium adjustment for use in prediction result types.
Fields
nx: Asset name vector.
X: Data matrixobservations × assetsif thedimskeyword does not exist ordims = 1,assets × observationswhendims = 2.
nf: Factor name vector.
F: Data matrixobservations × factorsif thedimskeyword does not exist ordims = 1,factors × observationswhendims = 2.
nb: Benchmark name vector.
B: Benchmark returns.
ts: Timestamp vector.
iv: Implied volatilities.
ivpa: Implied volatility risk premium adjustment.
Constructors
PredictionReturnsResult(; nx::Option{<:VecStr} = nothing, X::Option{<:VecNum_VecVecNum} = nothing, nf::Option{<:VecStr} = nothing, F::Option{<:MatNum} = nothing, nb::Option{<:VecStr} = nothing, B::Option{<:VecNum_VecVecNum} = nothing, ts::Option{<:VecDate} = nothing, iv::Option{<:VecNum_VecVecNum} = nothing, ivpa::Option{<:Num_VecNum} = nothing) -> PredictionReturnsResultKeywords correspond to the struct's fields.
No feature matrix
This carrier used to transport a per-fold collapsed feature matrix, so that rebuild_returns_result could stack the folds into the outer problem's. It no longer does: the outer collapse is recomputed at the assembly seam from the original, unsliced rd.pnl and the fold's weights, which is the same call the non-cross-validated path makes (see rebuild_returns_result). Nothing is lost — the fold's weights are on PredictionResult's res, and ts here is the fold's slice of the original clock, which is everything the seam needs to reconstruct any fold's view.
Validation
nfandFmust be consistent (both nothing, orFhaslength(nf)columns).- If
XandFprovided: row count ofFmatches length of eachXvector. - If
BandXprovided: same type (VecNum/VecVecNum) and matching lengths. - If
tsprovided:!isempty(ts); at least one ofX,Fis notnothing; lengths oftsmatchX,F, andBwhere applicable. - If
ivis aVecNum:ivpais scalar or nothing;ivis non-empty, non-negative, and finite;length(iv) == length(X). - If
ivis aVecVecNum:ivpaisVecNumor nothing;length(iv) == length(X) == length(ivpa); each sub-vector non-empty, non-negative, finite, and same length as correspondingX.
Related
PortfolioOptimisers.PredictionResult — Type
struct PredictionResult{__T_res, __T_rd, __T_hw} <: AbstractPredictionResultStores the result of a single cross-validation fold prediction. Pairs an optimisation result with the returns data from the test period.
Fold provenance
The fold's rows are not stored here. They do not need to be: rd.ts is the fold's slice of the original clock — port_opt_view slices it with the very test_idx the fold was built from — so feature_row_indices recovers them by matching timestamps whenever a consumer needs absolute rows. rebuild_returns_result is the one that does, and recovering rather than storing is what keeps that recovery correct on the combinatorial path, where a path's folds are assembled in split order rather than chronologically.
Fields
res: Optimisation result from the training fold.
rd: The returns result to use.
hw: Held-weights record of the fold, ornothingwhen the fold held its target weights on every observation.
Constructors
PredictionResult(; res::NonFiniteAllocationOptimisationResult, rd::PredictionReturnsResult, hw::Option{<:HeldWeightsResult} = nothing) -> PredictionResultKeywords correspond to the struct's fields. res and rd are required, because a fold prediction is meaningless without either half. hw defaults to nothing, which is the fold that held its target weights on every observation.
The held-weights record
hw is present only when a Weight Drift ran over the fold, so a reader dispatches on its absence rather than testing for it. It carries the asset returns of the fold, the weights held after the last observation and the form that made them, and weight_path rebuilds the weight path from it.
Related
PortfolioOptimisers.MultiPeriodPredictionResult — Type
struct MultiPeriodPredictionResult{__T_pred, __T_mrd, __T_id, __T_opt} <: AbstractPredictionResultStores predictions from multiple cross-validation folds as a single combined result. Concatenates the test-period returns from all folds into an aggregated PredictionReturnsResult.
Per-observation quantities (X, F, B, ts, iv) stack across folds. ivpa is per-asset, not per-observation, and each fold's reconstruct_rd has already collapsed it to one value per synthetic asset using that fold's weights, so it cannot stack — it is reduced to the last fold's value. This matches predict_realised_vols, which reads the last row of the stacked iv: the premium divisor is paired with the implied volatility it divides.
A feature matrix is not among them. It is not carried through the folds at all — rebuild_returns_result recomputes the outer collapse from the original rd.pnl, reaching each fold through pred[f].res.w and pred[f].rd.ts, so pred is what this result has to retain for it.
Fields
pred: Collection of fold predictions.
mrd: Aggregated multi-period returns result.
id: Path or fold identifier.
opt: The estimator the online arm of the fold loop threaded, folded through the last training end, ornothingon a batch run.Resumere-enters the loop from it.
An online run's Result also carries the estimator the fold loop threaded, in opt, folded through the last training end last(train_idx[end]). A batch run writes nothing. Resume hands the Result back to the loop over a longer history, and the loop continues from the fold after the last one held; a hand step in the value form, partial_fit(res.opt, rows), deploys the state from the last training end and leaves the Result resumable. The bang form, partial_fit!(res.opt, rows), writes the state's arrays in place — the held timestamps among them — so the Result it came from then names a row no fold ends at, and Resume refuses it; that is the seam's contract for a kept estimator, stated at partial_fit!.
Constructors
MultiPeriodPredictionResult(; pred::VecPredRes, id::Any = nothing, opt::Option{<:AbstractEstimator} = nothing) -> MultiPeriodPredictionResultKeywords correspond to the struct's fields. pred is required: the constructor stacks the folds' returns data into mrd, and the stack of no folds has no columns, no names, and no clock.
Validation
!isempty(pred).
Related
PortfolioOptimisers.PopulationPredictionResult — Type
struct PopulationPredictionResult{__T_pred} <: AbstractPredictionResultStores a collection of multi-period prediction results produced by a population-based cross-validation scheme (e.g. MultipleRandomised). Each element of pred represents one random asset-subset path.
Fields
pred: Collection of fold predictions.
Constructors
PopulationPredictionResult(; pred::VecPredRes_MultiPredRes = Vector{PredRes_MultiPredRes}(undef, 0)) -> PopulationPredictionResultKeywords correspond to the struct's fields. An empty pred is admitted: a population from which every path was dropped is a valid, if empty, answer.
Related
Base.split — Method
split(
res::CrossValidationResult,
args...
) -> CrossValidationResult
Identity split for CrossValidationResult. Returns the result unchanged, used as a no-op fallback when splitting is not applicable.
StatsAPI.predict — Method
predict(res::NonFiniteAllocationOptimisationResult, rd::ReturnsResult)
predict(res, rd, test_idx, cols = :)
predict(res, rd, test_idxs::VecVecInt, cols = :)Apply an optimisation result res to returns data rd to produce a PredictionResult or a vector of prediction results.
When test_idx is provided, only the rows (observations) indexed by test_idx (and optionally columns cols) of rd are used for the prediction.
The fee needs no horizon stamped onto it. charge_fees hands in the length of the series it charges, so a fold spreads a one-off cost over its own observations and the whole-sample method spreads it over the whole sample, each without a number stored on the fee. fees.fa names the clock alone: a nothing or FirstObservationFees charges the two fixed terms on the first observation of the series, and an AmortisedFees spreads them evenly over it.
The fa keyword overrides that clock for the series this method builds, and it reaches the result not at all. nothing inherits the clock the fee itself states, which is the library's original behaviour. This is what lets a report charge a fixed fee the way a fund saw it while the optimiser prices the same fee the way its own objective must. override_fee_amortisation is the verb, and the cross-validation schemes state the keyword in a field of the same name.
The Investable Mask, then the Held Gaps
A test window over a point-in-time universe holds two kinds of gap, and predict takes them in order.
- The column of a non-investable asset. The fit found it, its weight is
0, and the fold views the window and the weights atres.imskthroughinvestable_fold_viewbefore anything reads them, so the column is never read. The fees are not viewed, because the result carries them on the investable universe already. - A Held Gap, an
(observation, asset)pair at which the weight is non-zero and the return is missing. It is what an asset that delists inside the test window makes, and the mask is a per-fit fact that cannot see it.filter_held_gapszeroes every non-finite entry of the reduced window once, before the series is formed and before a Weight Drift compounds on it, and names the held pairs throughstrict_diagnostic: a warning by default, anArgumentErrorunderstrict. Nothing is renormalised, so the missing weight sits in cash on that observation.
The filtered window feeds calc_net_returns and held_weights_result alike, so the drift compounds on the matrix the series was formed from. The Held Weights record expands back to the caller's universe through expand_held_weights, because the next fold's turnover reads it. The identity a fold's series satisfies, with the fee taken over the whole weight vector:
returns[t] == sum_i w_i * (isfinite(X[t, i]) ? X[t, i] : 0) - feeA failed fold holds
A fold whose solve failed carries NaN weights, and its series is NaN: no fee is charged and the identity above holds of NaN. Under a drift the fold still held something, and held_start_weights says what: the previous weights it was handed through w_prev, member by member under a population, so the Held Weights record drifts them through the window and the next fold reads the book the fund carried. With no w_prev — fold 1, or a scheme whose folds are not a timeline — the record is NaN and nothing throws. res.w and rd.X stay NaN either way, so a scorer still sees the failure.
Arguments
res::NonFiniteAllocationOptimisationResult: Fitted optimisation result.rd::ReturnsResult: Returns data for the prediction period.test_idx: Observation index or vector of observation indices for the test fold.cols: Column selector. Defaults to:(all assets).
Keyword Arguments
fa::Option{<:AbstractFeeAmortisation} = nothing: The clock the series charges the two fixed fee terms on, ornothingto inherit the clock the fee itself states.strict::Bool = false: Whether a Held Gap raises anArgumentErrorrather than warning.w_prev::Option{<:VecNum_VecVecNum} = nothing: The previous weights the fold was handed, which a failed fold holds under a drift, ornothing.
Returns
PredictionResultor vector ofPredictionResult.
Related
PortfolioOptimisers.fit_predict — Method
fit_predict(opt::OptE_Opt, rd::ReturnsResult)Fit optimisation estimator opt on returns data rd and immediately produce a PredictionResult for the same data.
Arguments
opt: Optimisation estimator or result.rd::ReturnsResult: Returns data.
Returns
Related
PortfolioOptimisers.sort_by_measure — Function
sort_by_measure(ppred::PopulationPredictionResult, r::BaseRM_VecBaseRM; kwargs...)Sort the successful paths in a PopulationPredictionResult by their expected risk under r. Paths where any fold returned a non-success retcode are excluded.
Arguments
ppred::PopulationPredictionResult: Population prediction to sort.r::BaseRM_VecBaseRM: Risk measure used for ranking, or a vector of them. A vector is scalarised bykwargs.sca, defaulting toSumScalariser.kwargs...: Keyword arguments forwarded toexpected_risk.
Returns
Vector{MultiPeriodPredictionResult}: Sorted vector of successful path predictions.
A non-finite measure is last, whatever rev is
A path whose measure is not finite is placed after every finite one, under both directions of the ranking. A sort that put it first under one direction would make it the answer of a first, and a non-finite number is not a best. The finite members are sorted among themselves, and the non-finite ones keep their own order at the tail.
A mixed vector is refused here, and accepted by its sibling
The ranking direction comes from bigger_is_better, which throws on a vector whose elements disagree on polarity, because the flag decides which tail of the ranking is best and neither answer would be right. quantile_by_measure takes an explicit sign instead, so it admits a mixed vector.
Related
PortfolioOptimisers.previous_weights — Function
previous_weights(pws::Any, prev::Nothing)
previous_weights(pws::Nothing, prev::PredictionResult)
previous_weights(pws::AbstractPreviousWeightsSource, prev::PredictionResult)Read the weights a fold threads into the fold that follows it.
This is the one seam of the Previous-Weights Source. The first fold of a run has no fold behind it, so it threads nothing whatever the source is. A later fold threads the target weights of the previous fold by default, and the weights that fold held after its last observation when the source asks for them.
prev is the last fold whose weights this seam can thread, not always the fold before: the sequential loops advance it only when threads_weights holds of a fold, so a fold whose solve failed is skipped over by the target read and the fold before it is read instead. The weights this seam gives are therefore finite whenever it gives any.
Algorithm
- With no previous fold, give
nothing. - With no source, give the target weights of the previous fold,
prev.res.w. - With a source, give the held weights of the previous fold,
prev.hw.w.
Arguments
pws: Previous-weights source of the scheme, ornothing.prev: Prediction result of the last threadable fold, ornothing.
Returns
Option{<:VecNum_VecVecNum}: The weights the next fold reads throughfactory.
Related