High Order Factor Prior

PortfolioOptimisers.AbstractHighOrderPriorEstimator_FType
abstract type AbstractHighOrderPriorEstimator_F <: AbstractHighOrderPriorEstimator

High order prior estimator using factor returns.

AbstractHighOrderPriorEstimator_F is the base type for estimators that compute high order moments (such as coskewness and cokurtosis) requiring both asset and factor returns data. All concrete factor-based high order prior estimators should subtype this type.

Related

source
PortfolioOptimisers.HighOrderFactorPriorEstimatorType
struct HighOrderFactorPriorEstimator{__T_pe, __T_kte, __T_ske, __T_ex, __T_rsd} <: AbstractHighOrderPriorEstimator_F

Projects factor coskewness and cokurtosis onto the asset axis through the regression loadings.

HighOrderFactorPriorEstimator extends a low-order factor prior with coskewness and cokurtosis moments estimated from a factor model. It supports error correction of higher-order moments using residuals from the factor regression.

Fields

  • pe: Prior estimator.
  • kte: Cokurtosis estimator.
  • ske: Coskewness estimator.
  • ex: Parallel execution strategy.
  • rsd: Whether to include residual variance in the posterior covariance.

Constructors

HighOrderFactorPriorEstimator(;    pe::AbstractLowOrderPriorEstimator_F_AF = FactorPrior(),    kte::Option{<:CokurtosisEstimator} = Cokurtosis(; alg = FullMoment()),    ske::Option{<:CoskewnessEstimator} = Coskewness(; alg = FullMoment()),    ex::FLoops.Transducers.Executor = FLoops.ThreadedEx(),    rsd::Bool = true) -> HighOrderFactorPriorEstimator

Keywords correspond to the struct's fields.

Propagated parameters

When factory is called on this type, the following @fprop-tagged fields are automatically propagated:

  • pe: Recursively updated via factory.
  • kte: Recursively updated via factory.
  • ske: Recursively updated via factory.

View parameters

When port_opt_view is called on this type, the following @vprop-tagged fields are automatically subset to the selected indices:

Examples

julia> HighOrderFactorPriorEstimator()HighOrderFactorPriorEstimator   pe ┼ FactorPrior      │    pe ┼ EmpiricalPrior      │       │        ce ┼ PortfolioOptimisersCovariance      │       │           │   ce ┼ Covariance      │       │           │      │    me ┼ SimpleExpectedReturns      │       │           │      │       │   w ┴ nothing      │       │           │      │    ce ┼ GeneralCovariance      │       │           │      │       │   ce ┼ StatsBase.SimpleCovariance: StatsBase.SimpleCovariance(true)      │       │           │      │       │    w ┴ nothing      │       │           │      │   alg ┴ FullMoment()      │       │           │   mp ┼ MatrixProcessing      │       │           │      │     pdm ┼ Posdef      │       │           │      │         │      alg ┼ UnionAll: NearestCorrelationMatrix.Newton      │       │           │      │         │   kwargs ┴ @NamedTuple{}: NamedTuple()      │       │           │      │      dn ┼ nothing      │       │           │      │      dt ┼ nothing      │       │           │      │     alg ┼ nothing      │       │           │      │   order ┴ NTuple{4, Symbol}: (:pdm, :dn, :dt, :alg)      │       │        me ┼ SimpleExpectedReturns      │       │           │   w ┴ nothing      │       │   horizon ┴ nothing      │    mp ┼ MatrixProcessing      │       │     pdm ┼ Posdef      │       │         │      alg ┼ UnionAll: NearestCorrelationMatrix.Newton      │       │         │   kwargs ┴ @NamedTuple{}: NamedTuple()      │       │      dn ┼ nothing      │       │      dt ┼ nothing      │       │     alg ┼ nothing      │       │   order ┴ NTuple{4, Symbol}: (:pdm, :dn, :dt, :alg)      │    re ┼ StepwiseRegression      │       │   crit ┼ PValue      │       │        │   t ┴ Float64: 0.05      │       │    alg ┼ ForwardSelection()      │       │    tgt ┼ LinearModel      │       │        │   kwargs ┴ @NamedTuple{}: NamedTuple()      │    ve ┼ SimpleVariance      │       │          me ┼ SimpleExpectedReturns      │       │             │   w ┴ nothing      │       │           w ┼ nothing      │       │   corrected ┴ Bool: true      │   rsd ┴ Bool: true  kte ┼ Cokurtosis      │    me ┼ SimpleExpectedReturns      │       │   w ┴ nothing      │    mp ┼ MatrixProcessing      │       │     pdm ┼ Posdef      │       │         │      alg ┼ UnionAll: NearestCorrelationMatrix.Newton      │       │         │   kwargs ┴ @NamedTuple{}: NamedTuple()      │       │      dn ┼ nothing      │       │      dt ┼ nothing      │       │     alg ┼ nothing      │       │   order ┴ NTuple{4, Symbol}: (:pdm, :dn, :dt, :alg)      │   alg ┼ FullMoment()      │     w ┴ nothing  ske ┼ Coskewness      │    me ┼ SimpleExpectedReturns      │       │   w ┴ nothing      │    mp ┼ MatrixProcessing      │       │     pdm ┼ Posdef      │       │         │      alg ┼ UnionAll: NearestCorrelationMatrix.Newton      │       │         │   kwargs ┴ @NamedTuple{}: NamedTuple()      │       │      dn ┼ nothing      │       │      dt ┼ nothing      │       │     alg ┼ nothing      │       │   order ┴ NTuple{4, Symbol}: (:pdm, :dn, :dt, :alg)      │   alg ┼ FullMoment()      │     w ┴ nothing   ex ┼ Transducers.ThreadedEx{@NamedTuple{}}: Transducers.ThreadedEx()  rsd ┴ Bool: true

