The prior family on the partial-fit seam: private API

PortfolioOptimisers.PriorCarryStateType
struct PriorCarryState{__T_buf, __T_named} <: AbstractPartialFitState

Carries the observations a prior keeps when it folds its estimate exactly, and the assets whose scenario fill it has already named.

The state of a fold-and-carry prior, and what separates that route from a refit. A SampleBufferState means refit, everywhere in the library: an estimator carrying one has no recursion of its own, and its read-out is the batch verb over the rows the buffer kept. A prior carrying this state has folded its moments exactly, member by member, and keeps the rows for one reason only — LowOrderPrior carries X for the scenario risk measures, so the observations are memory, not arithmetic. Its read-out reads two folded moments and a matrix it already holds, and touches none of the rows.

A prior a wrapper seeds therefore falls to the refit route rather than to this one, which is what makes Online's cap the window of the whole fit.

The second field, and why a read-out writes to it

named is the set of assets a scenario_fill has told the caller about. strict_diagnostic has no memory of its own, so a batch fit names an asset once and a walk-forward reading out at every step names it at every step: two thousand notices about one listing, and a caller who learns to ignore the channel. The set is that memory, and a read-out reports only the assets outside it.

It is a Set, and a read-out writes into it in place, because a read-out returns a Prior Result rather than the estimator and there is no other channel by which the memory could survive the call. Base.copy copies it, so a state copied before a fold carries a memory of its own, and merge_states unions two.

Fields

  • buf: Buffer of the observations the prior carries, observations × assets, held verbatim and NaN included.
  • named: Indices of the assets whose scenario fill has already been named, written in place by a read-out that names one.

Constructors

PriorCarryState(;    buf::SampleBufferState = SampleBufferState(),    named::Set{Int} = Set{Int}()) -> PriorCarryState

Keywords correspond to the struct's fields. The default is the empty seed a first fold builds.

View parameters

When port_opt_view is called on this type, its fields are subset to the selected assets:

  • buf: Sliced to the selected indices via port_opt_view.
  • named: Remapped onto the selected indices, so an asset named before the slice is still named after it.

Related

source
PortfolioOptimisers.fold_carryFunction
fold_carry(cache::Option{<:PriorCarryState}, x::VecNum)
fold_carry(cache::Option{<:PriorCarryState}, X::MatNum; dims::Int = 1)

Folds observations into a PriorCarryState, seeding an empty one where the prior carries none.

The one line a fold-and-carry prior writes for its rows, beside the two that fold its moments. It is fold_buffer with the second field carried along, and the seed it builds is uncapped: a cap on the carry is EmpiricalPrior's max_scenarios, which is applied at the read-out, and a cap on the fit is Online's, which puts the prior on the refit route instead.

Arguments

  • cache: The state the prior carries, or nothing.
  • x: One observation, whose entries are the assets.
  • X: Data matrix observations × assets if the dims keyword does not exist or dims = 1, assets × observations when dims = 2.
  • dims: Dimension along which to perform the computation.

Returns

  • state::PriorCarryState: The state after the last observation.

Related

source
PortfolioOptimisers.needs_factor_returnsFunction
needs_factor_returns(pe::AbstractHiLoOrderPriorEstimator_F) -> true
needs_factor_returns(pe::AbstractLowOrderPriorEstimator_A) -> false
needs_factor_returns(pe::AbstractLowOrderPriorEstimator_AF) -> nothing
needs_factor_returns(pe::Online)
needs_factor_returns(pe::HighOrderPriorEstimator)
needs_factor_returns(pe::BlackLittermanPrior)
needs_factor_returns(pe::EntropyPoolingPrior)
needs_factor_returns(pe::MeucciEntropyPoolingPrior)
needs_factor_returns(pe::OpinionPoolingPrior)

Answers whether a prior's fit reads a factor matrix, from its estimator tree.

Whether a fit reads F is a fact of the tree an estimator embeds, not of the host's own type: no prior whose factor argument is optional reads it — each hands it to the prior it embeds — and only a member that requires it does. So the answer is three-valued, and it is read off the source shape the family names:

  • true for a member that requires factor returns, AbstractHiLoOrderPriorEstimator_F: its batch verb declares F::MatNum with no default, and a fit without one is refused.
  • false for a member that never reads them, AbstractLowOrderPriorEstimator_A: its batch verb declares the argument and ignores it, so a fold drops it as the batch verb drops it.
  • nothing for a member whose factor argument is optional, AbstractLowOrderPriorEstimator_AF: the type does not say; take what the fold is given, which is what its batch verb does.

Each of the library's optional-argument members recurses into the prior it embeds and answers the leaf's value, so EntropyPoolingPrior(; pe = FactorPrior()) answers true and EntropyPoolingPrior() answers false. OpinionPoolingPrior holds several: it answers true when any of them does, false when all of them do, and nothing otherwise. An Online answers for the estimator it wraps. A caller's own optional-argument subtype that embeds a prior defines the recursion; one that reads F itself may leave the default, which takes what it is given.

The predicate is the one test for this fit cannot run without factor returns at the doors that check for a missing factor matrix — the prior's ReturnsResult door, the optimiser's step, and the three uncertainty-set doors — where it replaces a shallow isa test that could not see a factor leaf under an optional-argument host. It also decides what the refit route of partial_fit! does with the factor observation it is given.

Arguments

  • pe: The prior estimator, or the wrapper around one.

Returns

  • needs::Union{Bool, Nothing}: true, false or nothing, as above.

