The Coverage Universe: private API

An asset is in the Coverage Universe of one fit when its return is finite and the active mask of the AssetPanel is true at every row of the window. A prior reduces its returns matrix to that universe, fits every plain estimator on the clean block, and expands every block of its result onto the full asset universe with a NaN frame outside it.

The Asset Panel travels as the third positional argument of every moment verb, and the root method of each verb is that reduce-and-expand. A mask-aware estimator overrides its root and takes the whole window.

The universe and the reduction

PortfolioOptimisers.coverage_maskFunction
coverage_mask(X::MatNum, pnl::Nothing; dims::Int = 1) -> Option{BitVector}
coverage_mask(X::MatNum, pnl::AssetPanel{<:Any, Nothing, Nothing};
              dims::Int = 1) -> Option{BitVector}
coverage_mask(X::MatNum, pnl::AssetPanel; dims::Int = 1) -> Option{BitVector}

Derive the Coverage Universe of one fit: true at every asset a plain moment estimator can be fitted on.

An asset is in the Coverage Universe when its return is finite and the panel's active mask is true at every row of the window. The estimation mask is not read: it names the assets that enter a cross-sectional estimate, and a moment is not one. A static panel carries no mask, so the rule there is finiteness alone, as it is with no panel at all.

The all-covered case returns nothing rather than a mask of every true. That sentinel skips both the slice and the expansion, exactly as the nothing of investable_mask skips the optimiser's two halves.

The rule has one cost, and no docstring may hide it. One non-finite return, or one inactive row, inside the window puts the asset outside the Coverage Universe for that fit. A caller with a holiday fills it at the price level with PriceGapFill, or reaches for a mask-aware estimator, which takes the whole window and emits its own frame.

The two scans are independent, and only the asset axes must agree. A prior that reweights observations works on the axis its nested prior answered, and a nested prior may drop rows, so X and the panel can carry different observation counts and no row of one pairs with a row of the other. Pairing them by position would read the wrong date, and pairing them by the tail would assume a warm-up that no contract states. Reading each over its own rows assumes nothing. It is conservative where the two axes differ: an asset that the panel reports inactive at a row the sample no longer holds is outside the Coverage Universe of that fit.

Algorithm

  1. Orient X to observations × assets with dims_oriented.
  2. Scan each column of X. An asset stays in while its return is finite at every row.
  3. Scan each column of the active mask, where a panel carries one. An asset stays in while the mask is true at every row.
  4. Throw an IsEmptyError when no asset is covered. A moment over no asset has no answer to give.
  5. Return nothing when every asset is covered, and the mask otherwise.

Arguments

  • X: Data matrix observations × assets if the dims keyword does not exist or dims = 1, assets × observations when dims = 2.
  • pnl: Optional AssetPanel, whose active mask the Coverage Universe of the fit is derived from. nothing makes the rule finiteness alone.
  • dims: Dimension along which to perform the computation.

Validation

  • dims in (1, 2).
  • The asset axis of pnl.amsk must be the asset axis of the oriented X.
  • At least one asset must be covered.

Returns

  • cmsk::Option{BitVector}: true at every covered asset, or nothing when every asset is covered.

Related

source
coverage_mask(X::MatNum, iv::MatNum, pnl::Option{<:AssetPanel};
              dims::Int = 1) -> Option{BitVector}

Derive the Coverage Universe of one ImpliedVolatility fit, which reads an implied volatility surface beside its returns.

The estimator fits on the assets whose returns qualify under coverage_mask and whose implied volatilities are finite at every row of the window. An implied volatility series is padded NaN where it is silent, exactly as a return is, so an asset the estimator cannot price is named by the same rule that names an asset it cannot estimate, and reduce-and-expand writes its NaN row and column.

This narrows the asset universe by reading a second input. It is not a second mask and not a different Coverage Universe: nothing on the implied volatility axis is named, and every consumer of the expanded moment reads it exactly as it reads an absent return.

The narrowing sits in the estimator's own reduce-and-expand, rather than at the carrier that assembled iv. A caller reaching Statistics.cov(ce, X; iv = …) with a surface of their own has crossed no carrier boundary, and neither has a nested estimator receiving the forwarded iv; both are downstream of this reduction, so both see a block whose implied volatilities are complete.