Related

References

  • [86] K. Boudt, W. Lu and B. Peeters. Higher order comoments of multifactor models and asset allocation. Finance Research Letters 13, 225–233 (2015).
  • [87] L. Martellini and V. Ziemann. Improved estimates of higher-order comoments and implications for portfolio selection. The Review of Financial Studies 23, 1467–1502 (2010).
source
PortfolioOptimisers.coskewness_residualsFunction
coskewness_residuals(X::MatNum, me::AbstractExpectedReturnsEstimator)

Build the residual coskewness matrix a factor lift adds to its projected coskewness.

X is the residual matrix X - posterior_X, not the asset returns. The residuals are independent across assets and have zero mean, so every cross term of their coskewness vanishes and only the N own-third-moment entries survive. The result is therefore an N × N² sparse matrix carrying mean(me, X .^ 3) on the positions 1:(N² + N + 1):(N² * N) — entry (i, (i - 1) * N + i), which is where $\mathbb{E}[\varepsilon_i^3]$ sits in a coskewness matrix — and zero everywhere else.

Nothing is demeaned here. The zero-mean assumption is the factor model's, and me supplies the averaging rule rather than a centre.

Arguments

  • X: Residual return matrix (observations × assets).
  • me: Expected returns estimator, used to average the cubed residuals.

Returns

  • sk_err::SparseMatrixCSC: N × N² residual coskewness matrix.

Related

source
PortfolioOptimisers.cokurtosis_residualsFunction
cokurtosis_residuals(sigma::MatNum, X::MatNum, me::AbstractExpectedReturnsEstimator,
                     ex::FLoops.Transducers.Executor = FLoops.ThreadedEx())

Build the residual cokurtosis matrix a factor lift adds to its projected cokurtosis.

X is the residual matrix X - posterior_X, not the asset returns, and sigma is the systematic covariance $\mathbf{B} \mathbf{\Sigma}_f \mathbf{B}^\intercal$, with any residual block already removed. The caller does that removal; see factor_residual_config.

Nothing is standardised here. Every entry is written in closed form from the second and fourth residual moments e2 = mean(me, X .^ 2) and e4 = mean(me, X .^ 4) together with sigma, under the factor model's assumption that the residuals have zero mean and are independent both of each other and of the factors. Under those assumptions each of the fourteen index patterns collapses to one of the branches in the loop, and every pattern with a lone index — one asset appearing exactly once — is zero.

Entry (i - 1) * N + k, (j - 1) * N + l of the result is the residual contribution to $\mathbb{E}[r_i r_k r_j r_l]$. The matrix is symmetric, so only the upper triangle is computed and each value is written to both places.

Arguments

  • sigma: Systematic covariance matrix, N × N.
  • X: Residual return matrix (observations × assets).
  • me: Expected returns estimator, used to average the squared and the fourth-power residuals.
  • ex: FLoops executor for the loop. Defaults to FLoops.ThreadedEx().

Returns

  • kt_res::Matrix: N² × N² residual cokurtosis matrix.

Related

source
PortfolioOptimisers.priorMethod
prior(pe::HighOrderFactorPriorEstimator, X::MatNum, F::MatNum; dims::Int = 1,
      kwargs...)

Compute high order factor prior moments for asset returns using a factor model.

prior estimates the mean, covariance, coskewness, and cokurtosis of asset returns using a factor model with residual error correction. It first computes low order moments via the embedded factor prior, then maps factor higher-order moments to asset space via the Kronecker product of the factor loadings, optionally adding residual corrections.

