Skip to content
18

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 verbprior 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
julia
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 a PipelineStep wrapper).

  • ctx: The pipeline context.

Returns

  • (fitted, ctx′): The fitted object and the updated context.

Related

source
julia
run_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

source
julia
run_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

source
PortfolioOptimisers.require_slot Function
julia
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 of PIPELINE_SLOTS.

  • est: The step about to run, used in the error message.

Returns

  • nothing.

Related

source
PortfolioOptimisers.set_slot Function
julia
set_slot(
    ctx::PipelineContext,
    slot::Symbol,
    val
) -> PipelineContext

Return 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 of PIPELINE_SLOTS.

  • val: The value to write.

Returns

  • ctx::PipelineContext: The updated context.

Related

source
PortfolioOptimisers.run_uncertainty_step Function
julia
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:

  • :mu computes mu_ucs and fills the mean half.

  • :sigma computes sigma_ucs and fills the covariance half.

  • :both computes ucs, 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 an ArgumentError.

  • ctx: The pipeline context; requires the returns slot.

Returns

Related

source
PortfolioOptimisers.pipeline_asset_sets Function
julia
pipeline_asset_sets(
    ctx::PipelineContext,
    est
) -> AssetSets{String, String, Dict{String, _A}} where _A

Build 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 the returns slot.

  • est: The step about to run, used in the error message.

Returns

  • sets::AssetSets: Asset sets whose nx entry holds the asset names.

Related

source
PortfolioOptimisers.add_constraint_result Function
julia
add_constraint_result(
    ctx::PipelineContext,
    res::AbstractConstraintResult
) -> PipelineContext

Append 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

source

A 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.