Algorithm

  1. Orient X and iv to observations × assets with dims_oriented.
  2. Derive the Coverage Universe of X with coverage_mask.
  3. Scan each column of iv. An asset stays in while its implied volatility is finite at every row.
  4. Intersect the two, and hand the result to coverage_sentinel with a refusal that names the implied volatilities.

Arguments

  • X: Data matrix observations × assets if the dims keyword does not exist or dims = 1, assets × observations when dims = 2.
  • iv: Implied volatility surface observations × assets.
  • pnl: Optional AssetPanel, whose active mask the Coverage Universe of the fit is derived from. nothing makes the rule finiteness alone.
  • dims: Dimension along which to perform the computation.

Validation

  • dims in (1, 2).
  • The asset axis of pnl.amsk must be the asset axis of the oriented X.
  • At least one asset must be covered.

Returns

  • cmsk::Option{BitVector}: true at every covered asset, or nothing when every asset is covered.

Related

source
PortfolioOptimisers.coverage_sentinelFunction
coverage_sentinel(cmsk::BitVector) -> Option{BitVector}
coverage_sentinel(cmsk::BitVector, msg::AbstractString) -> Option{BitVector}

Refuse an empty Coverage Universe, and collapse a complete one onto the nothing sentinel.

This is the tail that every coverage_mask method shares, so the refusal and the sentinel are written once and cannot drift apart. A method that reads an input the two-argument one does not passes its own msg, because the reason an asset left the Coverage Universe is the one thing the tail cannot know: coverage_mask reads an implied volatility surface as well, and a message naming only the returns and the Asset Panel would send its caller looking in the wrong place.

Algorithm

  1. Throw an IsEmptyError carrying msg when cmsk holds no true.
  2. Return nothing when cmsk holds no false.
  3. Return cmsk otherwise.

Arguments

  • cmsk: The raw coverage mask, one entry per asset.
  • msg: The refusal message, naming every input the mask was derived from.

Validation

  • At least one asset must be covered.

Returns

  • cmsk::Option{BitVector}: cmsk itself, or nothing when every asset is covered.

Related

source
PortfolioOptimisers.coverage_reductionMethod
coverage_reduction(X::MatNum, pnl::Option{<:AssetPanel};
                   dims::Int = 1) -> Tuple{Option{BitVector}, MatNum}

Reduce a returns matrix to its Coverage Universe, and return the mask beside the clean block.

The reduction keeps the caller's orientation, so the plain moment verb that receives the block sees exactly the matrix it saw before the Asset Panel existed, and its own dims still describes it. The nothing sentinel returns X itself, so a complete window allocates nothing.

Algorithm

  1. Derive the Coverage Universe with coverage_mask.
  2. Return (nothing, X) on the sentinel.
  3. Slice the asset axis of X otherwise: its columns when dims = 1, and its rows when dims = 2.

Arguments

  • X: Data matrix observations × assets if the dims keyword does not exist or dims = 1, assets × observations when dims = 2.
  • pnl: Optional AssetPanel, whose active mask the Coverage Universe of the fit is derived from. nothing makes the rule finiteness alone.
  • dims: Dimension along which to perform the computation.

Validation

  • dims in (1, 2).

Returns

  • (cmsk, Xc)::Tuple{Option{BitVector}, MatNum}: The Coverage Universe, and X reduced to it.

Related

source
PortfolioOptimisers.coverage_reductionMethod
coverage_reduction(rd::AbstractReturnsResult;
                   dims::Int = 1) -> Tuple{Option{BitVector}, AbstractReturnsResult}
coverage_reduction(X::MatNum, rd::AbstractReturnsResult;
                   dims::Int = 1) -> Tuple{Option{BitVector}, AbstractReturnsResult}
coverage_reduction(cmsk::Nothing,
                   rd::AbstractReturnsResult) -> Tuple{Nothing, AbstractReturnsResult}
coverage_reduction(cmsk::BitVector,
                   rd::AbstractReturnsResult) -> Tuple{BitVector, AbstractReturnsResult}

Reduce a returns carrier to the Coverage Universe of its own window.

This is the carrier-level door of the seam. coverage_reduction(X::MatNum, pnl::Option{<:AssetPanel}) hands a moment estimator a clean block, and this hands a consumer of the whole carrier a clean carrier: nx, X, the benchmark, the implied volatility surface and the AssetPanel are all sliced at the same asset index by port_opt_view. Pre-selection is the caller: fit_preprocessing over an AbstractAssetSelector reduces here, so every selector ranks among live assets alone.

