Step execution
The step execution contract is the only pipeline-aware layer over the estimator families. Each run_step method reads the PipelineContext slots its estimator needs, dispatches to that family's native verb — prior for prior estimators, clusterise for clustering, optimise for optimisers, fit_preprocessing/apply_preprocessing for preprocessing estimators — and writes the slot the family produces.
The estimators themselves live with their own families and know nothing about pipelines; the preprocessing estimators, for instance, are documented under Pre-processing.
PortfolioOptimisers.run_step Function
run_step(est, ctx::PipelineContext) -> (fitted, ctx′)Execute one pipeline step: fit est on the PipelineContext slots it reads and return the fitted object together with a new context whose written slot is updated.
Each estimator family dispatches to its native verb — prior for prior estimators, clusterise/phylogeny_matrix for phylogeny estimators, optimise for optimisation estimators, fit_preprocessing/apply_preprocessing for preprocessing estimators. The fitted object is what apply_preprocessing later uses to transform unseen data windows; for non-preprocessing steps it is the step's ordinary result.
Estimators whose family is not steppable throw an ArgumentError directing the caller to PipelineStep.
Arguments
est: The step estimator (or aPipelineStepwrapper).ctx: The pipeline context.
Returns
(fitted, ctx′): The fitted object and the updated context.
Related
sourcerun_step(
res::NonFiniteAllocationOptimisationResult,
ctx::PipelineContext
) -> Tuple{NonFiniteAllocationOptimisationResult, PipelineContext}Execute a precomputed optimisation result as the optimisation step: there is nothing to solve, so the result is written to the opt slot as-is and the fold predicts with its weights.
This is how a mixed TimeDependent schedule runs its result entries: the fold-loop swap (update_time_dependent_estimator) replaces the schedule step with entry i, which may be an estimator (the fold optimises) or a result (the fold only predicts). A result cannot consume computed context slots — see maybe_inject_step for the fail-closed injection rules.
Related
sourcerun_step(
tts::TrainTestSplit,
ctx::PipelineContext
) -> Tuple{TrainTestSplitResult, PipelineContext}Execute a TrainTestSplit step: replace the input data slot with the training window, and return the fitted TrainTestSplitResult holding both windows.
The split runs at whichever level the pipeline input supplied — prices when the pipeline was fed price-level data, returns otherwise — so the same estimator serves both. Every later step therefore fits on the training window alone, which is the whole point of pinning the split to the first position.
Related
sourcePortfolioOptimisers.require_slot Function
require_slot(ctx::PipelineContext, slot::Symbol, est)Validate that the PipelineContext slot slot is populated before step est runs.
Arguments
ctx: The pipeline context.slot: The required slot, one ofPIPELINE_SLOTS.est: The step about to run, used in the error message.
Returns
nothing.
Related
sourcePortfolioOptimisers.set_slot Function
set_slot(
ctx::PipelineContext,
slot::Symbol,
val
) -> PipelineContextReturn a new PipelineContext with slot slot set to val and every other slot unchanged.
Arguments
ctx: The pipeline context.slot: The slot to write, one ofPIPELINE_SLOTS.val: The value to write.
Returns
ctx::PipelineContext: The updated context.
Related
sourcePortfolioOptimisers.run_uncertainty_step Function
run_uncertainty_step(
ue::AbstractUncertaintySetEstimator,
target::Union{Nothing, Symbol},
ctx::PipelineContext
) -> Tuple{Any, PipelineContext}Execute an uncertainty-set step pinned to a target and merge its result into the uncertainty slot.
The target comes from the PipelineStep wrapper:
:mucomputesmu_ucsand fills the mean half.:sigmacomputessigma_ucsand fills the covariance half.:bothcomputesucs, which derives both halves from one fit — sharing the prior and, for the sampling algorithms, the simulation draws — and is therefore cheaper than the two narrowed calls.
A narrowed step fills its half of the PipelineUncertaintySets pair and leaves the other untouched, so separate :mu and :sigma steps compose. Every populated half must reach the optimiser: inject_config and inject_sigma_ucs reject a set they cannot route rather than dropping it, so :both requires an optimiser with an ArithmeticReturn and an UncertaintySetVariance risk measure.
Arguments
ue: The uncertainty-set estimator.target::mu,:sigma, or:both; anything else throws anArgumentError.ctx: The pipeline context; requires thereturnsslot.
Returns
(res, ctx′): The computed result and the updated context. For:both,resis the(mu, sigma)PipelineUncertaintySetspair; otherwise it is the singleAbstractUncertaintySetResult.
Related
sourcePortfolioOptimisers.pipeline_asset_sets Function
pipeline_asset_sets(
ctx::PipelineContext,
est
) -> AssetSets{String, String, Dict{String, _A}} where _ABuild the AssetSets a constraint-generation step needs from the asset names of the context's returns slot.
Constraint estimators referencing groups beyond the plain asset names cannot be satisfied by this minimal set; precompute their result instead, or wrap a callable in a PipelineStep that supplies richer sets.
Arguments
ctx: The pipeline context; requires thereturnsslot.est: The step about to run, used in the error message.
Returns
sets::AssetSets: Asset sets whosenxentry holds the asset names.
Related
sourcePortfolioOptimisers.add_constraint_result Function
add_constraint_result(
ctx::PipelineContext,
res::AbstractConstraintResult
) -> PipelineContextAppend a constraint result to the constraints slot of the context.
The slot accumulates: the first result is stored as-is, later results widen it into a Vector{AbstractConstraintResult} preserving step order.
Arguments
ctx: The pipeline context.res: The constraint result to append.
Returns
ctx′::PipelineContext: The updated context.
Related
sourceA TrainTestSplit is the one step whose written slot is not a property of its type: it narrows whichever data slot the pipeline input filled, and declares the sentinel :split (see pipe_writes) so that the generic constructor machinery treats it as writing nothing. Its run_step method and slot declarations are documented with run_step, pipe_reads, and pipe_writes.