Factor Model Summary: private API

Functions

PortfolioOptimisers.factor_summary_finite_columnFunction
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 series observations × factors.
  • k: Position of the factor.

Returns

  • v::Vector{<:Real}: The entries of column k that are not NaN, in the order of the observations.

Related

source
PortfolioOptimisers.factor_summary_ratioFunction
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, and NaN when the denominator is zero or absent, or when the ratio is not finite.

Related

source
PortfolioOptimisers.factor_summary_return_statsFunction
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 history observations × 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

source
PortfolioOptimisers.factor_summary_autocorrelationFunction
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 history observations × factors.

Returns

  • autocorr::Vector{<:Real}: One entry per factor, and NaN for a series of one observation.

Related

source
PortfolioOptimisers.factor_summary_returnsFunction
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: The csr field of the block, or nothing.

Validation

  • csfm.csr is not nothing, else an IsNothingError naming csr is raised.

Returns

  • f::MatNum: Factor return history observations × factors.

Related

source
PortfolioOptimisers.factor_summary_positionsFunction
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: The fcb field of the block, or nothing.
  • nf: The nf field of the block, or nothing.
  • K: Number of raw factors.

Validation

  • csfm.nf is not nothing when csfm.fcb is present, else an IsNothingError naming nf is raised: a re-based block cannot be joined without the names.

Returns

  • pos::Vector{Int}: One entry per raw factor. Entry k is the position of raw factor k on the reduced axis, or 0 when the re-basis dropped it.

Related

source
PortfolioOptimisers.factor_summary_gramFunction
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: The Ms field of the block, or nothing.
  • threshold: Absolute t-statistic the exceedance rate counts against.

Returns

  • mean_abs_t::Option{<:Vector{<:Real}}: One entry per raw factor, or nothing.
  • t_rate::Option{<:Vector{<:Real}}: One entry per raw factor, or nothing.
  • mean_vif::Option{<:Vector{<:Real}}: One entry per raw factor, or nothing.

Related

source
PortfolioOptimisers.factor_summary_exposure_varianceFunction
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 history observations × assets × factors, unlagged.
  • t: Position of the observation.
  • k: Position of the factor.

Returns

  • v::Real: The variance, and NaN when the cross-section carries no finite exposure.

Related

source
PortfolioOptimisers.factor_summary_constant_exposuresFunction
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 history observations × assets × factors, unlagged.

Returns

  • c::BitVector: One entry per factor, true when the largest cross-sectional variance the factor reaches is under 1e-12.

Related

source
PortfolioOptimisers.factor_summary_stabilityFunction
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 history observations × assets × factors, unlagged.
  • csfm: A cross-sectional factor model block.
  • step: Number of observations between the two cross-sections the coefficient reads.
  • weighting: The AbstractOrthogonalityMetric whose weight history the coefficient reads.

Returns

  • stability::Vector{<:Real}: One entry per raw factor.

Related

source
PortfolioOptimisers.factor_summary_exposureFunction
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: The Ms field of the block, or nothing.
  • step: Number of observations between the two cross-sections the stability reads.
  • weighting: The AbstractOrthogonalityMetric the stability reads.
  • coverage_weighting: The AbstractOrthogonalityMetric whose positive weights are the coverage's universe.

Returns

  • stability::Option{<:Vector{<:Real}}: One entry per raw factor, or nothing.
  • coverage::Option{<:Vector{<:Real}}: One entry per raw factor, or nothing.

Related

source