Four methods, and every branch is dispatch rather than a condition, as it is in coverage_reduction(opt::AbstractOptimisationEstimator, rd::ReturnsResult). The first hands the carrier's returns matrix back as the leading argument; the second derives the mask; the nothing method is the all-covered path and returns the carrier untouched; the BitVector method takes the view.

The split between the first two is the family's refusal. A carrier whose X is not an observations × assets matrix has no asset axis to reduce — PredictionReturnsResult collapsed it into one portfolio return series — so it matches no method and the call is a MethodError naming the carrier. That refusal comes before the panel is read, so a carrier that satisfies neither the {nx, X} contract nor the {nx, X, pnl} one is named by its returns matrix rather than by a missing field.

An all-dead window throws an IsEmptyError where the mask is derived, so the refusal is coverage_mask's and every caller has it for free.

Algorithm

  1. Hand rd.X back as the leading argument, which refuses a carrier with no asset axis.
  2. Derive the Coverage Universe of X and rd.pnl with coverage_mask.
  3. Return the mask and the carrier unchanged when the mask is nothing.
  4. Otherwise return the mask beside a port_opt_view of the carrier at findall(cmsk).

Arguments

  • rd: The returns result to use.
  • X: Data matrix observations × assets if the dims keyword does not exist or dims = 1, assets × observations when dims = 2.
  • cmsk: The Coverage Universe, or nothing.
  • dims: Dimension along which to perform the computation.

Validation

  • dims in (1, 2).
  • The carrier must hold an observations × assets returns matrix.
  • At least one asset must be in the Coverage Universe.

Returns

  • (cmsk, rdc)::Tuple{Option{BitVector}, AbstractReturnsResult}: The Coverage Universe, and the carrier reduced to it.

Related

source
PortfolioOptimisers.coverage_reduced_pairFunction
coverage_reduced_pair(A::MatNum, B::MatNum, cmsk::Nothing) -> Tuple{MatNum, MatNum}
coverage_reduced_pair(A::MatNum, B::MatNum, cmsk::BitVector) -> Tuple{MatNum, MatNum}

Slice two observations × assets matrices onto the same Coverage Universe.

An estimator that reads a second per-asset panel beside its returns, as ImpliedVolatility reads an implied volatility surface, must slice both, so that the two describe the same universe. The nothing sentinel returns both untouched.

Arguments

  • A, B: Two matrices, both observations × assets.
  • cmsk: The Coverage Universe, or nothing.

Returns

  • (A, B)::Tuple{MatNum, MatNum}: The two matrices on the Coverage Universe.

Related

source
PortfolioOptimisers.panel_moment_masksFunction
panel_moment_masks(pnl::Nothing) -> Tuple{Nothing, Nothing}
panel_moment_masks(pnl::AssetPanel) -> Tuple

Read the two universe masks a mask-aware moment estimator takes, out of an optional Asset Panel.

A mask-aware estimator overrides the panel method of its verb and takes the whole window, so it needs the masks themselves rather than the Coverage Universe that coverage_mask derives. No panel, and a static panel, both carry no mask, so both give the pair of nothing that is the estimator's own unmasked path.

Arguments

  • pnl: Optional AssetPanel, whose active mask the Coverage Universe of the fit is derived from. nothing makes the rule finiteness alone.

Returns

  • (amsk, emsk)::Tuple: The active mask and the estimation mask, or two nothing.

Related

source

The expansion

PortfolioOptimisers.coverage_nan_frameFunction
coverage_nan_frame(A::AbstractArray, sz::Dims) -> AbstractArray

Allocate the NaN frame that a moment expands into.

The frame takes its element type from the block through similar, and not from eltype(A). MatNum admits a JuMP scalar as well as a number, so eltype of one splits into two branches at inference and the numeric half is the only one a moment ever takes. Reading the type off the block instead keeps the frame in the block's own element type and leaves no unreachable branch behind.

Algorithm

  1. Allocate an array of sz, of the same kind and element type as A.
  2. Fill it with NaN, and return it.

Arguments

  • A: The block that will be written into the frame.
  • sz: Size of the frame.

Returns

  • frame::AbstractArray: An array of size sz, filled with NaN.

Related

source
PortfolioOptimisers.coverage_pair_indexFunction
coverage_pair_index(cmsk::BitVector) -> Vector{Int}

Map the columns of a reduced co-moment tensor onto the columns of the full-universe one.

