Cross-Sectional Exposure Diagnostics: private API
Functions
PortfolioOptimisers.exposure_weights — Function
exposure_weights(B::Arr3Num, w::Nothing)
exposure_weights(B::Arr3Num, w::MatNum)Return the cross-sectional weight history an exposure diagnostic reads, checking it against the exposure history.
Every diagnostic of this file weights the assets of one observation, and an absent weight history means equal weights. The absent case is resolved once, into a history of ones, so each kernel reads one matrix and no kernel carries a branch. A weight of zero excludes the asset from the observation, which is the same answer the history of ones gives when no asset is excluded.
Arguments
B: Exposure historyobservations × assets × factors, unlagged.w: Cross-sectional weight historyobservations × assets, ornothingfor equal weights.
Validation
!isempty(B).size(w) == (size(B, 1), size(B, 2)), whenwis present.- No finite entry of
wis negative.
Returns
u::MatNum: Weight historyobservations × assets. It is a history of ones whenwisnothing, andwitself otherwise.
Related
PortfolioOptimisers.cs_weighted_correlation — Function
cs_weighted_correlation(a::AbstractVector, b::AbstractVector, u::AbstractVector;
min_count::Integer = 3, eps::Real = 1e-12)Return the weighted correlation of two cross-sections of one observation.
It is the kernel of every diagnostic of this file that correlates two cross-sections: the information coefficient of an exposure against the forward return, and the stability of an exposure against its own later self. An asset enters when both of its values are finite and its weight is finite and positive, so a missing value costs the pair alone and not the observation.
Mathematical definition
\[\rho = \frac{\sum_{i} u_{i} (a_{i} - \bar{a}) (b_{i} - \bar{b})}{\sqrt{\sum_{i} u_{i} (a_{i} - \bar{a})^{2}} \sqrt{\sum_{i} u_{i} (b_{i} - \bar{b})^{2}}}\]
Where:
- $a_{i}$, $b_{i}$: The two values of asset $i$.
- $u_{i}$: Weight of asset $i$.
- $\bar{a} = \sum_{i} u_{i} a_{i} / \sum_{i} u_{i}$: Weighted mean of the first cross-section, and likewise $\bar{b}$.
Algorithm
- Count the assets that enter, and accumulate the weight sum and the two weighted means over them.
- Answer
NaNwhen fewer thanmin_countassets enter, or when the weight sum is zero. - Accumulate the weighted central moments over the same assets.
- Answer
NaNwhen the denominator is at or undereps, which is a cross-section that is constant in one of the two values.
Arguments
a: First cross-section, one entry per asset.b: Second cross-section, one entry per asset.u: Weight of each asset. An entry that is not finite, or not positive, excludes the asset.min_count: Least number of assets an answer needs.eps: Denominator at or under which the answer isNaN.
Returns
rho::Real: The correlation, orNaN.
Examples
julia> PortfolioOptimisers.cs_weighted_correlation([1.0, 2.0, 3.0], [2.0, 4.0, 6.0], ones(3))1.0Related
PortfolioOptimisers.cs_correlation_enters — Function
cs_correlation_enters(a::AbstractVector, b::AbstractVector, u::AbstractVector,
i::Integer)Return whether one asset enters the correlation of two cross-sections.
An asset enters when both of its values are finite and its weight is finite and positive. The two passes of cs_weighted_correlation read the same rule, so it is stated once.
Arguments
a: First cross-section, one entry per asset.b: Second cross-section, one entry per asset.u: Weight of each asset.i: Position of the asset.
Returns
enters::Bool:truewhen the asset enters.
Related
PortfolioOptimisers.cs_ordinal_ranks — Function
cs_ordinal_ranks(key::AbstractVector, valid::AbstractVector{Bool})Return the ordinal rank of every entry of a cross-section, and NaN outside a mask.
The rank is the position the entry takes in the sorted order, so two equal values take two different ranks, in the order of the asset axis. The masked entries are sorted to the end by their key and then written as NaN, so they take no rank and shift none.
Arguments
key: Sort key of each asset. The key of a masked asset must beInf, so the mask sorts to the end.valid: Mask, one entry per asset. Afalseentry getsNaN.
Returns
r::VecNum: Rank of each asset, orNaNoutside the mask.
Related
PortfolioOptimisers.cs_spearman_correlation — Function
cs_spearman_correlation(a::AbstractVector, b::AbstractVector;
min_count::Integer = 3, eps::Real = 1e-12)Return the rank correlation of two cross-sections of one observation.
It is the unweighted correlation of the ordinal ranks of the two cross-sections, taken over the assets at which both values are finite. The rank measures the order of the assets and not their level, so one extreme value moves the answer no more than one ordinary value does.
Algorithm
- Mark the assets at which both values are finite.
- Rank each cross-section over those assets with
cs_ordinal_ranks. - Correlate the two rank vectors with
cs_weighted_correlationunder equal weights.
Arguments
a: First cross-section, one entry per asset.b: Second cross-section, one entry per asset.min_count: Least number of assets an answer needs.eps: Denominator at or under which the answer isNaN.
Returns
rho::Real: The rank correlation, orNaN.
Related
PortfolioOptimisers.exposure_forward_mean_return — Function
exposure_forward_mean_return(R::MatNum, horizon::Integer)Return the forward mean asset return of every observation but the last horizon of them.
The information coefficient scores an exposure against what the asset earned after the exposure was known, and this verb builds that target. An observation whose forward window carries no finite return gets NaN, and a window that is part finite is averaged over the finite part alone.
Mathematical definition
\[y_{ti} = \frac{1}{|\mathcal{H}_{ti}|} \sum_{h \in \mathcal{H}_{ti}} r_{t+h,i}\]
Where:
- $r_{ti}$: Return of asset $i$ at observation $t$.
- $\mathcal{H}_{ti}$: The offsets $1 \le h \le H$ at which $r_{t+h,i}$ is finite.
- $H$: Forward window, in observations.
Arguments
R: Asset return historyobservations × assets.horizon: Forward window, in observations.
Validation
size(R, 1) > horizon.
Returns
y::MatNum: Forward mean return(observations - horizon) × assets. Rowtaverages the returns of observationst + 1tot + horizon.
Related
PortfolioOptimisers.exposure_pair_correlation — Function
exposure_pair_correlation(B::Arr3Num, u::MatNum, k::Integer, l::Integer)Return the time-averaged correlation of one pair of factor exposures.
The pair is correlated at each observation, and the answers are averaged over the observations at which the pair is defined. A pair that is degenerate at every observation it covers reads 0 by convention, and one that never reaches three common assets reads NaN.
Arguments
B: Exposure historyobservations × assets × factors, unlagged.u: Resolved weight historyobservations × assets.k,l: Positions of the two factors.
Returns
rho::Real: The time-averaged correlation,0by convention, orNaN.
Related
PortfolioOptimisers.exposure_pair_observation — Function
exposure_pair_observation(B::Arr3Num, u::MatNum, t::Integer, k::Integer, l::Integer)Return the correlation of one pair of factor exposures at one observation, and whether the pair is degenerate there.
The pair is correlated over the assets at which both exposures are finite. It has no answer at an observation that shares fewer than three such assets, and none at one where either weighted variance falls to the tolerance of its own weighted square sum. The second case is degenerate, which the caller reads as the 0 convention, and the first is not.
Arguments
B: Exposure historyobservations × assets × factors, unlagged.u: Resolved weight historyobservations × assets.t: Position of the observation.k,l: Positions of the two factors.
Returns
rho::Real: The correlation, orNaN.degenerate::Bool:truewhen the pair shares three assets and one of the two cross-sections is constant over them.
Related
PortfolioOptimisers.exposure_pair_sums — Function
exposure_pair_sums(B::Arr3Num, u::MatNum, t::Integer, k::Integer, l::Integer)Return the weighted sums of one pair of factor exposures over the assets they share at one observation.
An asset enters when both of its exposures are finite, so the support is the one the pair shares and not the one either factor holds alone. The six sums are what the correlation of the pair is a function of.
Arguments
B: Exposure historyobservations × assets × factors, unlagged.u: Resolved weight historyobservations × assets.t: Position of the observation.k,l: Positions of the two factors.
Returns
m::NamedTuple:(; nv, W, Sk, Sl, Qk, Ql, C), the count of the shared assets, the weight sum, the two weighted sums, the two weighted square sums and the weighted cross sum.
Related
PortfolioOptimisers.exposure_ic_factor_summary — Function
exposure_ic_factor_summary(ic::MatNum, k::Integer)Return the four summary numbers of one factor's information coefficient series.
The mean, the standard deviation and the hit rate read the observations at which the coefficient is defined, so an observation with no coefficient is in no denominator and the three agree on their sample; a series with no defined observation has no hit rate. The ratio has no answer where either of its two terms has none, and none where the standard deviation is zero. The t-statistic scales the ratio by the root of the number of observations that carried a coefficient, so it says whether the mean is far enough from zero to believe over the evidence there was; it inherits the ratio's absence.
It is the kernel of every summary of a per-observation correlation series, so forecast_ic_summary reads it too, and a coefficient of a factor exposure and a coefficient of a Return Forecast are summarised on the same terms.
Arguments
ic: Information coefficient seriespairs × factors.k: Position of the factor.
Returns
m::NamedTuple:(; mean_ic, std_ic, ic_ir, t_stat, hit_rate), five numbers.
Related
PortfolioOptimisers.exposure_cross_section_std — Function
exposure_cross_section_std(B::Arr3Num, u::MatNum, t::Integer, k::Integer)Return the weighted cross-sectional standard deviation of one factor exposure at one observation.
The weights are normalised over the assets at which the exposure is finite, so an absent exposure costs its own asset and no other. An observation at which the factor carries no weight has no answer.
Arguments
B: Exposure historyobservations × assets × factors, unlagged.u: Resolved weight historyobservations × assets.t: Position of the observation.k: Position of the factor.
Returns
sigma::Real: The standard deviation, orNaN.
Related
PortfolioOptimisers.exposure_universe_size — Function
exposure_universe_size(u::MatNum, t::Integer)Return the number of assets in the universe of one observation.
The universe is the assets of positive weight, which is every asset when the caller reads no weight history.
Arguments
u: Resolved weight historyobservations × assets.t: Position of the observation.
Returns
n::Int: Number of assets in the universe.
Related
PortfolioOptimisers.exposure_covered_count — Function
exposure_covered_count(B::Arr3Num, u::MatNum, t::Integer, k::Integer)Return the number of assets of the universe of one observation at which one factor exposure is finite.
Arguments
B: Exposure historyobservations × assets × factors, unlagged.u: Resolved weight historyobservations × assets.t: Position of the observation.k: Position of the factor.
Returns
n::Int: Number of covered assets.
Related
PortfolioOptimisers.cs_diagnostic_exposures — Function
cs_diagnostic_exposures(csfm::CrossSectionalFactorModel)
cs_diagnostic_exposures(Ms::Nothing)
cs_diagnostic_exposures(Ms::Arr3Num)Return the unlagged exposure history an exposure diagnostic reads off a factor model block.
The exposure group reads the history as the panel wrote it, so it takes no lag and no family re-basis. The absent case is the dispatch rather than a branch, and its message names the field the caller must populate.
Arguments
csfm: A cross-sectional factor model block.Ms: TheMsfield of the block, ornothing.
Validation
csfm.Msis notnothing, else anIsNothingErrornamingMsis raised.
Returns
Ms::Arr3Num: Exposure historyobservations × assets × factors.
Related
PortfolioOptimisers.exposure_ic_data — Function
exposure_ic_data(csfm::CrossSectionalFactorModel, reduced::Bool)Return the exposure history, the reconstructed asset returns and the regression weights the information coefficient reads off a factor model block.
The block carries no asset returns, so they are reconstructed from the parts it does carry: the systematic return of the fit and the residual. The reconstruction is defined from observation $\ell + 1$, so the answer starts at observation $\max(1, \ell)$, whose own return row is written NaN and is never read: the information coefficient scores an exposure against the returns that follow it.
Algorithm
- Refuse a block that carries no exposure history, or no cross-sectional fit.
- Reconstruct the return of each observation as $\mathbf{B}_{t-\ell} \boldsymbol{f}_{t} + \boldsymbol{\varepsilon}_{t}$, and write
NaNwhere the lag leaves it undefined. - Map the exposures through the family re-basis when
reduced, and trim all three histories to the observations from $\max(1, \ell)$.
Arguments
csfm: A cross-sectional factor model block.reduced: Map the exposures through the family re-basis of the block.
Validation
csfm.Msis notnothing, else anIsNothingErrornamingMsis raised.csfm.csris notnothing, else anIsNothingErrornamingcsris raised.size(csfm.Ms, 1) > csfm.lag, andcsfm.csr.fcarries the observation axis ofcsfm.Ms.
Returns
B::Arr3Num: Exposure history of the trimmed observation axis.R::MatNum: Reconstructed asset returns of the same axis.w::Option{<:MatNum}: Regression weights of the same axis, ornothing.
Related
PortfolioOptimisers.exposure_ic_exposures — Function
exposure_ic_exposures(fcb::Nothing, Ms::Arr3Num, reduced::Bool)
exposure_ic_exposures(fcb::FactorFamilyBasis, Ms::Arr3Num, reduced::Bool)Return the exposure history the information coefficient scores, on the raw axis or on the reduced one.
A block that carries no family re-basis has one axis, so that case returns the history unchanged whatever reduced states.
Arguments
fcb: Thefcbfield of aCrossSectionalFactorModel, ornothing.Ms: Unlagged exposure historyobservations × assets × factors.reduced: Map the history through the re-basis.
Returns
B::Arr3Num: The history, on the reduced axis when a re-basis is set andreducedistrue.
Related