Cokurtosis: private API
PortfolioOptimisers.coverage_cokurtosis — Function
coverage_cokurtosis(kte, cvg, X; dims::Int = 1, mean = nothing,
active_mask = nothing, kwargs...) -> MatNumFits a square cokurtosis matrix over the arm the estimator's coverage policy selects.
The cvg field of the estimator is passed as the second argument, so the arm is chosen by dispatch on the policy rather than by a branch on its value, exactly as coverage_covariance does for a covariance. The moment algorithm of kte chooses between the FullMoment arm, which centres on each asset's own mean and takes the deviations whole, and the SemiMoment arm, which clips them at zero first.
Arguments
kte: Cokurtosis estimator.cvg: The policy the estimator carries, which selects the arm.X: Data matrix (observations × assets).dims: Dimension along which to perform the computation.mean: Optional mean vector. The available-case arm refuses one.active_mask: The active mask of the Asset Panel over the window, ornothing. The Coverage Universe arm ignores it.kwargs...: Additional keyword arguments passed to the mean estimator.
Returns
ckurt::MatNum: Square cokurtosis matrixassets² x assets².
Related
PortfolioOptimisers.coverage_cokurtosis — Method
coverage_cokurtosis(
kte::Cokurtosis{<:Any, <:Any, <:FullMoment},
::Nothing,
X::AbstractMatrix{<:Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}};
dims,
mean,
active_mask,
kwargs...
) -> Any
Nothing method of the FullMoment arm of coverage_cokurtosis. The Coverage Universe arm, which centres the whole window on one vector and delegates to _cokurtosis, and which is the body the verb has always had.
Related
PortfolioOptimisers.coverage_cokurtosis — Method
coverage_cokurtosis(
kte::Cokurtosis{<:Any, <:Any, <:SemiMoment},
::Nothing,
X::AbstractMatrix{<:Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}};
dims,
mean,
active_mask,
kwargs...
) -> Any
Nothing method of the SemiMoment arm of coverage_cokurtosis. The Coverage Universe arm, which clips the de-meaned returns at zero before delegating, and which is the body the verb has always had.
Related
PortfolioOptimisers.coverage_cokurtosis — Method
coverage_cokurtosis(
kte::Cokurtosis,
cvg::CoveragePolicy,
X::AbstractMatrix{<:Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}};
dims,
mean,
active_mask,
kwargs...
) -> Any
CoveragePolicy method of coverage_cokurtosis. The available-case arm: each quadruple is fitted on the observations at which its four assets are all finite and active, and each cell carries its own denominator.
The centre is each asset's own available-case mean, its own finite and active observations alone, and not the quadruple's; coverage_coskewness states why. An external mean is refused for the same reason.
The repair sees the block, which matrix_processing_block! already derives correctly here: the diagonal of a cokurtosis matrix at the pair (i, j) is E[yᵢ²yⱼ²], finite exactly where the pair shares an observation, so the block is the set of pairs the fit answered for and the frame is left alone.
Neither this order nor the third folds: an exact per-cell recursion here needs the second and third co-moments over each quadruple's own observation set, so the online form of an available-case cokurtosis is a buffer refit through Online.
Algorithm
- Read the valid entries, the per-asset available-case centre and the per-asset bookkeeping of the block with
coverage_comoment_block. - Take the numerator as
transpose(z) * zand the denominator astranspose(zc) * zc, the pairwise expansions of the zeroed deviations and of the valid mask. - Divide with
coverage_divide, and frame the refused assets down both pair axes withcoverage_refuse_comoment!. - Repair the block with
matrix_processing_block!.
Related
PortfolioOptimisers._cokurtosis — Function
_cokurtosis(X::MatNum, mp::AbstractMatrixProcessingEstimator, w::Option{<:ObsWeights}) -> MatNumInternal helper that builds the square cokurtosis matrix from a deviation matrix.
_cokurtosis returns the $N^{2} \times N^{2}$ matrix, which the matrix processing estimator repairs in place before the return.
Mathematical definition
The pairwise expansion of the deviation matrix has the rows:
\[\begin{align} \mathbf{Z}_{t,\cdot} &= (\boldsymbol{1}^\intercal \otimes \boldsymbol{y}_t^\intercal) \odot (\boldsymbol{y}_t^\intercal \otimes \boldsymbol{1}^\intercal)\,. \end{align}\]
The $N^{2} \times N^{2}$ square cokurtosis matrix is:
Unweighted:
\[\begin{align} \hat{\mathbf{K}} &= \frac{1}{T} \mathbf{Z}^\intercal \mathbf{Z}\,. \end{align}\]
Weighted:
\[\begin{align} \hat{\mathbf{K}} &= \frac{1}{\sum_{t=1}^{T} w_t} (\boldsymbol{w} \odot \mathbf{Z})^\intercal \mathbf{Z}\,. \end{align}\]
Where:
- $\hat{\mathbf{K}}$: $N^{2} \times N^{2}$ square cokurtosis matrix. Its entry $\hat{\mathbf{K}}_{(i-1)N+j,\,(k-1)N+l}$ is the fourth comoment of the deviations of the assets $i$, $j$, $k$ and $l$, so the matrix is symmetric. This is the source's $\mathbf{\Sigma}_{4}$, not its $\mathbf{M}_{4}$. The latter is $N \times N^{3}$ and the library never builds it.
- $\mathbf{Y}$: $T \times N$ deviation matrix.
FullMomenttakes the centred returns, andSemiMomentclips every positive entry of them to zero. - $\boldsymbol{y}_t$: $N \times 1$ deviation vector of observation $t$, the $t$-th row of $\mathbf{Y}$. Its $i$-th entry is $y_{t,\,i}$.
- $\mathbf{Z}$: $T \times N^{2}$ pairwise expansion of $\mathbf{Y}$, whose $t$-th row is $\mathbf{Z}_{t,\cdot}$ and whose entry $\mathbf{Z}_{t,\,(i-1)N+j}$ is the product $y_{t,\,i} \, y_{t,\,j}$.
- $\boldsymbol{w}$: $T \times 1$ observation weights vector.
- $w_{t}$: Observation weight of observation $t$.
- $T$: Number of observations.
- $N$: Number of assets.
- $\boldsymbol{1}$: $N \times 1$ vector of ones.
- $\otimes$: Kronecker product.
- $\odot$: Element-wise product. Where the operands differ in shape, it broadcasts along the row axis.
Algorithm
- Build
o, the $1 \times N$ row of ones. - Build
z, the pairwise expansionkron(o, X) ⊙ kron(X, o). Its column(i - 1) * N + jis the element-wise product of the columnsiandjofX. - Without weights, form
ckurtastranspose(z) * z / T. - With weights, form
ckurtastranspose(w .* z) * z / sum(w). The weights multiply the left factor alone, so each summand carries one weight and not four. - Run
matrix_processing!onckurtin place, and return it.
Arguments
X: Deviation matrix (observations × assets), already centred by the caller.mp: Matrix processing estimator.w: Optional observation weights. The unweighted method takesnothingthrough itsargs....
Returns
ckurt::MatNum: Square cokurtosis matrixassets² x assets². It is processed in place bymp.
Related
References
References
- [5]
- D. Cajas. Advanced Portfolio Optimization: A Cutting-edge Quantitative Approach (Springer Nature Switzerland, 2025).
- [30]
- D. Cajas. Convex Optimization of Portfolio Kurtosis. Available at SSRN 4202967 (2022).