Base moments: private API
Abstract moment types and fallbacks
Some optimisations and constraints make use of summary statistics. These types and functions form the base for moment estimation in PortfolioOptimisers.jl.
They also provide generic fallbacks for the various functionality in the library.
PortfolioOptimisers.AbstractExpectedReturnsAlgorithm — Type
abstract type AbstractExpectedReturnsAlgorithm <: AbstractAlgorithmAbstract supertype for all expected returns algorithm types.
All concrete and/or abstract types that implement a specific algorithm used by an expected returns estimator should be subtypes of AbstractExpectedReturnsAlgorithm.
Interfaces
Given that these are meant to be used by expected returns estimators, there are no specific methods that need to be implemented for this abstract type. However, it serves as a marker for dispatching and organising different expected returns algorithms within the library. The interfaces should be defined at the level of the expected returns estimator that utilises these algorithms.
Related
PortfolioOptimisers.AbstractMomentAlgorithm — Type
abstract type AbstractMomentAlgorithm <: AbstractAlgorithmAbstract supertype for all moment algorithm types.
All concrete and/or abstract types that implement a specific algorithm for moment estimation should be subtypes of AbstractMomentAlgorithm.
Interfaces
Given that these are meant to be used by covariance estimators, there are no specific methods that need to be implemented for this abstract type. However, it serves as a marker for dispatching and organising different moment algorithms within the library. The interfaces should be defined at the level of the covariance estimator that utilises these algorithms.
Related
PortfolioOptimisers.gap_fill_value — Method
gap_fill_value(ce::StatsBase.CovarianceEstimator) -> NumberReturn the value that stands in for a gapped cell of a sample handed to ce.
A gapped sample carries a non-finite cell because the asset was not there, not because a number went wrong. A consumer that holds such a sample and an arbitrary covariance estimator cannot know which of the two the estimator wants of it, so it asks the estimator, and the answer is a property of the estimator alone.
A finite answer is written over every gapped cell before the sample is handed over, so the estimator sees a complete sample and no mask. A non-finite answer leaves the gap where it is, and the consumer hands the active mask that explains it to Statistics.cov(ce, X; dims, active_mask), which an estimator answering a non-finite value owns.
The fallback is zero: a plain moment estimator refuses a gapped sample outright, and zero is the neutral value of a standardised series. A gap-aware estimator answers NaN instead, and that one method is the whole cost of adding one.
A covariance estimator nests, so the answer recurses. An estimator that wraps another and forwards the sample and its keywords untouched — PortfolioOptimisersCovariance and CorrelationCovariance — answers what the estimator it wraps answers, so wrapping a gap-aware estimator keeps the gap. One that reads the sample itself before it delegates, as Covariance does through its own expected-returns estimator, keeps the fallback: it refuses the gap on its own account, and no answer of its inner estimator changes that.
Arguments
ce: Covariance estimator.
Returns
fv::Number: The value a gapped cell takes, zero for a plain estimator andNaNfor a gap-aware one.
Related
PortfolioOptimisers.densify — Function
densify(X::MatNum) -> MatNumMaterialise a lazy or sparse observation matrix as a dense Matrix.
StatsBase's weighted moment API is typed on DenseMatrix. A Transpose, an Adjoint, a SubArray or a sparse matrix does not match it. Without a mean the call raises a MethodError, which is recoverable. With a mean it is not: cov(::SimpleCovariance, X, w; mean = mu) forwards four positional arguments as covm(X, mu, w, dims), and when the DenseMatrix method does not match, that call resolves to Statistics.covm(x, xmean, y, ymean, vardim) — the cross-covariance of X against the weight vector. It returns an N × 1 matrix in place of an N × N one and raises nothing. robust_cov and robust_cor densify before every weighted call so that neither outcome is reachable.
Algorithm
- When
Xis aDenseMatrixof numbers or ofJuMPscalars, return it unchanged. - Otherwise return
Matrix(X), a dense copy.
Arguments
X: Data matrixobservations × assetsif thedimskeyword does not exist ordims = 1,assets × observationswhendims = 2.
Returns
X::MatNum:Xitself when it is already a denseMatrix, andMatrix(X)otherwise.
Related
PortfolioOptimisers.robust_cov — Function
robust_cov(
ce::StatsBase.CovarianceEstimator,
X::MatNum,
[w::StatsBase.AbstractWeights];
dims::Int = 1,
mean = nothing,
kwargs...
) -> MatNumComputes the optionally weighted covariance with compat_cov on dense observations. The unweighted method retries once with a densified Matrix after a MethodError. The weighted method calls densify before the estimator.
Algorithm
- Without
w, callcompat_covonXas the caller gave it. When that call raises aMethodError, callcompat_covonce more onMatrix(X). Any other error propagates to the caller. - With
w, densifyXwithdensify, then callcompat_covonce. There is no retry, because the densification already removes the only failure the retry answers. - Return the matrix that
compat_covreturned.
Arguments
ce: Covariance estimator.X: Data matrixobservations × assetsif thedimskeyword does not exist ordims = 1,assets × observationswhendims = 2.w: Optional observation weights vectorobservations × 1, or a concrete subtype ofDynamicAbstractWeights. Ifnothing, the computation is unweighted.dims: Dimension along which to perform the computation.mean: Optional mean value to use for centering.kwargs...: Additional keyword arguments passed tocompat_cov.
Validation
dims in (1, 2).
Returns
sigma::MatNum: Covariance matrixassets x assets.
Related
PortfolioOptimisers.robust_cor — Function
robust_cor(
ce::StatsBase.CovarianceEstimator,
X::MatNum,
[w::StatsBase.AbstractWeights];
dims::Int = 1,
mean = nothing,
kwargs...
) -> MatNumComputes the optionally weighted correlation with compat_cor on dense observations. The unweighted method retries once with a densified Matrix after a MethodError. The weighted method calls densify before the estimator.
Algorithm
- Without
w, callcompat_coronXas the caller gave it. When that call raises aMethodError, callcompat_coronce more onMatrix(X). Any other error propagates to the caller. - With
w, densifyXwithdensify, then callcompat_coronce. There is no retry, because the densification already removes the only failure the retry answers. - Return the matrix that
compat_correturned.
Arguments
ce: Covariance estimator.X: Data matrixobservations × assetsif thedimskeyword does not exist ordims = 1,assets × observationswhendims = 2.w: Optional observation weights vectorobservations × 1, or a concrete subtype ofDynamicAbstractWeights. Ifnothing, the computation is unweighted.dims: Dimension along which to perform the computation.mean: Optional mean value to use for centering.kwargs...: Additional keyword arguments passed tocompat_cor.
Validation
dims in (1, 2).
Returns
rho::MatNum: Correlation matrixassets x assets.
Related
PortfolioOptimisers.compat_cov — Function
compat_cov(
ce::StatsBase.CovarianceEstimator,
X::MatNum,
[w::StatsBase.AbstractWeights];
dims::Int = 1,
mean = nothing,
kwargs...
) -> MatNumCompute the covariance matrix robustly using the specified covariance estimator ce, data matrix X, and optional weights vector w.
Algorithm
- When the caller passed extra keyword arguments, and
hasmethodreports thatStatistics.covtakesdims,meanand those keys for this estimator and these arguments, callStatistics.covwith all of them and return the result. - When step 1 raises a
MethodError, drop the extra keyword arguments and continue. A method whose signature ends in akwargs...slurp satisfieshasmethodand can still reject a key further down its call chain. Any other error propagates to the caller. - Call
Statistics.cov(ce, X, args...; dims = dims, mean = mean), and return the result.
Arguments
ce: Covariance estimator.X: Data matrixobservations × assetsif thedimskeyword does not exist ordims = 1,assets × observationswhendims = 2.w: Optional observation weights vectorobservations × 1, or a concrete subtype ofDynamicAbstractWeights. Ifnothing, the computation is unweighted.dims: Dimension along which to perform the computation.mean: Optional mean value to use for centering.kwargs...: Additional keyword arguments passed tocov.
Returns
sigma::MatNum: Covariance matrixassets x assets.
Related
PortfolioOptimisers.compat_cor — Function
compat_cor(
ce::StatsBase.CovarianceEstimator,
X::MatNum,
[w::StatsBase.AbstractWeights];
dims::Int = 1,
mean = nothing,
kwargs...
) -> MatNumCompute the correlation matrix robustly using the specified covariance estimator ce, data matrix X, and optional weights vector w.
Algorithm
- When
hasmethodreports thatStatistics.cortakesdimsandmeanfor this estimator and these arguments, take steps 2 and 3. Otherwise take step 4. - When the caller passed extra keyword arguments, and
hasmethodreports thatStatistics.cortakes those keys too, callStatistics.corwith all of them and return the result. When that call raises aMethodError, drop the extra keyword arguments and continue. A method whose signature ends in akwargs...slurp satisfieshasmethodand can still reject a key further down its call chain. - Call
Statistics.cor(ce, X, args...; dims = dims, mean = mean), and return the result. When that call raises aMethodError, continue to step 4. Any other error propagates to the caller. - The estimator answers no
corcall, so compute the covariance matrixsigmawithrobust_covinstead. - When
sigmais mutable, convert it to a correlation matrix in place withStatsBase.cov2cor!and the square roots of its own diagonal. Otherwise convert a dense copy withStatsBase.cov2cor. - Return
sigma.
Arguments
ce: Covariance estimator.X: Data matrixobservations × assetsif thedimskeyword does not exist ordims = 1,assets × observationswhendims = 2.w: Optional observation weights vectorobservations × 1, or a concrete subtype ofDynamicAbstractWeights. Ifnothing, the computation is unweighted.dims: Dimension along which to perform the computation.mean: Optional mean value to use for centering.kwargs...: Additional keyword arguments passed tocor.
Returns
rho::MatNum: Correlation matrixassets x assets.
Related
PortfolioOptimisers.moment_window_and_weights — Function
moment_window_and_weights(
X::VecNum_MatNum,
w::Option{<:ObsWeights},
args...;
dims::Int = 1,
kwargs...
) -> (VecNum_MatNum, Option{<:StatsBase.AbstractWeights})
moment_window_and_weights(
X::VecNum_MatNum,
w::Option{<:ObsWeights},
window::VecInt;
dims::Int = 1,
kwargs...
) -> (VecNum_MatNum, Option{<:StatsBase.AbstractWeights})Apply the observation window and resolve weights for moment estimation.
Takes the view of X over the observations that window indexes, and resolves the observation weights over that same view. The caller resolves window first with get_window, so an Int window has already become a range by the time it reaches this function.
Algorithm
- Without a
window,Xpasses through unchanged, and step 3 resolves the weights over the whole of it. - With a
window, take the view ofXover those observations. For a matrix that isview(X, window, :)whendims == 1, andview(X, :, window)whendims == 2. For a vector it isview(X, window). Indexwto the same observations withnothing_scalar_array_getindex. - Resolve the observation weights with
get_observation_weights, overwand theXof the step above. - Return that
Xand the resolvedw.
Arguments
X: Data matrix or vector.w: Optional observation weights vectorobservations × 1, or a concrete subtype ofDynamicAbstractWeights. Ifnothing, the computation is unweighted.- Either:
args: Additional positional arguments (ignored).window: Observation window. An integer selects the lastwindowobservations, and a vector of indices selects those observations.
dims: Dimension along which to perform the computation. Ignored ifXis a vector.kwargs: Additional keyword arguments (ignored).
Returns
X::VecNum_MatNum: Appropriately windowed data matrix.w::Option{<:StatsBase.AbstractWeights}: Resolved and appropriately windowed weights.
Related
PortfolioOptimisers.windowed_preamble — Function
windowed_preamble(
est,
w::Union{Nothing, DynamicAbstractWeights, AbstractWeights},
window::Union{Nothing, Integer, AbstractVector{<:Integer}},
X::AbstractMatrix{<:Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}};
iv,
dims,
kwargs...
) -> Tuple{Any, Any, Nothing}
Shared preamble for windowed moment estimators (matrix input).
Whenever a window is given — an Int, which resolves to a range, or an explicit index vector — iv is subset to the same rows, or columns when dims = 2, so it stays aligned with the windowed returns. Only window = nothing, which resolves to a Colon, leaves iv unchanged.
Algorithm
- Resolve
windowwithget_window, givingwin.nothingresolves to aColon, anIntto the range of the lastwindowobservations, and an index vector passes through. - Apply
wintoXand rebind the observation weights to it withmoment_window_and_weights, giving the windowedXandw_new. - Build
inner, a copy ofestthat carriesw_new, withfactory. - When
ivis given andwinis an index vector, subsetivto the same rows, or to the same columns whendims == 2. AColonleavesivunchanged, so the full-data case never copies it. - Return
inner, the windowedX, andiv.
Arguments
est: Wrapped moment estimator to be cloned with updated weights.w: Optional observation weights applied after windowing.window: Window specification —nothing(full data), anInt(lastwindowobservations), or aVecIntof explicit row/column indices.X: Data matrix of asset returns.iv: Optional instrument variable matrix; subsetted to the window whenwindowis aVecInt.dims: Observation dimension — 1 for rows (default), 2 for columns. Checked byassert_dims, so every generated windowed method rejects an out-of-rangedimsinstead of silently resolving a one-observation window.kwargs...: Passed through tomoment_window_and_weights.
Validation
dims in (1, 2).
Returns
(inner, X, iv): Weight-updated estimator, windowed returns matrix, and (possibly subsetted) instrument variable matrix.
Related
windowed_preamble(
est,
w::Union{Nothing, DynamicAbstractWeights, AbstractWeights},
window::Union{Nothing, Integer, AbstractVector{<:Integer}},
X::AbstractVector{<:Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}}
) -> Tuple{Any, Any}
Shared preamble for windowed moment estimators (vector input).
This method takes no dims, because a vector carries one axis, and no iv, because no vector generic of the family declares one.
Algorithm
- Resolve
windowwithget_window, givingwin.nothingresolves to aColon, anIntto the range of the lastwindowobservations, and an index vector passes through. - Apply
wintoXand rebind the observation weights to it withmoment_window_and_weights, giving the windowedXandw_new. - Build
inner, a copy ofestthat carriesw_new, withfactory. - Return
innerand the windowedX.
Arguments
est: Wrapped moment estimator to be cloned with updated weights.w: Optional observation weights applied after windowing.window: Window specification —nothing(full data), anInt(lastwindowobservations), or aVecIntof explicit indices.X: Data vector of returns.
Returns
(inner, X): Weight-updated estimator and windowed returns vector.
Related
PortfolioOptimisers.weighted_centre — Function
weighted_centre(X::MatNum, me::AbstractExpectedReturnsEstimator,
w::Option{<:ObsWeights}; dims::Int = 1, mean = nothing,
kwargs...) -> Union{<:Number, <:ArrNum}Resolve the centre that a moment estimator's own observation weights weight.
A moment estimator's observation weights weight its centre, and not its deviations alone. This verb is the one place that rule lives, so SimpleVariance, Covariance, Coskewness and Cokurtosis reach their centre by one rule.
Algorithm
meanis notnothing: return it unchanged. The keyword is the escape hatch for a centre thatwdoes not describe.wisnothing: returnStatistics.mean(me, X; dims = dims, kwargs...).wis notnothing: sendmethroughfactorywithw, so the centre carries the weights of the deviations, and return the mean of the rebuilt estimator.
Step 2 is a performance guard and not a second contract. w reaches this verb from a field, so its type decides the branch, and the guard keeps a windowed loop from rebuilding the estimator tree of me once per window.
Arguments
X: Data matrixobservations × assetsif thedimskeyword does not exist ordims = 1,assets × observationswhendims = 2.me: Expected returns estimator.w: Optional observation weights vectorobservations × 1, or a concrete subtype ofDynamicAbstractWeights. Ifnothing, the computation is unweighted.dims: Dimension along which to perform the computation.mean: Optional mean value to use for centering.kwargs...: Additional keyword arguments for the expected returns estimator.
Returns
mu::Union{<:Number, <:ArrNum}: Centring vector, weighted bywwhenwis notnothing.
Related
PortfolioOptimisers.demean_returns — Function
demean_returns(X::MatNum, me::AbstractExpectedReturnsEstimator; dims::Int = 1, mean = nothing,
kwargs...) -> MatNumDemeans the returns in X using the expected returns estimator me or if provided, a mean array.
Algorithm
- Resolve the centre
muwithweighted_centre. Whenmeanisnothing, the estimator computes it; otherwisemuismean.mecarries whatever weights it holds, and this verb adds none of its own. - Subtract
mufromXby broadcast, and return the result.dimsnames the observation axis, and the estimator shapesmualong the other one, so the broadcast subtracts one value per asset from every observation of that asset.
Arguments
X: Data matrixobservations × assetsif thedimskeyword does not exist ordims = 1,assets × observationswhendims = 2.me: Expected returns estimator.dims: Dimension along which to perform the computation.mean: Optional mean value to use for centering.kwargs...: Additional keyword arguments for the expected returns estimator.
Returns
MatNum: The demeaned returns matrix.
Related
Windowed estimator generation
The five windowed estimators — WindowedExpectedReturns, WindowedVariance, WindowedCovariance, WindowedCoskewness and WindowedCokurtosis — share one shape: wrap an inner estimator, restrict it to a trailing window, and forward every moment call to it. Each is generated from a single declaration by @windowed_estimator, so the struct, its constructor, its factory/port_opt_view methods, its forwarding methods and all of their docstrings cannot drift apart.
The entries below are the macro and its expansion-time machinery. They are internal: callers use the five estimators, not these.
PortfolioOptimisers.WINDOWED_ESTIMATOR_KEYS — Constant
WINDOWED_ESTIMATOR_KEYSAssignment keys recognised in a @windowed_estimator body, besides the single field::Type = default declaration. Anything else is rejected at macro-expansion time with a did_you_mean suggestion, so a mistyped key cannot silently produce a malformed docstring or a missing forwarding method.
Related
PortfolioOptimisers.WINDOWED_ESTIMATOR_INPUTS — Constant
WINDOWED_ESTIMATOR_INPUTSInput types a @windowed_estimator forward entry may declare. MatNum generates the matrix forwarder (threading dims and iv through windowed_preamble), VecNum the vector forwarder.
Related
PortfolioOptimisers.@windowed_estimator — Macro
@windowed_estimator Name <: Super begin
field::FieldType = Default()
noun = "Noun"
forward = [generic(::MatNum; mean) => :ret_key, ...]
doctest = """..."""
endDeclare a windowed moment estimator: a wrapper that restricts an inner moment estimator to a sub-window of observations and rebinds observation weights to that window, leaving the inner estimator's semantics untouched.
One invocation emits the whole family member — the @propagatable @concrete struct (inner estimator tagged @fprop @vprop, w tagged @wprop, plus window), both constructors with their validation, one forwarding method per forward entry, the export, and every docstring.
Five nominal types exist rather than one parametric Windowed{E} because each answers a different generic and must subtype a different abstract estimator — AbstractCovarianceEstimator, CoskewnessEstimator, and the rest are load-bearing for dispatch across the library, and a Julia struct's supertype cannot depend on a type parameter. This macro is what keeps the five in sync.
Body
field::FieldType = Default(): the inner estimator. The field name is also itsfield_dictkey and the argument name of every generated method, so it must follow the library convention (me,ce,ve,ske,kte).noun: capitalised noun phrase naming the moment, e.g."Expected returns". Drives all generated prose.forward: one mini-signature per generic to forward, paired with theret_dictkey(s) documenting its return values. Namingmeanin the mini-signature emits it as a named keyword instead of letting it ride inkwargs..., where it would leak intowindowed_preamble.doctest: the body of thejldoctestblock for the# Examplessection, without its fences.
Unknown keys, malformed forward entries, and unknown field_dict/ret_dict keys are rejected at macro-expansion time with a did_you_mean suggestion.
Algorithm
- Read
nameandsuperfrom the header. - Walk the body once. The one
field::Type = defaultline goes towindowed_parse_field, which returnsfield,ftypeanddefault. Thenoun,forwardanddoctestlines bind their values. Any other key raises. - Parse every entry of
forwardwithwindowed_parse_forward, givingspecs. - Render one cross-reference per entry of
specswithwindowed_method_ref, givingrefs. - For each entry of
specs, build one documented forwarding method:windowed_method_docwrites its docstring, andwindowed_method_defwrites its body. Each method's# Relatedsection lists therefsof its siblings and not its own. - Build
structexpr, the@concretestruct. It declares the inner estimator tagged@fprop @vprop,wtagged@wprop, andwindow, each with its livefield_dictlookup, and the inner constructor that validateswandwindow. - Build
kwctor, the keyword constructor, whose defaults aredefault,nothingandnothing. - Write the type's docstring with
windowed_type_doc, and attach it tostructexprwrapped in@propagatable @concrete. - Return the escaped block: the documented struct,
kwctor, the forwarding methods, and theexportofname.
Validation
- The header reads
Name <: Super, andNameis aSymbol. - The declaration body is a
begin ... endblock, and every line of it is an assignment. - At most one
field::Type = defaultline appears. - Every other key names an entry of
WINDOWED_ESTIMATOR_KEYS. An unknown key raises with awindowed_estimator_suggestsuffix. - All four of
field::Type = default,noun,forwardanddoctestare present. nounanddoctestare string literals.forwardis a vector, and it declares at least one generic.- Every failure above raises an
ArgumentErrorthroughwindowed_estimator_error, at macro-expansion time.
Returns
ex::Expr: The escaped block that declares the whole family member.
Examples
@windowed_estimator WindowedVariance <: AbstractVarianceEstimator begin ve::AbstractVarianceEstimator = SimpleVariance() noun = "Variance" forward = [Statistics.var(::MatNum; mean) => :vararr, Statistics.var(::VecNum; mean) => :varnum] doctest = """ julia> WindowedVariance() ... """endRelated
PortfolioOptimisers.windowed_parse_field — Function
windowed_parse_field(ex) -> Tuple{Symbol, Any, Any}
Parse the field::Type = default line of a @windowed_estimator body into the inner estimator's field name, its declared type, and its keyword-constructor default.
The field name doubles as the field_dict key for the generated field docstring and as the argument name of every generated forwarding method, so it must follow the library's naming convention (me, ce, ve, ske, kte).
Algorithm
- Read the field name and its declared type from the left of the
=, givingnameandtype. - Check
nameagainstfield_dictwithwindowed_estimator_check_key. - Return
name,type, and the right of the=, which is the keyword-constructor default.
Arguments
ex: The onefield::Type = defaultline of the declaration body.
Validation
exreadsfield::Type = default. Any other shape raises.- The field name is a
Symbol. Any other name raises. - The field name names an entry of
field_dict.
Returns
(name, type, default): The field name, its declared type, and its keyword-constructor default.
Related
PortfolioOptimisers.windowed_parse_forward — Function
windowed_parse_forward(
ex
) -> Tuple{Any, Any, Bool, Vector{Symbol}}
Parse one forward entry of a @windowed_estimator body — generic(::MatNum; mean) => :ret_key — into the generic being forwarded, its input type, whether it names a mean keyword, and the ret_dict keys documenting its return values.
Naming mean in the mini-signature is what keeps it out of the forwarded kwargs..., where it would otherwise leak into windowed_preamble.
Algorithm
- Split
exat the=>, giving the mini-signaturesigand the return keysrets. - Read the forwarded generic from the head of
sig, givinggen. - Walk the arguments of
sig. Ameankeyword setshas_mean. The one positional argument type setsinput. - Check
inputagainstWINDOWED_ESTIMATOR_INPUTS. - Check every entry of
retsagainstret_dictwithwindowed_estimator_check_key, collecting them intokeys_. - Return
gen,input,has_meanandkeys_.
Arguments
ex: One entry of theforwardvector of the declaration body.
Validation
exreadsgeneric(::Input[; mean]) => :ret_key, or=> (:k1, :k2)for a tuple return. Any other shape raises.- The left of the
=>is a call. meanis the only keyword the mini-signature may name.- The mini-signature declares exactly one positional argument type.
- That type names an entry of
WINDOWED_ESTIMATOR_INPUTS. - Every return key is a quoted symbol, and names an entry of
ret_dict.
Returns
(gen, input, has_mean, keys_): The forwarded generic, its input type, whether the mini-signature namesmean, and theret_dictkeys of its return values.
Related
PortfolioOptimisers.windowed_estimator_check_key — Function
windowed_estimator_check_key(
key::Symbol,
dict::AbstractDict,
what::AbstractString
) -> Symbol
Validate that key names an entry of dict, appending a did_you_mean suggestion to the error when it does not. what names the table in the message.
Arguments
key::Symbol: The key the declaration wrote.dict::AbstractDict: The table the key must name an entry of.what::AbstractString: Name of that table, written into the message.
Validation
haskey(dict, key). A key that names no entry raises throughwindowed_estimator_error, with awindowed_estimator_suggestsuffix appended.
Returns
key::Symbol: The key, unchanged, so a caller can check and bind in one expression.
Related
PortfolioOptimisers.windowed_estimator_suggest — Function
windowed_estimator_suggest(key, candidates) -> String
Suggest the nearest candidates entry to a mistyped @windowed_estimator key.
Delegates to suggest_declared_key, which holds the looser scoped configuration every declaration-key suggestion shares: Damerau-Levenshtein at min_score = 0.5, because the candidates here are compile-time constants — block keys and field_dict/ret_dict names — with nothing to leak.
Arguments
key: The mistyped key.candidates: The keys the declaration accepts.
Returns
msg::String: The suggestion suffix, ready to append to a message, and empty when no candidate scores high enough.
Related
PortfolioOptimisers.windowed_estimator_error — Function
windowed_estimator_error(msg::AbstractString)
Throw a uniform, expansion-time ArgumentError for a malformed @windowed_estimator declaration.
Arguments
msg::AbstractString: Body of the message. The function prefixes it with@windowed_estimator:, so every message of the macro reads alike.
Validation
- The function always raises, so it never returns to its caller.
Related
PortfolioOptimisers.windowed_type_doc — Function
windowed_type_doc(
name::Symbol,
super,
field::Symbol,
ftype,
default,
noun::AbstractString,
doctest::AbstractString,
methods::Vector{String}
) -> Expr
Build the type docstring of a generated windowed estimator as an interpolation AST, keeping DocStringExtensions abbreviations and dictionary lookups live (see windowed_method_doc).
Algorithm
- Read the inner estimator's own name out of
default, givinginner_ref. A call such asSimpleVariance()contributes its head; a bare name contributes itself. - Open
partswith the liveDocStringExtensions.TYPEDEFabbreviation, the two summary sentences, the# Fieldsheading, and the liveDocStringExtensions.FIELDSabbreviation. - Push the
# Constructorssection, the keyword signature built fromname,field,ftypeanddefault, and the## Validationsubsection carrying the liveval_dict[:oow]lookup and the window rule. - Push the three propagation subsections,
## Propagated parameters,## View parametersand## Observation weight parameters, each namingfieldandwas the tags on the generated struct declare them. - Push the
# Examplessection, fencingdoctestas ajldoctestblock. - Push the
# Relatedheading, the supertype,inner_ref, every entry ofmethods, and the four seam functions the type answers. - Return
partswrapped inExpr(:string, ...), so every lookup stays live.
Arguments
name::Symbol: Name of the windowed estimator type.super: Its supertype.field::Symbol: Name of the inner estimator's field.ftype: Declared type of that field.default: Its keyword-constructor default.noun::AbstractString: Capitalised noun phrase naming the moment, which drives the generated prose.doctest::AbstractString: Body of thejldoctestblock of the# Examplessection, without its fences.methods::Vector{String}: Cross-references to the type's generated methods, fromwindowed_method_ref.
Returns
doc::Expr: AnExpr(:string, ...)holding the docstring, with every abbreviation and lookup left unevaluated.
Related
PortfolioOptimisers.windowed_method_ref — Function
windowed_method_ref(
gen,
field::Symbol,
name::Symbol,
input::Symbol
) -> String
Render the generic(field::Name, X::Input) reference used to cross-link one generated forwarding method from the type's and its siblings' # Related sections.
Keyword arguments are deliberately omitted: Documenter resolves an @ref by positional method signature, and the two positional types already identify the method uniquely.
Arguments
gen: The forwarded generic.field::Symbol: Name of the inner estimator's field, which is also the argument name of the generated method.name::Symbol: Name of the windowed estimator type.input::Symbol: Input type of the generated method,:MatNumor:VecNum.
Returns
ref::String: A Documenter cross-reference to the generated method. It links the code spangen(field::Name, X::Input)to that method.
Related
PortfolioOptimisers.windowed_method_doc — Function
windowed_method_doc(
gen,
field::Symbol,
name::Symbol,
input::Symbol,
has_mean::Bool,
ret_keys::Vector{Symbol},
noun::AbstractString,
siblings::Vector{String}
) -> Expr
Build the docstring for one generated forwarding method as an interpolation AST.
Returning Expr(:string, ...) rather than a String is load-bearing: it keeps arg_dict and ret_dict lookups as live parts of the DocStr, exactly as a hand-written $(arg_dict[:dims]) would be.
Algorithm
- Build the signature line
sigfromgen,field,nameandinput. The matrix signature carriesdims,ivandkwargs...; the vector signature carries neither.meanjoins either one whenhas_meanis set. - Open
partswithsig, the summary sentences, the two steps of the generated method's own algorithm, and the arguments heading with its two prose bullets. The summary names the generic and not the type's noun, becausestdon aWindowedVariancecomputes a standard deviation and not a variance. - For the matrix input, push the
arg_dict[:dims]lookup as a live expression. - When
has_meanis set, push themeanbullet. - For the matrix input, push the
arg_dict[:oiv]lookup and thekwargs...bullet. - Push the returns heading, then one live
ret_dictlookup per entry ofret_keys. - Push the related heading, the type, every entry of
siblings, andwindowed_preamble. - Return
partswrapped inExpr(:string, ...), so every lookup stays live.
Arguments
gen: The forwarded generic.field::Symbol: Name of the inner estimator's field, which is also the argument name of the generated method.name::Symbol: Name of the windowed estimator type.input::Symbol: Input type of the generated method,:MatNumor:VecNum.has_mean::Bool: Whether the method declares ameankeyword.ret_keys::Vector{Symbol}: Theret_dictkeys documenting the return values.noun::AbstractString: Capitalised noun phrase naming the moment, which drives the generated prose.siblings::Vector{String}: Cross-references to the type's other generated methods, fromwindowed_method_ref.
Returns
doc::Expr: AnExpr(:string, ...)holding the docstring, with every dictionary lookup left unevaluated.
Related
PortfolioOptimisers.windowed_method_def — Function
windowed_method_def(
gen,
field::Symbol,
name::Symbol,
input::Symbol,
has_mean::Bool
) -> Expr
Build one generated forwarding method: resolve the window via windowed_preamble, then delegate to the inner estimator's own method.
Algorithm
- Build the three field accesses the body reads:
field.field, the inner estimator;field.w, the observation weights; andfield.window, the window specification. - Build the keyword list of the signature. The matrix method takes
dims, thenmeanwhenhas_meanis set, thenivandkwargs.... The vector method takesmeanalone, and only whenhas_meanis set. - Build the matching keyword list of the delegated call. It carries the same names, each forwarded by value, and the
ivit forwards is the windowed one. - Build the body: one call to
windowed_preamblethat bindsinnerand the windowedX, andivtoo for the matrix method, then areturnofgenapplied toinnerand thatX. - Return the whole
Expr(:function, ...).
Arguments
gen: The forwarded generic.field::Symbol: Name of the inner estimator's field, which is also the argument name of the generated method.name::Symbol: Name of the windowed estimator type.input::Symbol: Input type of the generated method,:MatNumor:VecNum.has_mean::Bool: Whether the method declares ameankeyword.
Returns
def::Expr: TheExpr(:function, ...)of the forwarding method.
Related
FullMoment and semi moments
Moments other than the expected return can be estimated using the entire spectrum of deviations (full), or only the deviations below a target (semi/downside). These types allow us to provide such functionality.
PortfolioOptimisers.coverage_comoment_deviations — Function
coverage_comoment_deviations(alg::FullMoment, Xo::MatNum, mu::VecNum) -> MatNum
coverage_comoment_deviations(alg::SemiMoment, Xo::MatNum, mu::VecNum) -> MatNumCentres an available-case block on each asset's own mean, and clips the deviations where the moment algorithm asks for it.
The one line the two arms of a higher-order available-case fit differ in, taken out so that coverage_comoment_block is one body. FullMoment keeps the deviations whole and SemiMoment clips every positive one to zero, which is the same asymmetry the plain path already has.
Arguments
alg: Moment algorithm of the estimator.Xo: The oriented block,observations × assets, whose invalid entries are still non-finite.mu: Each asset's available-case mean, over its own finite and active observations.
Returns
Y::MatNum: The deviations, non-finite whereverXois.
Related
PortfolioOptimisers.coverage_comoment_block — Function
coverage_comoment_block(
alg::AbstractMomentAlgorithm,
cvg::CoveragePolicy,
X::AbstractMatrix{<:Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}},
active_mask::Union{Nothing, AbstractMatrix{<:Bool}},
dims::Int64
) -> Tuple{Any, Any, Any, Any, Any, Union{Nothing, BitVector}}
Builds the pairwise expansions and the admission mask a higher-order available-case fit reads.
The block half of the available-case arm, shared by coverage_coskewness and coverage_cokurtosis. A third and a fourth co-moment differ in which pair of expansions they multiply, and in nothing else, so this returns both expansions and lets each order take its own product. Neither order folds, so the block is seen whole and there is no state.
The deviations are centred on each asset's own available-case mean and the invalid entries are then zeroed, so an observation at which an asset has no quote contributes to neither the numerator nor the denominator of any cell that asset appears in. The mask expansion zc is the same product over the mask, so the denominator of a cell is the count of observations at which every asset of that cell is valid.
Algorithm
- Read the valid entries, the per-asset available-case mean and the per-asset bookkeeping of the block with
coverage_valid_block. - Centre and clip the block with
coverage_comoment_deviations, and zero the invalid entries. - Take the valid mask as integers,
Mi. - Build the pairwise expansions
zof the deviations andzcof the mask, bothobservations × assets². - Admit the assets with
coverage_admission, against each asset's own observation count.
Arguments
alg: Moment algorithm of the estimator.cvg: The policy the estimator carries.X: Data matrix.active_mask: The active mask of the Asset Panel over the window, ornothing.dims: Dimension along which to perform the computation.
Returns
(Xo, Y, Mi, z, zc, cmsk)::Tuple: The oriented block, the zeroed deviations, the valid mask as integers, the pairwise expansion of each, and the admitted assets ornothing.
Related