A coskewness tensor is assets × assets² and a cokurtosis matrix is assets² × assets². Both index an asset pair (a, b) at (a - 1) * N + b, because both are built from kron(o, Y) ⊙ kron(Y, o), whose column (a - 1) * N + b is the elementwise product of column b and column a. The reduced tensor uses the same rule over the reduced width, and its pairs run with a outermost, so the index that this returns is in the order that the reduced columns already have.

Algorithm

  1. Take the positions of the covered assets.
  2. Return (a - 1) * N + b over every ordered pair of them, with a outermost.

Arguments

  • cmsk: The Coverage Universe.

Returns

  • idx::Vector{Int}: The full-universe pair columns of the reduced ones, in the reduced order.

Related

source
PortfolioOptimisers.expand_columnsFunction
expand_columns(A::MatNum, cmsk::Nothing) -> A
expand_columns(A::MatNum, cmsk::BitVector) -> MatNum

Write a block whose columns are the asset axis back into a NaN frame of the full width.

This is one of the three primitives of the expansion, beside expand_rows and expand_vector. expand_moment is the verb-facing name over them, and a prior that carries a block of its own reaches for them directly: a reconstructed returns matrix and a Cholesky factor are observations × assets and factors × assets, so both expand along their columns.

Arguments

  • A: The block that the reduced fit produced, anything × assets.
  • cmsk: The Coverage Universe, or nothing.

Returns

  • The block on the full asset universe, carrying NaN outside the Coverage Universe.

Related

source
PortfolioOptimisers.reduce_columnsFunction
reduce_columns(A::MatNum, cmsk::Nothing) -> A
reduce_columns(A::MatNum, cmsk::BitVector) -> MatNum

Take the columns of an observations × assets block that a mask keeps.

This is the inverse of expand_columns, and it is written beside it so that the pair cannot drift. coverage_reduction does the same slice for a mask it derives itself; this is for a caller that already holds one — an AugmentedBlackLittermanPrior reduces its returns by the Investable Mask its asset prior answered, which is not the same mask the returns alone would give: a column can be quoted throughout the window and still be unestimable.

A copy and not a view, because the block goes on to a regression, and a SubArray of an open-eltype array is where the compiler stops inferring.

nothing is the all-covered path and returns the block untouched.

Arguments

  • A: The block to reduce, observations × assets.
  • cmsk: The mask to keep, or nothing.

Returns

  • The block over the kept columns.

Related

source
PortfolioOptimisers.expand_rowsFunction
expand_rows(A::MatNum, cmsk::Nothing) -> A
expand_rows(A::MatNum, cmsk::BitVector) -> MatNum

Write a block whose rows are the asset axis back into a NaN frame of the full width.

This is expand_columns along the other axis. A loadings matrix is assets × factors, so it expands along its rows.

Arguments

  • A: The block that the reduced fit produced, assets × anything.
  • cmsk: The Coverage Universe, or nothing.

Returns

  • The block on the full asset universe, carrying NaN outside the Coverage Universe.

Related

source
PortfolioOptimisers.expand_vectorFunction
expand_vector(v::VecNum, cmsk::Nothing) -> v
expand_vector(v::VecNum, cmsk::BitVector) -> VecNum

Write a per-asset vector back into a NaN frame of the full width.

This is expand_columns over one axis alone. A mean vector, an intercept vector and a per-asset idiosyncratic variance all take it.

Arguments

  • v: The per-asset vector that the reduced fit produced.
  • cmsk: The Coverage Universe, or nothing.

Returns

  • The vector on the full asset universe, carrying NaN outside the Coverage Universe.

Related

source
PortfolioOptimisers.expand_momentFunction
expand_moment(m, cmsk::Nothing) -> m
expand_moment(m, cmsk::Nothing, dims::Int) -> m
expand_moment(m, cmsk::Nothing, ::Val{:kt}) -> m
expand_moment(sigma::MatNum, cmsk::BitVector) -> MatNum
expand_moment(mu::VecNum, cmsk::BitVector, dims::Int) -> VecNum
expand_moment(mu::MatNum, cmsk::BitVector, dims::Int) -> MatNum
expand_moment(skV::Tuple{<:MatNum, <:MatNum}, cmsk::BitVector) -> Tuple{MatNum, MatNum}
expand_moment(kt::MatNum, cmsk::BitVector, ::Val{:kt}) -> MatNum

