Factor Model Summary: private API
Functions
PortfolioOptimisers.factor_summary_finite_column — Function
factor_summary_finite_column(A::MatNum, k::Integer)Return the finite entries of one column of a diagnostic series.
Every column of the summary aggregates a series over the observations, and an observation whose answer is absent contributes nothing rather than poisoning the aggregate. The absent entries are dropped once, here, so each aggregate reads a dense vector and carries no test of its own.
Arguments
A: A seriesobservations × factors.k: Position of the factor.
Returns
v::Vector{<:Real}: The entries of columnkthat are notNaN, in the order of the observations.
Related
PortfolioOptimisers.factor_summary_column_mean — Function
factor_summary_column_mean(A::MatNum, k::Integer)Return the mean of the finite entries of one column of a diagnostic series.
Arguments
A: A seriesobservations × factors.k: Position of the factor.
Returns
m::Real: The mean, andNaNwhen the column carries no finite entry.
Related
PortfolioOptimisers.factor_summary_column_median — Function
factor_summary_column_median(A::MatNum, k::Integer)Return the median of the finite entries of one column of a diagnostic series.
Arguments
A: A seriesobservations × factors.k: Position of the factor.
Returns
m::Real: The median, andNaNwhen the column carries no finite entry.
Related
PortfolioOptimisers.factor_summary_ratio — Function
factor_summary_ratio(m::Real, v::Real)Return a ratio of two summary statistics, answering NaN wherever the ratio is not defined.
A ratio of a summary is a Sharpe ratio, so its denominator is a volatility. A zero volatility, an absent volatility and a division that overflows all say the same thing — the ratio has no value — and this is the one place that says it.
Arguments
m: Numerator.v: Denominator.
Returns
r::Real: The ratio, andNaNwhen the denominator is zero or absent, or when the ratio is not finite.
Related
PortfolioOptimisers.factor_summary_return_stats — Function
factor_summary_return_stats(f::MatNum, ppy::Number)Return the annualised mean, the annualised volatility and the Sharpe ratio of every factor return series.
An observation whose factor return is absent is dropped from the mean and from the volatility, so a series with a gap is still summarised. The volatility is the corrected sample standard deviation, which needs two observations, and a series with fewer reads NaN.
Mathematical definition
Let $\boldsymbol{f}_{k}$ be the finite entries of the factor return series of factor $k$, let $T_{k}$ be their count, and let $p$ be ppy.
\[\begin{align} \mathrm{ann\_return}_{k} &= p \, \dfrac{1}{T_{k}} \sum_{t} f_{tk}\\ \mathrm{ann\_volatility}_{k} &= \sqrt{\dfrac{p}{T_{k} - 1} \sum_{t} \left(f_{tk} - \dfrac{1}{T_{k}} \sum_{s} f_{sk}\right)^{2}}\\ \mathrm{sharpe}_{k} &= \dfrac{\mathrm{ann\_return}_{k}}{\mathrm{ann\_volatility}_{k}}\,. \end{align}\]
Arguments
f: Factor return historyobservations × factors.ppy: Periods per year.
Returns
ann_return::Vector{<:Real}: One entry per factor.ann_volatility::Vector{<:Real}: One entry per factor.sharpe::Vector{<:Real}: One entry per factor.
Related
PortfolioOptimisers.factor_summary_autocorrelation — Function
factor_summary_autocorrelation(f::MatNum)Return the lag-one autocorrelation of every factor return series.
The answer is the Pearson correlation of the pair (f[1:end - 1, k], f[2:end, k]), each half centred on its own mean. It is not StatsBase.autocor, which centres both halves on the mean of the whole series and divides by the sum of squares of the whole series. The two agree in the limit and differ on a short series, so a caller who wants the other definition calls StatsBase.autocor on the factor return history itself.
A series with an absent entry reads NaN, because the mean of the half that holds it is absent.
Mathematical definition
Let $a_{t} = f_{tk}$ for $t = 1 \ldots T - 1$, let $b_{t} = f_{(t + 1)k}$, and let $\bar{a}$ and $\bar{b}$ be their means.
\[\mathrm{autocorr}_{k} = \dfrac{\sum_{t} (a_{t} - \bar{a})(b_{t} - \bar{b})}{\sqrt{\sum_{t} (a_{t} - \bar{a})^{2} \sum_{t} (b_{t} - \bar{b})^{2}}}\,.\]
Arguments
f: Factor return historyobservations × factors.
Returns
autocorr::Vector{<:Real}: One entry per factor, andNaNfor a series of one observation.
Related
PortfolioOptimisers.factor_summary_returns — Function
factor_summary_returns(csfm::CrossSectionalFactorModel)
factor_summary_returns(csr::Nothing)
factor_summary_returns(csr::CrossSectionalRegression)Return the factor return history a summary reads off a factor model block.
The history is on the raw factor axis, because it is what the fit produced before any 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.csr: Thecsrfield of the block, ornothing.
Validation
csfm.csris notnothing, else anIsNothingErrornamingcsris raised.
Returns
f::MatNum: Factor return historyobservations × factors.
Related
PortfolioOptimisers.factor_summary_positions — Function
factor_summary_positions(csfm::CrossSectionalFactorModel)
factor_summary_positions(fcb::Nothing, nf::Nothing, K::Integer)
factor_summary_positions(fcb::Nothing, nf::VecStr, K::Integer)
factor_summary_positions(fcb::AbstractFactorFamilyBasis, nf::Nothing, K::Integer)
factor_summary_positions(fcb::FactorFamilyBasis, nf::VecStr, K::Integer)Return the position each raw factor takes on the reduced factor axis.
The regression group answers on the reduced axis and the summary answers on the raw one, so the two are joined by name. A raw factor the re-basis dropped takes the position 0, which is what makes its Gram columns read NaN.
A block that carries no re-basis needs no join, and the two axes are then the same axis.
Arguments
csfm: A cross-sectional factor model block.fcb: Thefcbfield of the block, ornothing.nf: Thenffield of the block, ornothing.K: Number of raw factors.
Validation
csfm.nfis notnothingwhencsfm.fcbis present, else anIsNothingErrornamingnfis raised: a re-based block cannot be joined without the names.
Returns
pos::Vector{Int}: One entry per raw factor. Entrykis the position of raw factorkon the reduced axis, or0when the re-basis dropped it.
Related
PortfolioOptimisers.factor_summary_mapped — Function
factor_summary_mapped(v::VecNum, pos::AbstractVector{Int})Return a statistic of the reduced factor axis, written onto the raw factor axis.
Arguments
v: A statistic, one entry per reduced factor.pos: Position of each raw factor on the reduced axis,0where the re-basis dropped it.
Returns
m::Vector{<:Real}: One entry per raw factor, andNaNat a factor the re-basis dropped.
Related
PortfolioOptimisers.factor_summary_gram — Function
factor_summary_gram(csfm::CrossSectionalFactorModel, threshold::Number)
factor_summary_gram(Ms::Nothing, csfm::CrossSectionalFactorModel, threshold::Number)
factor_summary_gram(Ms::Arr3Num, csfm::CrossSectionalFactorModel, threshold::Number)Return the three regression columns of a factor model summary, on the raw factor axis.
The columns are the mean absolute t-statistic, the rate at which the absolute t-statistic passes threshold, and the mean variance inflation factor. Each is the time average of a level-2 series of the regression group, joined back onto the raw factor axis by name.
A block that carries no exposure history carries no regression design either, so the three columns are absent as a whole. The absent case is the dispatch rather than a branch.
Arguments
csfm: A cross-sectional factor model block.Ms: TheMsfield of the block, ornothing.threshold: Absolute t-statistic the exceedance rate counts against.
Returns
mean_abs_t::Option{<:Vector{<:Real}}: One entry per raw factor, ornothing.t_rate::Option{<:Vector{<:Real}}: One entry per raw factor, ornothing.mean_vif::Option{<:Vector{<:Real}}: One entry per raw factor, ornothing.
Related
PortfolioOptimisers.factor_summary_exposure_variance — Function
factor_summary_exposure_variance(Ms::Arr3Num, t::Integer, k::Integer)Return the cross-sectional variance of one factor exposure at one observation.
The variance is taken over the finite exposures of the observation and it is not corrected.
Arguments
Ms: Exposure historyobservations × assets × factors, unlagged.t: Position of the observation.k: Position of the factor.
Returns
v::Real: The variance, andNaNwhen the cross-section carries no finite exposure.
Related
PortfolioOptimisers.factor_summary_constant_exposures — Function
factor_summary_constant_exposures(Ms::Arr3Num)Return which factor exposures never vary across the cross-section.
A constant exposure is the global intercept and the constant column of a one-hot family. Its cross-section has no spread, so its stability coefficient is not defined and the summary writes 1 in its place: an exposure that never moves is perfectly stable. The patch lives in the summary rather than in exposure_stability, which answers the NaN the correlation earns.
Arguments
Ms: Exposure historyobservations × assets × factors, unlagged.
Returns
c::BitVector: One entry per factor,truewhen the largest cross-sectional variance the factor reaches is under1e-12.
Related
PortfolioOptimisers.factor_summary_stability — Function
factor_summary_stability(Ms::Arr3Num, csfm::CrossSectionalFactorModel; step::Integer,
weighting)Return the stability column of a factor model summary, on the raw factor axis.
The column is the median over the observations of exposure_stability, with a constant exposure patched to 1. A history with no more observations than step has no stability series at all, and then every factor reads NaN but for the constant ones, which still read 1.
Arguments
Ms: Exposure historyobservations × assets × factors, unlagged.csfm: A cross-sectional factor model block.step: Number of observations between the two cross-sections the coefficient reads.weighting: TheAbstractOrthogonalityMetricwhose weight history the coefficient reads.
Returns
stability::Vector{<:Real}: One entry per raw factor.
Related
PortfolioOptimisers.factor_summary_exposure — Function
factor_summary_exposure(csfm::CrossSectionalFactorModel; step, weighting,
coverage_weighting)
factor_summary_exposure(Ms::Nothing, csfm::CrossSectionalFactorModel; kwargs...)
factor_summary_exposure(Ms::Arr3Num, csfm::CrossSectionalFactorModel; step, weighting,
coverage_weighting)Return the two exposure columns of a factor model summary, on the raw factor axis.
The columns are the median exposure stability and the average coverage. Both read the unlagged exposure history, as the whole exposure group does. A block that carries no exposure history has neither, and the absent case is the dispatch rather than a branch.
The two columns read different weight histories: the stability reads the history weighting names, and the coverage reads the one coverage_weighting names.
Arguments
csfm: A cross-sectional factor model block.Ms: TheMsfield of the block, ornothing.step: Number of observations between the two cross-sections the stability reads.weighting: TheAbstractOrthogonalityMetricthe stability reads.coverage_weighting: TheAbstractOrthogonalityMetricwhose positive weights are the coverage's universe.
Returns
stability::Option{<:Vector{<:Real}}: One entry per raw factor, ornothing.coverage::Option{<:Vector{<:Real}}: One entry per raw factor, ornothing.
Related