Cross-Sectional Exposure Diagnostics
Functions
PortfolioOptimisers.exposure_correlation — Function
exposure_correlation(B::Arr3Num, w::Option{<:MatNum} = nothing) -> Matrix{<:Real}
exposure_correlation(csfm::CrossSectionalFactorModel;
weighting::AbstractOrthogonalityMetric = BenchmarkWeightMetric()) -> Matrix{<:Real}Return the time-averaged correlation between every pair of factor exposures.
Two exposures that correlate across the assets carry the same reading of the cross-section, so the pair is redundant and the design of the fit is collinear. This answer is the cross-sectional counterpart of the variance inflation factor, which reads the same collinearity off the design of one observation.
Each pair is correlated over the assets at which both exposures are finite, one observation at a time, and the answers are then averaged over the observations at which the pair is defined. A pair one of whose exposures is constant across the assets has no correlation, and it reads 0 by convention. A pair that never shares three finite assets reads NaN. The diagonal is 1.
The level-2 method answers on the raw factor axis, because the exposure history is the reading of the panel and not the design of the fit, and it reads the unlagged history.
Mathematical definition
\[\mathbf{C}_{kl} = \frac{1}{|\mathcal{T}_{kl}|} \sum_{t \in \mathcal{T}_{kl}} \rho \left( \mathbf{B}_{t \cdot k}, \mathbf{B}_{t \cdot l}, \boldsymbol{u}_{t} \right)\]
Where:
- $\mathbf{B}_{t \cdot k}$: Cross-section of factor $k$ at observation $t$.
- $\boldsymbol{u}_{t}$: Cross-sectional weights of observation $t$.
- $\rho$: The weighted correlation of two cross-sections.
- $\mathcal{T}_{kl}$: The observations at which the pair is defined.
Algorithm
- Resolve the weight history with
exposure_weights. - For each observation and each pair, accumulate the weighted sums over the assets at which both exposures are finite.
- Mark the pair as degenerate when either weighted variance falls to the tolerance of its own weighted square sum, and as insufficient when fewer than three assets are shared.
- Average the pairs that are neither over the observations. A pair that is degenerate at every observation it covers reads
0, and one that is never sufficient readsNaN. - Write
1on the diagonal.
Arguments
B: Exposure historyobservations × assets × factors, unlagged.w: Cross-sectional weight historyobservations × assets, ornothingfor equal weights.csfm: A cross-sectional factor model block.weighting: A member ofAbstractOrthogonalityMetric. It names the weight history the block is read with, andcs_diagnostic_weightsresolves it over the whole observation axis.
Validation
!isempty(B).size(w) == (size(B, 1), size(B, 2)), whenwis present.csfm.Msis notnothing, else anIsNothingErrornamingMsis raised.- The field
weightingnames is notnothing, else anIsNothingErrornaming it is raised.
Returns
C::Matrix{<:Real}:factors × factors, symmetric, with a diagonal of1.
Related
PortfolioOptimisers.exposure_ic — Function
exposure_ic(B::Arr3Num, R::MatNum, w::Option{<:MatNum} = nothing;
horizon::Integer = 1, rank::Bool = true) -> Matrix{<:Real}
exposure_ic(csfm::CrossSectionalFactorModel; horizon::Integer = 1, rank::Bool = true,
reduced::Bool = false) -> Matrix{<:Real}Return the information coefficient of every factor exposure, one row per pair of observations.
The information coefficient is the cross-sectional correlation between the exposure known at an observation and the mean asset return over the observations that follow it. It scores the exposure as a forecast of the return.
A risk factor with an information coefficient near zero is not a bad risk factor. A risk factor is built to explain the covariance and not to predict the mean, so read exposure_stability and the variance the factor contributes before you judge one, and never the information coefficient alone.
The level-2 method reconstructs the asset returns as $\mathbf{B}_{t-\ell} \boldsymbol{f}_{t} + \boldsymbol{\varepsilon}_{t}$, reads rw for the weights of the Pearson form, and answers on the raw factor axis. reduced maps the exposures through the family re-basis of the block first, and then the answer is on the reduced axis.
Mathematical definition
\[\mathrm{IC}_{tk} = \rho \left( \mathbf{B}_{t \cdot k}, \boldsymbol{y}_{t}, \boldsymbol{u}_{t} \right) \qquad y_{ti} = \frac{1}{H} \sum_{h=1}^{H} r_{t+h,i}\]
Where:
- $\mathbf{B}_{t \cdot k}$: Cross-section of factor $k$ at observation $t$.
- $\boldsymbol{y}_{t}$: Forward mean asset return of observation $t$.
- $\rho$: The rank correlation when
rank, and the weighted correlation otherwise. - $H$: Forward window, in observations.
Algorithm
- Resolve the weight history with
exposure_weights. - Build the forward mean return with
exposure_forward_mean_return. - Correlate each exposure against it, one observation at a time, with
cs_spearman_correlationwhenrankandcs_weighted_correlationotherwise.
Arguments
B: Exposure historyobservations × assets × factors, unlagged.R: Asset return historyobservations × assets, on the observation axis ofB.w: Cross-sectional weight historyobservations × assets, ornothingfor equal weights. The rank form reads no weights.horizon: Forward window, in observations.rank: Take the rank correlation whentrue, and the weighted correlation otherwise.csfm: A cross-sectional factor model block.reduced: Map the exposures through the family re-basis of the block before the correlation.
Validation
!isempty(B).size(R) == (size(B, 1), size(B, 2)).horizon >= 1andsize(B, 1) > horizon.csfm.Msandcsfm.csrare notnothing, else anIsNothingErrornaming the field is raised.
Returns
ic::Matrix{<:Real}:(observations - horizon) × factors. Rowtscores the exposures of observationtagainst the returns that follow it.
Related
PortfolioOptimisers.exposure_ic_summary — Function
exposure_ic_summary(ic::MatNum)
exposure_ic_summary(csfm::CrossSectionalFactorModel; horizon::Integer = 1,
rank::Bool = true, reduced::Bool = false)Return the summary of an information coefficient series, one entry per factor.
The mean states the average score, the standard deviation states how much the score moves, their ratio states the score per unit of movement, the t-statistic states whether the mean is far enough from zero to believe over the observations that carried a score, and the hit rate states how often the score was positive. All five are read against the observations that carried a score: an observation whose score is NaN is one at which nothing was measured, not a miss, so it is in no denominator here, as it is in none of the library's other summaries. Whether a series was silenced often is a separate question, and the coverage of the series answers it.
Mathematical definition
\[\overline{\mathrm{IC}}_{k} = \frac{1}{|\mathcal{T}_{k}|} \sum_{t \in \mathcal{T}_{k}} \mathrm{IC}_{tk} \qquad \mathrm{IR}_{k} = \frac{\overline{\mathrm{IC}}_{k}}{s_{k}} \qquad t_{k} = \mathrm{IR}_{k} \sqrt{\left| \mathcal{T}_{k} \right|} \qquad \mathrm{hit}_{k} = \frac{1}{|\mathcal{T}_{k}|} \sum_{t \in \mathcal{T}_{k}} \mathbb{1}\left[\mathrm{IC}_{tk} > 0\right]\]
Where:
- $\mathrm{IC}_{tk}$: Information coefficient of factor $k$ at observation $t$.
- $\mathcal{T}_{k}$: The observations at which it is finite.
- $s_{k}$: Its standard deviation over $\mathcal{T}_{k}$, with one degree of freedom removed.
Arguments
ic: Information coefficient seriespairs × factors.csfm: A cross-sectional factor model block.horizon: Forward window, in observations.rank: Take the rank correlation whentrue, and the weighted correlation otherwise.reduced: Map the exposures through the family re-basis of the block before the correlation.
Validation
!isempty(ic).
Returns
summary::NamedTuple:(; mean_ic, std_ic, ic_ir, t_stat, hit_rate), each one entry per factor.
Related
PortfolioOptimisers.exposure_stability — Function
exposure_stability(B::Arr3Num, w::Option{<:MatNum} = nothing;
step::Integer = 21) -> Matrix{<:Real}
exposure_stability(csfm::CrossSectionalFactorModel; step::Integer = 21,
weighting::AbstractOrthogonalityMetric = BenchmarkWeightMetric()) -> Matrix{<:Real}Return the stability of every factor exposure, one row per pair of observations.
The stability is the correlation of the cross-section of an exposure against its own cross-section step observations later. An exposure that ranks the assets the same way from one month to the next reads near 1, and one that re-orders them reads near 0. A risk factor needs a stable exposure, because a turnover of the exposure is a turnover of the portfolio that holds it.
The level-2 method answers on the raw factor axis, and it reads the unlagged history.
Mathematical definition
\[\mathrm{S}_{tk} = \rho \left( \mathbf{B}_{t \cdot k}, \mathbf{B}_{t + s, \cdot k}, \boldsymbol{u}_{t} \right)\]
Where:
- $\mathbf{B}_{t \cdot k}$: Cross-section of factor $k$ at observation $t$.
- $\boldsymbol{u}_{t}$: Cross-sectional weights of observation $t$, the earlier of the two.
- $\rho$: The weighted correlation of two cross-sections.
- $s$: Number of observations between the two cross-sections.
Arguments
B: Exposure historyobservations × assets × factors, unlagged.w: Cross-sectional weight historyobservations × assets, ornothingfor equal weights.step: Number of observations between the two cross-sections.csfm: A cross-sectional factor model block.weighting: A member ofAbstractOrthogonalityMetric. It names the weight history the block is read with, andcs_diagnostic_weightsresolves it over the whole observation axis.
Validation
!isempty(B).step >= 1andsize(B, 1) > step.csfm.Msis notnothing, else anIsNothingErrornamingMsis raised.
Returns
S::Matrix{<:Real}:(observations - step) × factors.
Related
PortfolioOptimisers.exposure_dispersion — Function
exposure_dispersion(B::Arr3Num, w::Option{<:MatNum} = nothing) -> Matrix{<:Real}
exposure_dispersion(csfm::CrossSectionalFactorModel;
weighting::AbstractOrthogonalityMetric = BenchmarkWeightMetric()) -> Matrix{<:Real}Return the weighted cross-sectional standard deviation of every factor exposure, one row per observation.
The level of the answer follows the standardisation the exposures were built under, so read the series and not the level: a collapse is a data feed that stopped, and a jump is one asset that ran away. An observation at which the factor carries no weight reads NaN.
The level-2 method answers on the raw factor axis, and it reads the unlagged history.
Mathematical definition
\[\mathrm{D}_{tk} = \sqrt{\sum_{i} \tilde{u}_{tik} \left( B_{tik} - \sum_{j} \tilde{u}_{tjk} B_{tjk} \right)^{2}}\]
Where:
- $B_{tik}$: Exposure of asset $i$ to factor $k$ at observation $t$.
- $\tilde{u}_{tik}$: Weight of asset $i$, zero where the exposure is not finite, and normalised over the assets to sum to one.
Arguments
B: Exposure historyobservations × assets × factors, unlagged.w: Cross-sectional weight historyobservations × assets, ornothingfor equal weights.csfm: A cross-sectional factor model block.weighting: A member ofAbstractOrthogonalityMetric. It names the weight history the block is read with, andcs_diagnostic_weightsresolves it over the whole observation axis.
Validation
!isempty(B).csfm.Msis notnothing, else anIsNothingErrornamingMsis raised.
Returns
D::Matrix{<:Real}:observations × factors.
Related
PortfolioOptimisers.exposure_coverage — Function
exposure_coverage(B::Arr3Num, w::Option{<:MatNum} = nothing) -> Vector{<:Real}
exposure_coverage(csfm::CrossSectionalFactorModel;
weighting::AbstractOrthogonalityMetric = BenchmarkWeightMetric()) -> Vector{<:Real}Return the coverage of every factor exposure, one entry per factor.
The coverage is the share of the universe at which the exposure is finite, averaged over the observations. The universe of an observation is the assets that carry a positive weight, and it is every asset when no weight history is read. A factor whose coverage falls has lost its panel field on part of the universe, and the fit of that observation then rests on fewer assets than the caller believes.
The level-2 method answers on the raw factor axis, and it reads the unlagged history.
Mathematical definition
\[\mathrm{c}_{k} = \frac{1}{T} \sum_{t=1}^{T} \frac{\left| \left\{ i \in \mathcal{U}_{t} : B_{tik} \text{ is finite} \right\} \right|}{\left| \mathcal{U}_{t} \right|}\]
Where:
- $B_{tik}$: Exposure of asset $i$ to factor $k$ at observation $t$.
- $\mathcal{U}_{t}$: Universe of observation $t$, the assets of positive weight.
- $T$: Number of observations.
Arguments
B: Exposure historyobservations × assets × factors, unlagged.w: Cross-sectional weight historyobservations × assets, ornothingfor every asset.csfm: A cross-sectional factor model block.weighting: A member ofAbstractOrthogonalityMetric. It names the weight history the universe is read off, andcs_diagnostic_weightsresolves it over the whole observation axis.
Validation
!isempty(B).csfm.Msis notnothing, else anIsNothingErrornamingMsis raised.
Returns
c::Vector{<:Real}: One entry per factor, between0and1. An observation whose universe is empty contributes0.
Related