The coverage policy: private API
PortfolioOptimisers.CoverageCounts — Type
struct CoverageCounts{__T_nu, __T_centre, __T_active, __T_stale}Carries the per-cell denominators and the per-asset bookkeeping of an available-case fold.
The component a partial-fit state holds in its cvg field, which is nothing on the plain path so that the plain state costs nothing. nu has the shape of the accumulator it serves, because the observation count of a covariance cell is a count per pair and not a count per asset, and centre has that shape wherever a cell's own centre differs from the state's per-asset mean.
This type is an implementation detail and is not intended for direct use. partial_fit! writes it, the read-out verbs divide by it, and merge_states folds two of them.
Fields
nu:nu: Per-cell surviving observation count, of the shape of the accumulator it serves.
centre:centre: Per-cell running mean, of the shape of the accumulator it serves, ornothingwhen the state's ownmuis already the cell's centre. Entry(i, j)is the running mean of assetiover the observations at which the pair(i, j)is valid, so entry(j, i)is the mean of assetjover those same observations.
active:active: Active mask of the last observation folded, one entry per asset.
stale:stale: Number of observations folded since each asset was last finite and active, one entry per asset.
Related
PortfolioOptimisers.coverage_counts_seed — Function
coverage_counts_seed(cvg::Nothing, counts, N::Integer, Tf::Type,
pairwise::Bool) -> Nothing
coverage_counts_seed(cvg::CoveragePolicy, counts::CoverageCounts, N::Integer, Tf::Type,
pairwise::Bool) -> CoverageCounts
coverage_counts_seed(cvg::CoveragePolicy, counts::Nothing, N::Integer, Tf::Type,
pairwise::Bool) -> CoverageCountsReturns the CoverageCounts an available-case fold writes into, seeding one of zeros when the state carries none.
The seed is written here rather than inside partial_fit!, so that the branch that reads the cvg field of a state has one home and the fold reads as one line. The policy is the first argument because it is what selects the arm: nothing is the plain path and gives nothing, whatever the state carries.
Arguments
cvg: The policy the estimator carries.counts: The component the state carries, ornothing.N: Number of assets.Tf: Element type of the accumulators.pairwise: Whether the cell axis is a pair, so thatnuandcentreareN × Nrather thanN-long.
Returns
counts::Option{<:CoverageCounts}: The componentcountsholds, or a fresh one of zeros.
Related
Base.copy — Method
copy(x::CoverageCounts) -> CoverageCounts
Copies a CoverageCounts, so that the copy shares no array with the original.
Arguments
x: The component to copy.
Returns
counts::CoverageCounts: A fresh component, equal tox, whose arrays are fresh.
Related
PortfolioOptimisers.coverage_counts_view — Function
coverage_counts_view(x::Nothing, i) -> Nothing
coverage_counts_view(x::CoverageCounts, i) -> CoverageCountsSlices a CoverageCounts to the selected assets.
A per-cell count reads the assets of its own cell alone, so the slice of the component is the component of the sliced universe, entry for entry. The slice copies by index and does not view, as port_opt_view does for every partial-fit state.
Arguments
x: The component to slice, ornothing.i: Index or indices of the assets to keep.
Returns
counts::Option{<:CoverageCounts}: The component of the same sample over the selected assets.
Related
PortfolioOptimisers.coverage_valid — Function
coverage_valid(
x::AbstractVector{<:Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}},
active_mask::Union{Nothing, AbstractVector{<:Bool}},
counts::CoverageCounts
) -> Tuple{Any, Any}
Reads the assets that are valid at one observation, and the assets that have just gone inactive.
An asset is valid when its return is finite and the active mask admits it, which is the condition the exponentially weighted family already reads. With no mask every asset is active, so a non-finite return reads as a holiday rather than as a delisting and no asset is ever newly inactive.
Arguments
x: One observation, one entry per asset.active_mask: The active mask of the Asset Panel at this observation, ornothing.counts: The component whoseactivefield holds the mask of the previous observation.
Validation
active_mask, when it is given, has one entry per asset. ADimensionMismatchis thrown otherwise.
Returns
(valid, ni)::Tuple: The valid assets, and the assets that were active at the previous observation and are inactive at this one.
Related
PortfolioOptimisers.coverage_valid_block — Function
coverage_valid_block(
X::AbstractMatrix{<:Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}},
active_mask::Union{Nothing, AbstractMatrix{<:Bool}};
dims
) -> NTuple{5, Any}
Reads everything a two-pass available-case fit needs out of a block of observations.
The block counterpart of coverage_valid and coverage_step!, for the arms that have no incremental recursion and must see the whole window at once. It returns the oriented block beside the four quantities the fold would otherwise have carried, so that a two-pass arm and a folding arm read the same universe and the same bookkeeping.
Algorithm
- Orient
X, and the mask when there is one, toobservations × assets. - Take the valid entries, finite and active, giving
F. - Take each asset's available-case mean over its own valid entries, giving
mu, which is zero for an asset with none. - Take the active mask of the last observation, and each asset's staleness at it.
Arguments
X: The block of observations.active_mask: The active mask of the Asset Panel over the block, ornothing.dims: Whether the observations lie on the rows,1, or on the columns,2.
Validation
active_mask, when it is given, has the shape ofX. ADimensionMismatchis thrown otherwise.
Returns
(Xo, F, mu, active, stale)::Tuple: The oriented block, its valid entries, each asset's available-case mean, the active mask of the last observation, and each asset's staleness at it.
Related
PortfolioOptimisers.coverage_step! — Function
coverage_step!(
counts::CoverageCounts,
valid::AbstractVector{<:Bool},
active_mask::Union{Nothing, AbstractVector{<:Bool}}
)
Moves the per-asset bookkeeping of a CoverageCounts on by one observation.
Algorithm
- Set the staleness of every valid asset to zero, and add one to the staleness of every other.
- Rebind
activeto the mask of this observation, which is every asset when the caller gave none.
Arguments
counts: The component to move on, mutated in place.valid: The valid assets of this observation.active_mask: The active mask of this observation, ornothing.
Returns
nothing.
Related
PortfolioOptimisers.coverage_merge_stale — Function
coverage_merge_stale(
a::CoverageCounts,
b::CoverageCounts,
n_b::Integer
) -> Any
Folds the staleness counters of two CoverageCounts fitted on consecutive blocks.
An asset that was valid somewhere in the second block carries that block's own count, and an asset that was valid nowhere in it has spent the whole block stale, so its staleness is the two counts added. The test for "valid nowhere in b" is that b's counter has reached b's observation count, which is what the counter does when nothing resets it.
Arguments
a: The component of the first block of observations.b: The component of the second block of observations.n_b: The number of observations folded intob.
Returns
stale::Vector{<:Integer}: The staleness of each asset over the concatenated block.
Related
PortfolioOptimisers.coverage_reset! — Function
coverage_reset!(A::Nothing, ni::AbstractVector{<:Bool}) -> Nothing
coverage_reset!(A::AbstractVector, ni::AbstractVector{<:Bool}) -> Nothing
coverage_reset!(A::AbstractMatrix, ni::AbstractVector{<:Bool}) -> NothingZeroes the entries of an accumulator that touch a set of assets.
The primitive the ResetCoverage methods of fold_inactive! share, so that the reset of a per-asset accumulator and the reset of a per-pair accumulator are written once.
Arguments
A: The accumulator or count array to zero, mutated in place.nothingpasses through, which is thecentreof a per-asset state.ni: One entry per asset,truewhere the asset is to be zeroed.
Returns
nothing.
Related
PortfolioOptimisers.coverage_admission — Function
coverage_admission(
cvg::CoveragePolicy,
counts::CoverageCounts,
n::Integer
) -> Union{Nothing, BitVector}
Reads the universe of an available-case fit out of its per-cell counts.
The read-out's own mask, and the one place admits is called. It collapses onto the nothing sentinel exactly as coverage_sentinel does, so an answer that admits every asset allocates no mask. Unlike coverage_sentinel it refuses no sample: an available-case fit whose window admits nothing answers all NaN rather than raising, because the fit is opt-in and its caller asked for the gaps.
Algorithm
- Take the per-asset observation count, which is the diagonal when the counts are per pair.
- Divide it by
n, the number of observations folded, giving each asset's coverage share. - Call
admitsonce per asset. - Return
nothingwhen every asset is admitted, and the mask otherwise.
Arguments
cvg: The policy the estimator carries.counts: The per-cell counts the state carries.n: The number of observations folded, which is the share's denominator.
Returns
cmsk::Option{BitVector}: The admitted assets, ornothingwhen every asset is admitted.
Related
PortfolioOptimisers.coverage_divide — Function
coverage_divide(
M::AbstractArray,
nu::AbstractArray,
corrected::Bool,
cmsk::Union{Nothing, BitVector}
) -> Any
Divides an available-case accumulator by its per-cell denominator, and frames the assets the policy refuses.
The tail every available-case read-out shares. A cell whose denominator has not reached one is NaN, which is the per-cell half of the rule, and an asset coverage_admission refuses is NaN across its whole row and column, which is the per-asset half.
The answer's element type is the type of the division itself, so a Float32 accumulator reads out as Float32 and is never widened by the sentinel. An element type that cannot hold NaN cannot hold the answer either: an exact accumulator, a Rational among them, raises an InexactError at the first cell the policy refuses rather than silently reading out as Float64. A window with no refused cell is unaffected.
Algorithm
- Divide each entry of
Mby its entry ofnulesscorrected, writingNaNwhere that denominator is below one. - Write
NaNinto every entry that touches an asset outsidecmsk.
Arguments
M: The accumulator, of the shape of the answer.nu: The per-cell denominator, of the shape ofM.corrected: The Bessel correction, subtracted from every denominator.cmsk: The admitted assets, ornothing.
Returns
val::Array{<:AbstractFloat}: The answer, of the shape ofM, carryingNaNwhere the fit has no number.
Related
PortfolioOptimisers.coverage_frame — Function
coverage_frame(
A::AbstractArray,
nu::AbstractArray,
cmsk::Union{Nothing, BitVector}
) -> Any
Frames an available-case estimate that needs no division, and frames the assets the policy refuses.
The read-out of a quantity that is already a ratio, which is what a running per-asset mean is: the value is copied where its cell has an observation and is NaN where it has none, and coverage_refuse! then writes the frame. It exists beside coverage_divide so that a Welford mean is never multiplied by its count and divided by it again, which would move the last bits of an answer the fold computed exactly.
The answer carries the element type of A, which the fold already derived from its own division. As in coverage_divide, an exact element type cannot hold the NaN sentinel and raises an InexactError at the first cell that has no observation.
Arguments
A: The estimate, of the shape of the answer.nu: The per-cell observation count, of the shape ofA.cmsk: The admitted assets, ornothing.
Returns
val::Array{<:AbstractFloat}: The answer, of the shape ofA, carryingNaNwhere the fit has no number.
Related
PortfolioOptimisers.coverage_refuse! — Function
coverage_refuse!(val::AbstractArray, cmsk::Nothing) -> Nothing
coverage_refuse!(val::AbstractArray, cmsk::BitVector) -> NothingWrites NaN into every entry of an answer that touches an asset the policy refuses.
The per-asset half of the read-out rule, shared by coverage_divide and coverage_frame. A nothing mask is the sentinel of coverage_admission and means that every asset is admitted, so nothing is written.
Arguments
val: The answer, mutated in place.cmsk: The admitted assets, ornothing.
Returns
nothing.
Related
PortfolioOptimisers.coverage_refuse_comoment! — Function
coverage_refuse_comoment!(val::AbstractMatrix, cmsk::Nothing, ::Val) -> Nothing
coverage_refuse_comoment!(val::AbstractMatrix, cmsk::BitVector, ::Val{:sk}) -> Nothing
coverage_refuse_comoment!(val::AbstractMatrix, cmsk::BitVector, ::Val{:kt}) -> NothingWrites NaN into every entry of a higher-order co-moment answer that touches an asset the policy refuses.
The co-moment form of coverage_refuse!, for an answer whose axes are not all the asset axis. A coskewness tensor is assets × assets², so its rows take the asset mask and its columns the pair mask; a cokurtosis matrix is assets² × assets², so both of its axes take the pair mask. The Val marker names the shape, exactly as it does for expand_moment, and the mask stays one argument so the arm is a plain dispatch rather than a product of two Options.
A pair is admitted when both of its assets are, and a co-moment tensor indexes the pair (i, j) at the column (i - 1) * N + j, which is the layout coverage_pair_index states. kron(cmsk, cmsk) is that conjunction in that order, entry for entry.
Arguments
val: The answer, mutated in place.cmsk: The admitted assets, ornothingwhen every asset is admitted.::Val:Val(:sk)for a coskewness tensor andVal(:kt)for a cokurtosis matrix.
Returns
nothing.
Related