Write a moment estimated on the Coverage Universe back into a NaN frame of the full width.

A Prior Result lives on the full asset universe, and an asset that the prior could not estimate carries NaN, so every block a reduced fit produced is expanded before it is carried. This is the second half of the seam whose first half is coverage_reduction, and the nothing sentinel returns the argument untouched.

The four shapes need four methods, because their types do not separate them: a covariance matrix and a cokurtosis matrix are both square, and a mean and a coskewness tensor are both rectangular. The arity and the Val marker separate them instead.

Algorithm

The method that Julia selects is the algorithm.

  1. A nothing mask returns the moment untouched, at every arity.
  2. A covariance-like matrix, assets × assets, is written at (cmsk, cmsk).
  3. A marginal, 1 × assets under dims = 1 and assets × 1 under dims = 2, is written along its asset axis.
  4. A coskewness pair expands its tensor at the rows cmsk and the pair columns of coverage_pair_index, and expands its negative spectral skewness matrix as a covariance-like matrix.
  5. A cokurtosis matrix is written at the pair index on both axes.

Arguments

  • m, sigma, mu, skV, kt: The moment that the reduced fit produced.
  • cmsk: The Coverage Universe, or nothing.
  • dims: The dimension that the marginal was computed along.
  • ::Val{:kt}: The marker that names a cokurtosis matrix, which a covariance matrix cannot be told from by type.

Returns

  • The moment on the full asset universe, carrying NaN outside the Coverage Universe.

Related

source
PortfolioOptimisers.expand_regressionFunction
expand_regression(re, cmsk::Nothing) -> re
expand_regression(re::Regression, cmsk::BitVector) -> Regression

Write a regression result fitted on the Coverage Universe back onto the full asset universe.

A Prior Result has no mask field, so every block it carries lives on the full asset universe, and the regression result it carries is one of those blocks. Its loadings, its intercepts and its idiosyncratic covariance are all per-asset, so all three expand along their asset axis.

L is read with getfield, as port_opt_view reads it: the swap(L, M) property rule makes re.L return re.M where L is unset, so an expanded result would materialise L as a copy of M and lose the unset-ness that the rule exists to express.

Arguments

  • re: The regression result the reduced fit produced.
  • cmsk: The Coverage Universe, or nothing.

Returns

  • re::Regression: The regression result on the full asset universe.

Related

source
PortfolioOptimisers.expand_idiosyncratic_covarianceFunction
expand_idiosyncratic_covariance(esigma::Nothing, cmsk) -> nothing
expand_idiosyncratic_covariance(esigma::VecNum, cmsk::BitVector) -> VecNum
expand_idiosyncratic_covariance(esigma::MatNum, cmsk::BitVector) -> MatNum

Expand the idiosyncratic covariance a regression result carries, in either of the two shapes it takes.

The block is a per-asset variance vector where the residuals are taken as uncorrelated, and an assets × assets matrix where they are not. This is the expansion counterpart of idiosyncratic_covariance_view, which slices the same two shapes.

Arguments

  • esigma: The idiosyncratic covariance, or nothing.
  • cmsk: The Coverage Universe.

Returns

  • esigma: The idiosyncratic covariance on the full asset universe.

Related

source

The refusal

PortfolioOptimisers.assert_finite_sampleFunction
assert_finite_sample(X::ArrNum) -> nothing

Refuse a non-finite sample in a plain moment estimator, and name the two ways out.

A plain moment estimator has no correct answer for an asset whose window carries a gap, so it refuses the whole sample rather than returning a number that reads as an estimate. The message names the two paths a caller has: fit through a prior, which reduces to the Coverage Universe and expands, or reach for a mask-aware estimator, which takes the whole window and emits its own frame.

This is assert_all_finite with the message that this refusal owes its caller. The generic message names the count and the position alone, which tells a caller what is wrong and not what to do about it.

Arguments

  • X: Data matrix observations × assets if the dims keyword does not exist or dims = 1, assets × observations when dims = 2.

Validation

  • Every entry of X must be finite.

Returns

  • nothing.

Related

source

The roots of the seven verbs

PortfolioOptimisers.variance_seriesMethod
variance_series(
    ce::AbstractCovarianceEstimator,
    X::AbstractMatrix{<:Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}},
    pnl::Union{Nothing, AssetPanel};
    dims,
    kwargs...
) -> Matrix

The point-in-time series root of the Asset Panel seam.

