Factor attribution realised methods: private API
PortfolioOptimisers.attribution_net_returns — Function
attribution_net_returns(w::VecNum, X::MatNum, fees::Option{<:Fees}, strict::Bool,
amsk::Option{<:AbstractMatrix{Bool}} = nothing)Return the net portfolio return series over the finite entries of the asset returns.
A point-in-time panel carries a NaN at every (observation, asset) pair where the asset is inactive: before it lists, after it delists, and at a non-investable asset's whole column. 0 * NaN is NaN, so a zero weight does not remove a NaN from the product X * w. The series is therefore formed over the finite entries.
A pair with a zero weight contributes nothing whatever it holds, and no message names it. A pair with a non-zero weight and a non-finite return splits by the active mask amsk. An active pair is a holiday: the asset is listed and its price does not move, so its return is exactly zero, and the pair fills zero with no message. An inactive pair is a holding with no return to earn. After a delisting its return can be as low as -100 %, so a zero there is an assumption the caller must see, and the pair takes the library's strictness policy through strict_diagnostic. By default a warning names the observations and the assets, and the pair contributes zero. Under strict, an ArgumentError names them instead. Without a mask no pair is known to be a holiday, so every held pair with a non-finite return takes the policy. Under a walk-forward the held pairs after a delisting carry a zero weight already, so the default is silent there.
Mathematical definition
\[\begin{align} \tilde{x}_{ti} &= \begin{cases} x_{ti} & x_{ti} \text{ finite}\,, \\ 0 & \text{otherwise}\,. \end{cases} \end{align}\]
The series is the net series calc_net_returns forms from $\tilde{\mathbf{X}}$ and $\boldsymbol{w}$. A panel with no non-finite entry gives $\tilde{\mathbf{X}} = \mathbf{X}$.
Where:
- $x_{ti}$, $\tilde{x}_{ti}$: Return of asset $i$ at observation $t$, and its finite part, the entries of $\mathbf{X}$ and $\tilde{\mathbf{X}}$.
- $\boldsymbol{w}$: Portfolio weights vector $N \times 1$.
Arguments
w: Portfolio weights.X: Asset returns,observations × assets.fees: Fees the net series is formed against, ornothing.strict: Whether a non-finite return at an inactive held pair raises rather than warns.amsk: The active mask of the asset returns,observations × assets, ornothingwhen the returns carry none.
Validation
- Every inactive held pair of
Xis finite, else a warning naming the pairs is emitted, or anArgumentErrornaming them is raised understrict. Without a mask the rule reads every held pair.
Returns
ret::VecNum: The net portfolio return series, one entry per observation.
Related
PortfolioOptimisers.attribution_active_mask — Function
attribution_active_mask(pnl::Nothing)
attribution_active_mask(pnl::AssetPanel)Return the active mask a realised attribution reads off the Asset Panel of the returns data, or nothing.
A returns result without a panel states no mask, so no blank cell of it is known to be a holiday. A static panel puts every asset in its universe at every observation, so every cell of it is active, through panel_active_cells.
Arguments
pnl: The Asset Panel of the returns data, ornothing.
Returns
amsk::Option{<:AbstractMatrix{Bool}}: The active cells,observations × assets, ornothing.
Related
PortfolioOptimisers.attribution_returns_entry — Function
attribution_returns_entry(w::VecNum, pr::AbstractPriorResult, X::MatNum,
amsk::Option{<:AbstractMatrix{Bool}}, fees::Option{<:Fees},
args...; strict::Bool = false, kwargs...)Form the net return series of constant weights over an asset return matrix, then attribute it.
Every realised method of factor_attribution that takes constant weights and asset returns calls this function. A bare matrix carries no active mask, and a returns result carries the mask of its Asset Panel, so each reaches attribution_net_returns with the rule it can state.
Algorithm
- Refuse weights over another universe through
assert_attribution_assets. - Form the net series with
attribution_net_returns. - Decompose the series with
attribution_realised_entry, or roll it withattribution_rolling_entrywhenargsholds the window.
Arguments
w: Portfolio weights.pr: Prior result carrying the factor model block.X: Asset returns,observations × assets.amsk: The active mask of the asset returns, ornothing.fees: Fees the net series is formed against, ornothing.args: The positionalwindowof a rolling attribution, or nothing.strict: Whether a held non-investable asset, or a non-finite return at an inactive held pair, raises rather than warns.kwargs: The keywords of the entry function.
Validation
- The weights hold one entry for each asset of
pr, else aDimensionMismatchis raised. - The rules of
attribution_net_returns, and of the entry function.
Returns
fa: The attribution, or one attribution per window.
Related
PortfolioOptimisers.attribution_array_keywords — Function
attribution_array_keywords(kwargs) -> NamedTupleSplit the keywords of a realised bare-array method into those of the block and those of the decomposition.
The block keywords describe the arrays, and attribution_array_block takes them. Every other keyword goes to attribution_realised_entry or attribution_rolling_entry, whose keyword list is closed, so a misspelt keyword is refused there by name.
Arguments
kwargs: The keywords the caller passed.
Returns
kw::NamedTuple: The block keywordsblk, amonglag,trim,rw,vs,fcb,unseen,observed,fam,h1anddc, and the other keywordsentry.
Related
PortfolioOptimisers.attribution_prediction_history — Function
attribution_prediction_history(pred::MultiPeriodPredictionResult)Return the weight history and the net return series a cross-validation produced.
Each fold holds its own weights and its own net series, so the history is the folds stacked in order. A fold that recorded a Held Weights result carries its drifted path, and a fold that recorded none held its target weights for the whole fold.
Arguments
pred: A multi-period prediction result.
Returns
W::MatNum: The weight history,observations × assets.ret::VecNum: The net portfolio return series.
Related
PortfolioOptimisers.attribution_fold_weights — Function
attribution_fold_weights(pred::PredictionResult)Return the weight history one fold of a cross-validation held.
A fold that recorded a Held Weights result returns its drifted path, and a fold that recorded none held its target weights over every observation of the fold.
Arguments
pred: A single-fold prediction result.
Returns
W::MatNum: The fold's weight history,observations × assets.
Related
PortfolioOptimisers.attribution_fold_returns — Function
attribution_fold_returns(pred::PredictionResult)Return the net return series one fold of a cross-validation produced.
Arguments
pred: A single-fold prediction result.
Returns
ret::VecNum: The fold's net portfolio return series.
Related
PortfolioOptimisers.attribution_unknown_kinds — Function
attribution_unknown_kinds(rule::AbstractUnknownEntryRule) -> NamedTuple
attribution_unknown_kinds(rule::KindwiseUnknown) -> NamedTupleReturn the rule of each kind of unknown entry.
A preset applies to every kind, so it is the rule of each kind. KindwiseUnknown holds the rule of each kind in a field.
Arguments
rule: The rule for an unknown entry.
Returns
kinds::NamedTuple: The ruleunstatedfor an entry the model does not state, and the ruleleveragefor the variance split of a Leverage-One Pair.
Related
PortfolioOptimisers.attribution_block_arrays — Function
attribution_block_arrays(rr::AbstractLoadingsRegressionResult, pr::AbstractPriorResult)
-> NamedTupleReturn a factor model block as the bare arrays a realised attribution reads.
The block states its histories through the reads of factor_attribution, and this function takes each of them once, so a prior method and the bare-array method hand attribution_align the same fields.
Arguments
rr: The factor model block.pr: The prior result the block travels on, which carries the two return series of a block that stores none.
Returns
blk::NamedTuple: The fieldsB,f,eps,lag,rw,vs,fcb,unseen,noandfam, fromattribution_exposures,attribution_factor_returns,attribution_idiosyncratic_returns,attribution_lag,attribution_regression_weights,attribution_idiosyncratic_variances,attribution_family_basis,attribution_unseen_rule,attribution_observed_countandattribution_families, and the fieldsidxandtsofattribution_row_key.
Related
PortfolioOptimisers.attribution_leverage_marks — Function
attribution_leverage_marks(rr::AbstractLoadingsRegressionResult) -> Nothing
attribution_leverage_marks(rr::CrossSectionalFactorModel) -> Option{<:AbstractMatrix{Bool}}Return the leverage-one mask of a factor model block, or nothing.
The mask is the h1 field of the cross-sectional fit, observations × assets, on the rows of the idiosyncratic returns. A block that is not cross-sectional fits no design across the assets, so it marks no pair.
Arguments
rr: The factor model block.
Returns
h1::Option{<:AbstractMatrix{Bool}}: The leverage-one mask, ornothingwhen the block states none.
Related
PortfolioOptimisers.attribution_dropped_columns — Function
attribution_dropped_columns(rr::AbstractLoadingsRegressionResult) -> Nothing
attribution_dropped_columns(rr::CrossSectionalFactorModel) -> Option{<:AbstractMatrix{Bool}}Return the dropped-column mask of a factor model block, or nothing.
The mask is the dc field of the cross-sectional fit, observations × estimated factors, on the rows of the idiosyncratic returns. A block that is not cross-sectional fits no design across the assets, so it drops no column.
Arguments
rr: The factor model block.
Returns
dc::Option{<:AbstractMatrix{Bool}}: The dropped-column mask, ornothingwhen the block states none.
Related
PortfolioOptimisers.attribution_marked_assets — Function
attribution_marked_assets(h1::Nothing) -> Nothing
attribution_marked_assets(h1::AbstractMatrix{Bool}) -> BitVectorReturn the assets that the leverage-one mask marks at one row or more.
The predicted side reads one set of loadings and the moments of the whole fit. The factor covariance reads the factor returns of every row, and the factor return of a row where an asset is a Leverage-One Pair holds the own return of that asset. So the predicted split of an asset is not identified when the mask marks it at any row.
Arguments
h1: The leverage-one mask,observations × assets, ornothing.
Returns
lev::Option{<:BitVector}:trueat every asset the mask marks at one row or more, ornothing.
Related
PortfolioOptimisers.attribution_sole_factors! — Function
attribution_sole_factors!(fac::AbstractVector{Bool}, Bt::MatNum, i::Integer)Mark every factor whose only member is asset i.
A member of a factor is an asset with a finite exposure to it that is not zero. A Leverage-One Pair of a one-hot family is the only member of its level, so the factor return of the level holds the own return of the asset.
Arguments
fac: The factor mask, changed in place.Bt: Exposures of one row,assets × factors.i: The asset.
Returns
fac::AbstractVector{Bool}: The factor mask.
Related
PortfolioOptimisers.attribution_leverage_nan — Function
attribution_leverage_nan(lv::Nothing, x) -> x
attribution_leverage_nan(lv::NamedTuple, x::Nothing) -> Nothing
attribution_leverage_nan(lv::NamedTuple, c::AttributionComponent) -> AttributionComponent
attribution_leverage_nan(lv::NamedTuple, bd::AttributionBreakdown) -> AttributionBreakdown
attribution_leverage_nan(lv::NamedTuple, abd::AssetAttributionBreakdown)
-> AssetAttributionBreakdown
attribution_leverage_nan(lv::NamedTuple, afc::AssetFactorContribution)
-> AssetFactorContributionReturn a part of an attribution with NaN in every variance number that reads the split of a held Leverage-One Pair.
The total return of the pair is identified, and the split between its systematic and its idiosyncratic part is not. A component of the portfolio loses its volatility, its volatility contribution, its variance share and its correlation. A factor row that lv marks loses its volatility contribution, its variance share and its correlation, and keeps the standalone volatility of the factor. An asset row that lv marks loses its systematic and its idiosyncratic volatility contribution, and keeps its total. Every mean keeps its value, because the own return has an expected value of zero, so the mean split is unbiased. lv = nothing changes nothing.
Arguments
lv: The marks ofattribution_leverage_split, ornothing.x,c,bd,abd,afc: The part of the attribution, ornothingfor an axis the caller did not ask for.
Returns
- The part, with
NaNin the numbers that read the split.
Related
PortfolioOptimisers.attribution_mask_nan — Function
attribution_mask_nan(A::AbstractArray, m::AbstractArray{Bool}) -> AbstractArrayReturn A with NaN at every entry that m marks.
Each NaN takes the type of the entry it replaces.
Arguments
A: The numbers.m: The mask, the shape ofA.
Returns
B::AbstractArray: A copy ofAwithNaNat the marked entries.
Related
PortfolioOptimisers.attribution_error_pass — Function
attribution_error_pass(s2::AbstractMatrix, g::MatNum, al::NamedTuple, red::NamedTuple,
fam::Option{<:VecStr}, s1::Number) -> NamedTupleReturn the standard errors of the mean return contributions for one matrix of idiosyncratic variances.
The sandwich of each observation reads s2, and the function sums it over the observations through the portfolio exposure. attribution_standard_errors calls it with the variances of the regression pairs. attribution_leverage_errors calls it with an indicator in place of the variances, so one reduction gives the answer and the weight that each output puts on a set of pairs. At an observation with an Unseen Member, attribution_changed_covariance maps the sandwich of the changed design to the covariance of the factor returns. At an observation where DependentColumnDrop dropped a column, attribution_dropped_observation takes the sandwich on the kept columns, so a dropped factor has no estimation error.
Arguments
s2: The idiosyncratic variance of each pair,observations × assets, zero outside the regression.g: The per-observation portfolio exposure on the raw axis,observations × factors.al: The aligned factor model history, with the regression weightsrw.red: The regression basis and the changesPof the observations with an Unseen Member, fromattribution_reduce_for_errors.fam: The family label of each raw factor, ornothing.s1: The factor a mean takes under the annualisation.
Returns
sys::Real: The standard error of the systematic mean return contribution.factor::VecNum: The standard error of each factor's,NaNfor an observed factor.family::Option{<:VecNum}: The standard error of each family's, ornothing.
Related
PortfolioOptimisers.attribution_leverage_error_nan — Function
attribution_leverage_error_nan(x::Nothing, l::Nothing, s::Nothing) -> Nothing
attribution_leverage_error_nan(x::Number, l::Number, s::Number) -> Number
attribution_leverage_error_nan(x::AbstractVector, l::AbstractVector, s::AbstractVector)
-> AbstractVectorReturn a standard error, or NaN when its leverage index exceeds $\varepsilon$ times its scale.
The two indicator passes of attribution_leverage_errors return standard errors, which are the square roots of the two sums, so the test compares their squares. An output that the attribution states as NaN already, an observed factor for example, stays NaN. A family axis that the attribution does not have stays nothing.
Arguments
x: The standard error.l: The standard error of the indicator of the marked pairs.s: The standard error of the indicator of every regression pair.
Returns
x: The standard error, orNaN.
Related
PortfolioOptimisers.attribution_unknown_rows — Function
attribution_unknown_rows(A::AbstractArray, keep::AbstractVector{Bool})Return the loadings, the intercept or the expected returns with every unknown entry outside the kept assets replaced by zero.
A finite entry stays as it is, so a held non-investable asset keeps its finite loadings, and the exposures that read them are exact. A non-finite entry of a kept asset stays too, so every number that reads it is NaN.
Mathematical definition
\[\begin{align} \tilde{A}_{ik} &= \begin{cases} A_{ik} & \text{if } A_{ik} \text{ is finite or } k_{i} = 1\,, \\ 0 & \text{otherwise}\,. \end{cases} \end{align}\]
Where:
- $A_{ik}$, $\tilde{A}_{ik}$: Entry of asset $i$ in column $k$, before and after the rule. A vector has one column.
- $k_{i}$: Whether asset $i$ keeps its unknown entries, from
attribution_unknown_keep.
Arguments
A: The loadings,assets × factors, or a vector with one entry per asset.keep: Whether each asset keeps its unknown entries.
Returns
A::AbstractArray: The array after the rule.
Related
PortfolioOptimisers.attribution_unknown_block — Function
attribution_unknown_block(E::VecNum_MatNum, keep::AbstractVector{Bool})Return the idiosyncratic covariance with every unknown entry outside the kept pairs replaced by zero.
The covariance sibling of attribution_unknown_rows. A diagonal covariance travels as a vector, and takes the rule of the rows. A full covariance keeps an unknown entry only when both of its assets keep their unknown entries, because the quadratic form w' E w reads the entry (i, j) with the weight w_i w_j.
Mathematical definition
\[\begin{align} \tilde{E}_{ij} &= \begin{cases} E_{ij} & \text{if } E_{ij} \text{ is finite, or } k_{i} = k_{j} = 1\,, \\ 0 & \text{otherwise}\,. \end{cases} \end{align}\]
Where:
- $E_{ij}$, $\tilde{E}_{ij}$: Idiosyncratic covariance of assets $i$ and $j$, before and after the rule.
- $k_{i}$: Whether asset $i$ keeps its unknown entries, from
attribution_unknown_keep.
Arguments
E: The idiosyncratic variances, one entry per asset, or the idiosyncratic covariance,assets × assets.keep: Whether each asset keeps its unknown entries.
Returns
E::VecNum_MatNum: The variances or the covariance after the rule.
Related
PortfolioOptimisers.attribution_held_entries — Function
attribution_held_entries(X::AbstractArray, w::VecNum)Return a per-asset contribution with every non-finite entry of an asset the portfolio does not hold replaced by zero.
A contribution of asset i is its weight times a number of the model, divided by the portfolio volatility where it is a share. An asset with a weight of zero contributes zero whatever that number is, because the number is finite in the model even where the attribution cannot state it. A held asset whose unknown entry reaches the number keeps its NaN. A finite entry stays as it is, so the sign of a zero is kept.
Mathematical definition
\[\begin{align} \tilde{x}_{ik} &= \begin{cases} 0 & \text{if } w_{i} = 0 \text{ and } x_{ik} \text{ is not finite}\,, \\ x_{ik} & \text{otherwise}\,. \end{cases} \end{align}\]
Where:
- $x_{ik}$, $\tilde{x}_{ik}$: Contribution of asset $i$ in column $k$, before and after the rule. A vector has one column.
- $\boldsymbol{w}$: Portfolio weights vector $N \times 1$.
Arguments
X: The contributions, one row per asset.w: Portfolio weights.
Returns
X::AbstractArray: The contributions after the rule.
Related