Related

source
PortfolioOptimisers.combine_factor_answersFunction
combine_factor_answers(answers) -> Union{Nothing, Bool}

Combines the answers of several embedded priors into one, for a host that holds more than one.

The three-valued conjunction needs_factor_returns states for OpinionPoolingPrior: true when any member requires factor returns, because a fit that reaches that member without them is refused; false when every member never reads them, because the fit then drops them as each member does; and nothing otherwise, because at least one member takes what it is given and none requires it.

Arguments

  • answers: The answers of the members, each true, false or nothing.

Returns

  • needs::Union{Bool, Nothing}: The combined answer.

Related

source
PortfolioOptimisers.assert_factor_returnsFunction
assert_factor_returns(
    pe::Union{AbstractPriorEstimator, Online},
    F::Union{Nothing, AbstractMatrix{<:Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}}, AbstractVector{<:Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}}}
)

Refuses a missing factor matrix at a door whose prior's tree requires one.

The one refusal the five doors share — the prior's ReturnsResult method, the optimiser's step, and the three uncertainty-set doors — written once so that its message and its test cannot drift apart. The test is needs_factor_returns answering true, which walks the estimator tree, so a factor leaf nested under a host whose own factor argument is optional is refused here by name rather than by the leaf's MethodError one call later.

A pe of nothing is an uncertainty set with no prior of its own. It reads no factor matrix, so nothing is checked here; the returns-data form it is on its way to refuses it by name through ucs_prior.

Arguments

  • pe: The prior estimator the door hands the matrix to, or nothing.
  • F: The factor matrix the carrier holds, or the factor observation a fold is given, or nothing.

Validation

  • !isnothing(F), when needs_factor_returns(pe) === true. An IsNothingError is thrown otherwise.

Returns

  • nothing.

Related

source
PortfolioOptimisers.fold_factor_argumentFunction
fold_factor_argument(needs::Bool, pe::AbstractPriorEstimator, F::Option{<:VecNum_MatNum})
fold_factor_argument(::Nothing, ::AbstractPriorEstimator, F::Option{<:VecNum_MatNum})

Applies the estimator tree's answer to the factor argument of a fold.

The three arms of needs_factor_returns as the refit route reads them: true refuses a missing F by name and passes a present one through, false drops it, and nothing passes it through as it is. Written by dispatch on the answer so that a tree whose answer is a compile-time constant — every one of the library's — costs the fold no branch.

Arguments

  • needs: The answer of needs_factor_returns.
  • pe: The prior, for the refusal's message.
  • F: The factor argument the fold was given, or nothing.

Returns

  • F: The factor argument the buffer records, or nothing.

Related

source
PortfolioOptimisers.fold_memberFunction
fold_member(est, args...; kwargs...)

Folds an observation into a member of a carrying host, where that member folds.

The fold half of the mixed-host rule. A host that carries the observations folds every member that folds and leaves the rest untouched, because it can run their batch verb over its own rows at the read-out. supports_partial_fit is the question, and it is answered from the member's type and its cache field, so a host of concrete members resolves the branch at compile time and folds nothing it should not.

A member the host does not hold is nothing, and folding it is a no-op.

Arguments

  • est: The member to fold, or nothing.
  • args...: The observations, forwarded to partial_fit!.
  • kwargs...: Additional keyword arguments, forwarded to partial_fit!.

Returns

  • est: The member carrying the state after the last observation, or the member unchanged where it does not fold.

Related

source
PortfolioOptimisers.read_memberFunction
read_member(
    f,
    est,
    X::AbstractMatrix{<:Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}};
    kwargs...
) -> Any

Reads a member's estimate out of its fold, or refits it over the host's own rows.

The read-out half of the mixed-host rule, and the twin of fold_member: a member the host folded answers from its state, and a member it did not fold answers from the matrix the host carries. f is the member's batch verb — Statistics.mean, Statistics.cov, coskewness, cokurtosis — and the one-argument form of that same verb is its read-out, which is a convention every family of the seam already follows.

No AssetPanel reaches this verb. A panel is fold context rather than sample, and a buffer holds no activity mask, so a member refitted here is refitted over the rows alone; that is #999's to change.

Arguments

  • f: The member's batch verb.
  • est: The member, or nothing.
  • X: The rows the host carries, as the member was folded on them.
  • kwargs...: Additional keyword arguments, forwarded to the batch verb alone. A folded member is read with no keyword argument at all, because its state is already the answer and there is no sample left for a keyword to describe.

Returns

  • The member's estimate.

Related

source
PortfolioOptimisers.update_online_estimatorMethod
update_online_estimator(pe::Union{<:HighOrderPriorEstimator, <:BlackLittermanPrior})

Resolves the Online declarations under the prior a wrapping prior embeds, at warm-up.

A wrapping prior hands its embedded prior across a boundary of its own, so it writes the recursion the generic method does not: HighOrderPriorEstimator(; pe = BlackLittermanPrior(; pe = Online(EmpiricalPrior()), …)) is resolved through this method, where the generic scan of the host's own fields would find no wrapper — pe holds a plain prior — and leave the one two levels down unseeded. A wrapper stored in the host's own pe, HighOrderPriorEstimator(; pe = Online(EmpiricalPrior())), is seeded the same way, because the recursion meets it at the first level. The co-moments of a HighOrderPriorEstimator are scanned by the generic method as they always were.

Arguments

  • pe: The wrapping prior.

Returns

  • pe: The prior, with every wrapper under its embedded prior resolved.

Related

source