variance_series refits its estimator once per observation, so every window meets the refusal of assert_finite_sample on its own. A window is therefore reduced to its own Coverage Universe rather than to the sample's: an asset that lists inside the window is outside the Coverage Universe of every window that reaches back past its listing, and inside the Coverage Universe of none. That is one reduction per row, and it is what a point-in-time series of a gapped panel means.

A mask-aware estimator overrides this method and takes the whole window, as it overrides Statistics.cov(ce::AbstractCovarianceEstimator, X::MatNum, pnl::Option{<:AssetPanel}; dims::Int = 1, kwargs...).

Algorithm

  1. Orient X so that the observations lie on the rows.
  2. Allocate a NaN frame of the shape of X with coverage_nan_frame.
  3. For each observation t, take the assets whose window is finite throughout and, when the Asset Panel carries an active mask, active throughout.
  4. Fit the estimator on that block, and write the answer into the covered entries of row t. An asset outside the window's Coverage Universe keeps its NaN, and a window that covers no asset leaves the whole row at NaN.
  5. Return the series, transposed when dims == 2.

Arguments

  • ce: Covariance estimator.
  • X: Data matrix observations × assets if the dims keyword does not exist or dims = 1, assets × observations when dims = 2.
  • pnl: Optional AssetPanel, whose active mask the Coverage Universe of the fit is derived from. nothing makes the rule finiteness alone.
  • dims: Dimension along which to perform the computation.
  • kwargs...: Additional keyword arguments passed to the estimator.

Validation

  • dims in (1, 2).

Returns

  • val::Matrix{<:Number}: Variance series on the full asset universe, shaped as (T, N) if dims == 1 or (N, T) if dims == 2, carrying NaN outside each window's Coverage Universe.

Related

source

The available-case seam

An estimator that carries a CoveragePolicy is a mask-aware estimator, so its panel method hands it the whole window and the panel's active mask instead of reducing to the Coverage Universe.

PortfolioOptimisers.coverage_panel_momentFunction
coverage_panel_moment(f, est, cvg, X, pnl, expand; dims::Int = 1, kwargs...)

Routes a moment verb's Asset Panel method to the Coverage Universe seam or to the available-case one.

An estimator that carries a CoveragePolicy is a mask-aware estimator in the sense the covariance root of this file states: it takes the whole window and reads pnl.amsk itself, so the panel method must hand it the mask rather than reduce the window to its Coverage Universe. The cvg field is passed as the third argument, so the two seams are chosen by dispatch, and the Nothing method is the reduce-and-expand the root has always run.

expand is the framing the verb needs, because the four moment shapes frame differently: a covariance frames as a matrix, a marginal along its asset axis alone, and a co-moment at the pair index. It is passed rather than chosen here, so that this routing is written once for every verb.

Arguments

  • f: The plain, panel-free method of the verb.
  • est: The estimator.
  • cvg: The policy the estimator carries, which selects the seam.
  • X: Data matrix observations × assets if the dims keyword does not exist or dims = 1, assets × observations when dims = 2.
  • pnl: Optional AssetPanel, whose active mask the Coverage Universe of the fit is derived from. nothing makes the rule finiteness alone.
  • expand: The framing, called as expand(val, cmsk) on the Coverage Universe seam and unused on the other.
  • dims: Dimension along which to perform the computation.
  • kwargs...: Additional keyword arguments passed to the estimator.

Returns

  • val: The moment on the full asset universe.

Related

source
PortfolioOptimisers.coverage_panel_momentMethod
coverage_panel_moment(
    f,
    est,
    ::CoveragePolicy,
    X::AbstractMatrix{<:Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}},
    pnl::Union{Nothing, AssetPanel},
    ;
    dims,
    kwargs...
) -> Any

CoveragePolicy method of coverage_panel_moment. The available-case seam: hand the estimator the whole window and the panel's active mask, and let it write its own frame.

Related

source
PortfolioOptimisers.coverage_variance_seriesFunction
coverage_variance_series(ce, cvg, X, pnl; dims::Int = 1, kwargs...) -> MatNum

Routes a point-in-time variance series to the Coverage Universe seam or to the available-case one.

The series counterpart of coverage_panel_moment, written apart from it because the series refits per observation and frames per row rather than once at the end.