Mathematical definition

Factor comoments are mapped to asset space through the loadings matrix $\mathbf{B}$:

\[\begin{align} \hat{\mathbf{\Sigma}}_4 &= (\mathbf{B} \otimes \mathbf{B}) \hat{\mathbf{\Sigma}}_{4,f} (\mathbf{B} \otimes \mathbf{B})^\intercal + \hat{\mathbf{\Sigma}}_{4,\varepsilon}\,, \\ \hat{\mathbf{M}}_3 &= \mathbf{B} \hat{\mathbf{M}}_{3,f} (\mathbf{B} \otimes \mathbf{B})^\intercal + \hat{\mathbf{M}}_{3,\varepsilon}\,. \end{align}\]

Where:

  • $\hat{\mathbf{\Sigma}}_4$: $N^2 \times N^2$ asset square cokurtosis matrix, kt.
  • $\hat{\mathbf{M}}_3$: $N \times N^2$ asset coskewness matrix, sk.
  • $\mathbf{B}$: $N \times K$ factor loadings matrix, pr.rr.M.
  • $\hat{\mathbf{\Sigma}}_{4,f}$: $K^2 \times K^2$ factor square cokurtosis matrix, fpr.kt.
  • $\hat{\mathbf{M}}_{3,f}$: $K \times K^2$ factor coskewness matrix, fpr.sk.
  • $\hat{\mathbf{\Sigma}}_{4,\varepsilon}$: Residual cokurtosis correction from cokurtosis_residuals, present only when rsd is true.
  • $\hat{\mathbf{M}}_{3,\varepsilon}$: Residual coskewness correction from coskewness_residuals, present only when rsd is true.
  • $\otimes$: Kronecker product.

The factor comoments come from pe.kte and pe.ske fit on F, so a non-default alg on either replaces its display above. Either estimator set to nothing drops its moment from both the asset result and the nested factor block.

Arguments

  • pe: High order factor prior estimator.
  • X: Asset returns matrix (observations × assets).
  • F: Factor returns matrix (observations × factors).
  • dims: Dimension along which to perform the computation.
  • kwargs...: Additional keyword arguments passed to underlying estimators.

Validation

Returns

  • pr::HighOrderPrior: Result object containing asset returns, mean, covariance, coskewness tensor, cokurtosis tensor, and factor moments.

Details

The factor co-moments are computed from F directly and nested as a HighOrderPrior over the wrapped prior's own factor block, so fpr.pr === pr.fpr — the co-moments and the low order factor moments describe one distribution, reachable by either route.

The residual cokurtosis correction is defined on the systematic covariance, so a residual block the wrapped estimator added has to come back off first. Which estimator added one, and with what variance estimator, is a declaration the wrapped estimator makes through factor_residual_config rather than a field read — pe is bounded AbstractLowOrderPriorEstimator_F_AF, and only FactorPrior and FactorBlackLittermanPrior carry the fields. A wrapper over either forwards the declaration; everything else declares nothing in an explicit method, and a nothing answer — like an answer whose rsd is false — leaves the covariance alone. There is no default, so a type that declares nothing throws rather than reading as no residual block.

Note

A Black-Litterman prior underneath this estimator now returns numbers where it used to throw. Every wrapping estimator forwards rr and the factor block under ADR 0046, so HighOrderFactorPriorEstimator(; pe = BlackLittermanPrior(; pe = FactorPrior(…))) reaches a regression instead of an IsNothingError.

What comes back is worth understanding. The higher co-moments project through rr.M while mu and sigma carry the views — Black-Litterman makes no claim about third and fourth moments, so the factor projection is the only estimate available.

Warning

The co-moments are computed from F as supplied, so they always describe the pre-view factor distribution, whichever Black-Litterman member is underneath. Where that member reports a posterior factor block — FactorBlackLittermanPrior and BayesianBlackLittermanPrior — the nested fpr therefore mixes orders: fpr.mu and fpr.sigma carry the views, fpr.kt, fpr.sk and fpr.V do not. The fpr.pr === pr.fpr invariant still holds, because both routes reach the same posterior low order block; what differs is the order at which the views stop.

This is a consequence of Black-Litterman having no higher-moment update to apply, not of a value being discarded, and it is the same under BlackLittermanPrior — where the low order factor block is pre-view too, so the carrier happens to be uniform.

Related

source

References

[86]
K. Boudt, W. Lu and B. Peeters. Higher order comoments of multifactor models and asset allocation. Finance Research Letters 13, 225–233 (2015).
[87]
L. Martellini and V. Ziemann. Improved estimates of higher-order comoments and implications for portfolio selection. The Review of Financial Studies 23, 1467–1502 (2010).