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, or nothing.
  • 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, or nothing when the returns carry none.

Validation

  • Every inactive held pair of X is finite, else a warning naming the pairs is emitted, or an ArgumentError naming them is raised under strict. Without a mask the rule reads every held pair.

Returns

  • ret::VecNum: The net portfolio return series, one entry per observation.

Related

source
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, or nothing.

Returns

  • amsk::Option{<:AbstractMatrix{Bool}}: The active cells, observations × assets, or nothing.

Related

source
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

  1. Refuse weights over another universe through assert_attribution_assets.
  2. Form the net series with attribution_net_returns.
  3. Decompose the series with attribution_realised_entry, or roll it with attribution_rolling_entry when args holds 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, or nothing.
  • fees: Fees the net series is formed against, or nothing.
  • args: The positional window of 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 a DimensionMismatch is raised.
  • The rules of attribution_net_returns, and of the entry function.

Returns

  • fa: The attribution, or one attribution per window.

Related

source
PortfolioOptimisers.attribution_array_keywords — Function
attribution_array_keywords(kwargs) -> NamedTuple

Split 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 keywords blk, among lag, trim, rw, vs, fcb, unseen, observed, fam, h1 and dc, and the other keywords entry.

Related

source
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

source
PortfolioOptimisers.attribution_unknown_kinds — Function
attribution_unknown_kinds(rule::AbstractUnknownEntryRule) -> NamedTuple
attribution_unknown_kinds(rule::KindwiseUnknown) -> NamedTuple

Return 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 rule unstated for an entry the model does not state, and the rule leverage for the variance split of a Leverage-One Pair.

Related

source
PortfolioOptimisers.attribution_block_arrays — Function
attribution_block_arrays(rr::AbstractLoadingsRegressionResult, pr::AbstractPriorResult)
    -> NamedTuple

Return 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

Related

source
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, or nothing when the block states none.

Related

source
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, or nothing when the block states none.

Related

source
PortfolioOptimisers.attribution_marked_assets — Function
attribution_marked_assets(h1::Nothing) -> Nothing
attribution_marked_assets(h1::AbstractMatrix{Bool}) -> BitVector

Return 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, or nothing.

Returns

  • lev::Option{<:BitVector}: true at every asset the mask marks at one row or more, or nothing.

Related

source
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

source
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)
    -> AssetFactorContribution

Return 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 of attribution_leverage_split, or nothing.
  • x, c, bd, abd, afc: The part of the attribution, or nothing for an axis the caller did not ask for.

Returns

  • The part, with NaN in the numbers that read the split.

Related

source
PortfolioOptimisers.attribution_mask_nan — Function
attribution_mask_nan(A::AbstractArray, m::AbstractArray{Bool}) -> AbstractArray

Return 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 of A.

Returns

  • B::AbstractArray: A copy of A with NaN at the marked entries.

Related

source
PortfolioOptimisers.attribution_error_pass — Function
attribution_error_pass(s2::AbstractMatrix, g::MatNum, al::NamedTuple, red::NamedTuple,
                       fam::Option{<:VecStr}, s1::Number) -> NamedTuple

Return 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 weights rw.
  • red: The regression basis and the changes P of the observations with an Unseen Member, from attribution_reduce_for_errors.
  • fam: The family label of each raw factor, or nothing.
  • 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, NaN for an observed factor.
  • family::Option{<:VecNum}: The standard error of each family's, or nothing.

Related

source
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)
    -> AbstractVector

Return 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, or NaN.

Related

source
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

source
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

source
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

source