A Result resumes an online run

An online walk-forward's MultiPeriodPredictionResult carries the estimator the fold loop threaded, folded through the last training end, and Resume hands that Result back to the loop over the full history extended: the folds up to the one whose training window ends where the state stopped are skipped, the ordinary delta is folded into a copy of the state, and the loop continues from the fold after them, reaching the weights of the one-shot run over the longer history fold for fold. The Result returned holds the new folds only, and vcat stacks a run and its resumes for scoring. ADR 0144 records the decision.

PortfolioOptimisers.ResumeType
struct Resume{T1}

Continues an online walk-forward from the folds its Result holds, over the history extended.

A transient declaration in the estimator slot, in the idiom of Online and TimeDependent, decided by #1018. An online run's MultiPeriodPredictionResult carries the estimator the loop threaded, folded through the last training end. Resume(res) hands that Result back to cross_val_predict over the full history extended — the old carrier with the new rows appended — and the same scheme. The scheme enumerates every fold as the one-shot run does; the loop skips the folds the Result holds — located by the state's last held timestamp, so a resumed Result, which holds the new folds only, resumes again — folds the ordinary delta from the last training end into a copy of res.opt, and continues from the fold after them, threading res.pred[end]'s weights as the previous fold's. No warm-up runs: the warm-up was fold 1's window, and fold 1 is skipped. The resumed Result carries the new folds only and opt again, so the chain continues, and vcat on the two Results stacks them for scoring.

The oracle is the one-shot run. For an online scheme cv, a history rd_T and its extension rd_{T+k},

res  = cross_val_predict(mr, rd_T, cv)res2 = cross_val_predict(Resume(res), rd_{T+k}, cv)vcat(res.pred, res2.pred)  cross_val_predict(mr, rd_{T+k}, cv).pred   # fold for fold

to the tolerance of the moment layer and of the solver for the weights, and exactly for the carrier the read-out rebuilds, a capped run included. res is never written — Resume copies every state at entry — so one Result resumes any number of times, and a terminal view never spoils a later continuation.

The re-entry checks four things, each an ArgumentError by name. The scheme is a walk-forward with a Fold Fit, and it adds at least one fold. Timestamps are required: the carrier and the state must both hold them, and every held timestamp must equal its row of the carrier — state.ts == rd.ts[(r - h + 1):r] for r the last training end and h the held count — which pins the prefix exactly over the held span, under a cap or not; an index-only caller attaches a synthetic calendar, ts = Date(1) .+ Day.(0:(T - 1)). And a partial last fold is terminal: with reduce_test = true the old run's last fold is the first part of a full window of the longer run, so it can be neither skipped nor completed. Resume the same Result terminally with reduce_test = true for the live view of the leftover rows, and again with reduce_test = false when the rows arrive.

Every state is an immutable struct of arrays, names, integers and a timestamp vector, so a Result of an online run round-trips through the stdlib Serialization as it stands, and a deserialised Result resumes to the same weights. That format is bound to the Julia version that wrote it, and no other format is provided.

A batch Result, a PopulationPredictionResult (a MultipleRandomised run), a scheme that is not a walk-forward, a scheme with no Fold Fit, and a search are refused by name. A Pipeline host resumes on the same terms, through the state its row owner keeps.

Fields

  • res: The Result of the online run to continue, carrying the threaded estimator in opt.

Constructors

Resume(res::MultiPeriodPredictionResult)Resume(; res::MultiPeriodPredictionResult)

Validation

  • res.opt is not nothing. An ArgumentError is thrown otherwise, because a batch run threads no estimator.
  • res is not a PopulationPredictionResult. An ArgumentError is thrown otherwise.

Related

source
PortfolioOptimisers.cross_val_predictMethod
cross_val_predict(r::OptimiserResume, rd::ReturnsResult, cv::CVER; cols = :, ex = FLoops.ThreadedEx())
fit_and_predict(r::OptimiserResume, rd::ReturnsResult, cv::CVER; cols = :, ex = FLoops.ThreadedEx(), id = nothing)

Continue an online walk-forward from a Result, over the full history extended.

The doors that take an optimiser in the estimator slot take a Resume too. The carrier is viewed by cols as the one-shot door views it, and the estimator is not: the Result's estimator was threaded over the old run's view already, so the pinned context refuses a different one at the first delta step. The scheme is checked at the door (assert_resume_scheme) and the fold loop takes its resumed arm. The Result returned holds the new folds only, its opt folded through the last training end, and id.

Arguments

  • r: The declaration, holding the Result to continue.
  • rd: The returns result to use.
  • cv: The scheme the Result came from, a walk-forward with ff = OnlineStep().
  • cols: The asset view of the carrier.
  • ex: Unread; the resumed arm runs in order.
  • id: The identifier the Result carries.

Validation

Returns

  • res::MultiPeriodPredictionResult: The new folds, carrying the threaded estimator.

Related

source