High Order Factor Prior: private API
PortfolioOptimisers.AbstractHiLoOrderPriorEstimator_F — Type
const AbstractHiLoOrderPriorEstimator_F = Union{<:AbstractLowOrderPriorEstimator_F,
<:AbstractHighOrderPriorEstimator_F}Groups the two families that require factor returns, one per order.
AbstractHiLoOrderPriorEstimator_F is the type-level half of the test for this estimator cannot run without factor returns, taken across both orders at once: a member answers true to needs_factor_returns. The doors that check for a missing factor matrix ask the predicate rather than this union, because a factor leaf may sit under a host whose own factor argument is optional, and the predicate walks the tree where an isa test reads the host alone.
Related
PortfolioOptimisers.coskewness_residuals — Function
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.
Nothing is demeaned here. The zero-mean assumption is the factor model's, and me supplies the averaging rule rather than a centre. Feed residuals whose mean is not zero and the surviving entries hold the raw third moment $\mathbb{E}[(\varepsilon_i + c_i)^3]$ rather than the central one, so the result is a coskewness only as far as the assumption holds.
Mathematical definition
\[(\hat{\mathbf{M}}_{3,\varepsilon})_{i,\,c} = \begin{cases} \mathbb{E}[\varepsilon_i^3]\,, & c = (i - 1)N + i\,, \\ 0\,, & \text{otherwise.} \end{cases}\]
Where:
- $\varepsilon_i$: residual of asset $i$, the $i$-th column of
X. - $N$: Number of assets.
- $\hat{\mathbf{M}}_{3,\varepsilon}$: the $N \times N^2$ residual coskewness matrix,
sk_err.
Column $(i - 1)N + i$ is the one that holds $\varepsilon_i \varepsilon_i$ in a coskewness matrix, so row $i$ meets it at the only entry of that row a set of independent zero-mean residuals can fill.
Algorithm
- Take
N = size(X, 2)andN2 = N^2. - Cube the residuals entry by entry, giving
X3. - Allocate
sk_err, anN × N2sparse zero matrix of the element type ofX3. - Take
idx, the linear index range1:(N2 + N + 1):(N2 * N). In anN × N2matrix stored column by column, itsi-th entry addresses(i, (i - 1) * N + i). - Average the columns of
X3underme, and write theNvalues intoidx.
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.
The incremental fit
This prior has no exact incremental recursion, so it takes the online step by refitting from a sample buffer: Online seeds cache, partial_fit! appends each observation to it verbatim, and the one-argument prior runs this estimator's own batch verb over the rows the buffer kept. The answer is therefore exactly a batch fit over those rows, and a max_history on the wrapper windows the whole fit.
cache travels the three propagation channels as every partial-fit state does: factory carries it unchanged, port_opt_view slices it to the selected assets, and obs_weights_view drops it, because no slice of a state exists on the observation axis. It is not rendered, because a running buffer is not the configuration a reader looks the type up for.
Related
PortfolioOptimisers.cokurtosis_residuals — Function
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 index pattern collapses to one of the branches in the loop, and the only pattern that is zero is the one whose four indices are all distinct.
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.
Mathematical definition
Write $r_i = s_i + \varepsilon_i$, with $s_i$ the systematic return and $\varepsilon_i$ the residual. The residual contribution is $\mathbb{E}[r_i r_k r_j r_l] - \mathbb{E}[s_i s_k s_j s_l]$, and it depends on the four indices only through the pattern of their coincidences:
\[(\hat{\mathbf{\Sigma}}_{4,\varepsilon})_{(i-1)N+k,\;(j-1)N+l} = \begin{cases} 6 e_{2,a} \mathbf{\Sigma}_{aa} + e_{4,a}\,, & i = k = j = l = a\,, \\ 3 e_{2,a} \mathbf{\Sigma}_{ab}\,, & \text{three indices are } a \text{ and the fourth is } b\,, \\ e_{2,a} \mathbf{\Sigma}_{bb} + e_{2,b} \mathbf{\Sigma}_{aa} + e_{2,a} e_{2,b}\,, & \text{two pairs, } a \text{ and } b\,, \\ e_{2,a} \mathbf{\Sigma}_{bc}\,, & \text{one pair } a \text{, and singles } b \text{ and } c\,, \\ 0\,, & \text{all four distinct.} \end{cases}\]
Where:
- $e_{2,i} = \mathbb{E}[\varepsilon_i^2]$, $e_{4,i} = \mathbb{E}[\varepsilon_i^4]$: the second and fourth residual moments,
e2ande4. - $\mathbf{\Sigma}$: the systematic covariance,
sigma. - $N$: Number of assets.
- $\hat{\mathbf{\Sigma}}_{4,\varepsilon}$: the $N^2 \times N^2$ residual cokurtosis matrix,
kt_res.
A single $\varepsilon$ factor averages to zero and a lone $s$ factor is centred, which is what removes the odd terms. Four distinct indices leave no $\varepsilon$ paired with itself, so that case alone vanishes; a pattern with a pair and two singles does not, because the pair contributes $e_{2,a}$ and the two singles contribute their systematic covariance.
Algorithm
- Take
N = size(X, 2)andN2 = N^2. - Square and fourth-power the residuals entry by entry, giving
X2andX4. - Average the columns of each under
me, givinge2ande4. - Allocate
kt_res, of size(N2, N2), in the promotion of the element types ofe4andsigma. - Run
exover theN2column pairs(j, l). For each column, walk the row pairs(i, k)and skip the pair whenrow > col, so only the upper triangle is visited. - Select the value
valfor(i, k, j, l)through the branch chain of the closed form above, ordered so the most common patterns are tested first. - Write
valtokt_res[row, col]and tokt_res[col, row].
The executor changes the order in which the columns are visited and nothing else: each column writes its own entries, so FLoops.SequentialEx() and FLoops.ThreadedEx() give bit-identical results.
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:FLoopsexecutor for theN²loop. Defaults toFLoops.ThreadedEx().
Returns
kt_res::Matrix:N² × N²residual cokurtosis matrix.
Related
PortfolioOptimisers.show_fields — Method
show_fields(
_::HighOrderFactorPriorEstimator
) -> NTuple{5, Symbol}
Renders every field of a HighOrderFactorPriorEstimator except cache.
The state a cache holds is the running detail of an incremental fit, not the configuration a reader looks the type up for, and it prints under the estimator at every site that renders one. Set set_show_nothing_fields!(:HighOrderFactorPriorEstimator, true) to render it.
Arguments
::HighOrderFactorPriorEstimator: Prior estimator, read for its type alone.
Returns
fields::Tuple: The field names to render, which is(:pe, :kte, :ske, :ex, :rsd).
Related