Arguments

  • ce: Covariance estimator.
  • cvg: The policy the estimator carries, which selects the seam.
  • X: Data matrix observations × assets if the dims keyword does not exist or dims = 1, assets × observations when dims = 2.
  • pnl: Optional AssetPanel, whose active mask the Coverage Universe of the fit is derived from. nothing makes the rule finiteness alone.
  • dims: Dimension along which to perform the computation.
  • kwargs...: Additional keyword arguments passed to the estimator.

Returns

  • val::Matrix{<:Number}: Variance series on the full asset universe.

Related

source
PortfolioOptimisers.coverage_variance_seriesMethod
coverage_variance_series(
    ce::AbstractCovarianceEstimator,
    ::Nothing,
    X::AbstractMatrix{<:Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}},
    pnl::Union{Nothing, AssetPanel};
    dims,
    kwargs...
) -> Any

Nothing method of coverage_variance_series. The Coverage Universe seam: each window is reduced to its own Coverage Universe and the estimator is fitted on that block, which is the rule variance_series(ce::AbstractCovarianceEstimator, X::MatNum, pnl::Option{<:AssetPanel}; dims::Int = 1, kwargs...) states.

Related

source
PortfolioOptimisers.coverage_variance_seriesMethod
coverage_variance_series(
    ce::AbstractCovarianceEstimator,
    ::CoveragePolicy,
    X::AbstractMatrix{<:Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}},
    pnl::Union{Nothing, AssetPanel};
    dims,
    kwargs...
) -> Any

CoveragePolicy method of coverage_variance_series. Each window is fitted available-case over the whole universe rather than reduced to its own Coverage Universe, so an asset that lists inside the window carries a number from its listing on instead of NaN throughout.

Algorithm

  1. Orient X, and the panel's active mask, to observations × assets.
  2. For each observation t, fit the estimator on the window 1:t with the mask of those rows.
  3. Write the answer into row t, and return the series, transposed when dims == 2.

Related

source
PortfolioOptimisers.coverage_floorFunction
coverage_floor(cvg::Nothing)
coverage_floor(cvg::CoveragePolicy)
coverage_floor(me::AbstractExpectedReturnsEstimator)
coverage_floor(ce::StatsBase.CovarianceEstimator)
coverage_floor(me::SimpleExpectedReturns)
coverage_floor(ve::SimpleVariance)
coverage_floor(ce::Covariance)
coverage_floor(ce::PortfolioOptimisersCovariance)
coverage_floor(a::Nothing, b::Nothing)
coverage_floor(a::Nothing, b::Real)
coverage_floor(a::Real, b::Nothing)
coverage_floor(a::Real, b::Real)

Read the coverage floor an estimator admits on, and take the binding one of two arms.

A CoveragePolicy is a field of one estimator, so the floor a fit admits on is not a property of the fit as a whole until someone reads it off the arms. The one-argument methods do that read: a carrier answers its own cvg, a wrapper forwards to the estimator it holds, and every other estimator answers nothing, which says that this arm states no floor rather than that it states a floor of zero. The two-argument method takes the maximum of two arms, because admission is their conjunction — the Investable Mask needs mu and the diagonal of sigma finite, and coverage_admission reads the same per-asset count for both — so a floor stated on either arm bounds every investable column whatever the other arm does.

The reader is resolve_fill_limit, which turns the floor into the share a scenario_fill may invent in silence. An estimator with no method answers nothing through its root's method, so a policy buried inside a wrapper this verb does not forward through names every fill rather than none: the conservative answer, and never a silence the caller did not ask for.

The two-argument methods are dispatch rather than a branch, so a call site holding two Options finds a method for every arm of its union split.

Arguments

  • cvg: A CoveragePolicy or nothing.
  • me, ve, ce: A moment estimator whose floor is being read.
  • a, b: The floors of two arms, each a Real or nothing.

Returns

  • floor::Option{<:Real}: The coverage floor, or nothing when none is stated.

Related

source
coverage_floor(pe::EmpiricalPrior) -> Any

EmpiricalPrior method of coverage_floor, the binding floor of its two arms.

pe.me and pe.ce may each carry a CoveragePolicy, and either bounds every investable column on its own, because the Investable Mask is the conjunction of the two admissions and both read the same per-asset observation count. The binding floor is therefore the maximum of the floors the arms state, and a mixed configuration needs no rule of its own.

Arguments

  • pe: The empirical prior estimator.

Returns

  • floor::Option{<:Real}: The binding coverage floor, or nothing when neither arm states one.

Related

source