Variance Skew Kurtosis

PortfolioOptimisers.MaxRiskMeasureSettingsType
struct MaxRiskMeasureSettings{__T_scale, __T_lb, __T_rke} <: JuMPRiskMeasureSettings

Weights a risk measure inside an aggregate, and bounds its risk expression from below.

This is the settings type of a quantity the optimisation wants more of, so its bound is a floor rather than a ceiling — the shape of the return floor $\bar{\mu}$ in Equation 8.7 of [5]. Skewness is its one holder, and a stated lb reaches the model only through VarianceSkewKurtosis, where that skewness term is built: Skewness is a NonOptimisationRiskMeasure, so no optimiser takes it on its own.

Unlike the ub of RiskMeasureSettings, lb is not checked for non-negativity. A negative floor is meaningful here and works: lb = -1e-8 returns the unconstrained -6.1627e-9, which satisfies it.

Fields

  • scale: Weight of this risk measure in the aggregate risk expression formed from a vector of measures. It is a combination weight, so it is inert on a single measure: an optimiser given one measure drops it before the risk expression is built, and the value-level readers ignore it too. The upper bound in ub binds on the measure's own expression, before scale is applied.
  • lb: Lower bound(s) on the measure's own risk expression, for a quantity the optimisation maximises. A scalar bounds one model. A vector and a Frontier are sweep axes, one solve per entry. A negative value is meaningful, because the quantity it bounds may be negative.
  • rke: Whether to include the risk measure value in the JuMP risk expression.

Constructors

MaxRiskMeasureSettings(;    scale::Number = 1.0,    lb::Option{<:RkRtBounds} = nothing,    rke::Bool = true,) -> MaxRiskMeasureSettings

Keywords correspond to the struct's fields.

Validation

Examples

julia> MaxRiskMeasureSettings()MaxRiskMeasureSettings  scale ┼ Float64: 1.0     lb ┼ nothing    rke ┴ Bool: true

Related

References

  • [5] D. Cajas. Advanced Portfolio Optimization: A Cutting-edge Quantitative Approach (Springer Nature Switzerland, 2025). Section 8.2.1, Equation 8.7.
source
PortfolioOptimisers.SkewnessType
struct Skewness{__T_settings, __T_ve, __T_sk, __T_w, __T_mu, __T_pe} <: NonOptimisationRiskMeasure

Represents the standardised Skewness risk measure.

Skewness computes the third standardised central moment (skewness) of portfolio returns. Positive skewness is preferred (the distribution is skewed towards more positive values), so bigger_is_better returns true for this measure.

Mathematical definition

Let $\mu$ be the specified centre, $\delta_t = x_t - \mu$, and $\sigma$ the standard deviation of returns. The skewness is:

\[\begin{align} \mathrm{Skew}(\boldsymbol{x}) &= \frac{1}{T \sigma^3} \sum_{t=1}^{T} \delta_t^3\,. \end{align}\]

Where:

  • $\mathrm{Skew}(\boldsymbol{x})$: Standardised skewness of portfolio returns. The w field replaces $1/T$ with a weighted average when it holds observation weights.
  • $\boldsymbol{x}$: Portfolio returns vector $T \times 1$.
  • $T$: Number of observations.
  • $\mu$: Specified centre of the distribution.
  • $\delta_t = x_t - \mu$: Centred deviation at period $t$.
  • $\sigma$: Standard deviation of returns, computed by ve. Its corrected field sets the divisor.

Fields

  • settings: Risk measure settings.
  • ve: Variance estimator.
  • sk: Optional coskewness matrix assets × assets^2. Also admits a Deferred Quantity — a coskewness estimator or a prior estimator that computes the matrix against the optimisation's own prior, at factory time (see SkSlot and resolve_deferred_quantities). A coskewness estimator supplies mu as well, from its own me, so that the tensor and the centre it was taken about come out of one object. If nothing, the prior supplies it.
  • w: Optional observation weights vector observations × 1, or a concrete subtype of DynamicAbstractWeights. If nothing, the computation is unweighted.
  • mu: Optional centre the moment is taken about, a scalar or a vector assets × 1. Also admits a Deferred Quantity — an expected returns estimator or a prior estimator that computes the centre against the optimisation's own prior, at factory time (see MuSlot and resolve_deferred_quantities). If nothing, the prior supplies it.
  • pe: Optional prior estimator that fills every prior-derived slot the measure leaves unstated, from a single fit. A stated slot wins. See resolve_deferred_quantities.

Constructors

Skewness(;    settings::MaxRiskMeasureSettings = MaxRiskMeasureSettings(),    ve::AbstractVarianceEstimator = SimpleVariance(),    sk::Option{<:SkSlot} = nothing,    w::Option{<:ObsWeights} = nothing,    mu::Option{<:MuSlot} = nothing,    pe::Option{<:AbstractPriorEstimator} = nothing) -> Skewness

Keywords correspond to the struct's fields.

Validation

  • If sk is not nothing: !isempty(sk) and size(sk, 1)^2 == size(sk, 2).
  • If mu is a VecNum: !isempty(mu).
  • If w is not nothing: !isempty(w).
Warning

mu and sk are stated independently, so nothing makes them agree with each other. A caller who wants one consistent set names pe alone and lets it fill both from a single fit. A caller who states them by hand must make sure that they agree.

Info

sk also admits a CoskewnessEstimator or an AbstractPriorEstimator, and mu an AbstractExpectedReturnsEstimator or an AbstractPriorEstimator. Either is resolved against the optimisation's own prior — see resolve_deferred_quantities. A coskewness estimator in sk also supplies mu from its own me, so that the tensor and the centre it was taken about come out of one object. A deferred slot wins over pe.

Functor

(r::Skewness)(w::VecNum, X::MatNum, fees::Option{<:Fees} = nothing)(r::Skewness)(x::VecNum)

Computes the skewness of the portfolio returns. The second arity takes a precomputed portfolio return series and skips the weighting step.

Arguments

  • w: Portfolio weights vector assets × 1.
  • X::MatNum: Asset returns matrix ($T \times N$).
  • fees: Fees estimator or result.

Examples

julia> Skewness()Skewness  settings ┼ MaxRiskMeasureSettings           │   scale ┼ Float64: 1.0           │      lb ┼ nothing           │     rke ┴ Bool: true        ve ┼ SimpleVariance           │          me ┼ SimpleExpectedReturns           │             │   w ┴ nothing           │           w ┼ nothing           │   corrected ┴ Bool: true        sk ┼ nothing         w ┼ nothing        mu ┼ nothing        pe ┴ nothing

Related

References

  • [116] D. Cajas. Semidefinite Relaxation of Higher Portfolio Moments. Available at SSRN 5284483 (2025).
source
PortfolioOptimisers.VarianceSkewKurtosisType
struct VarianceSkewKurtosis{__T_settings, __T_vr, __T_sk, __T_kt, __T_pe} <: RiskMeasure

Composite risk measure combining variance, skewness, and kurtosis into a single expression.

VarianceSkewKurtosis encodes the joint SDP formulation $\sigma^2 - \mathrm{Skew} + \kappa$ where each component has its own scale weight. The skewness term is subtracted because higher skewness is preferable.

Mathematical definition

\[\begin{align} \mathcal{R}(\boldsymbol{w}) &= s_{\sigma^2}\,\mu_2(\boldsymbol{w}) - s_{\mathrm{sk}}\,\mu_3(\boldsymbol{w}) + s_{\kappa}\,\mu_4(\boldsymbol{w})\,, \\ \mu_2(\boldsymbol{w}) &= \boldsymbol{w}^\intercal \mathbf{\Sigma} \boldsymbol{w}\,, \\ \mu_3(\boldsymbol{w}) &= \boldsymbol{w}^\intercal \mathbf{M}_3 \left(\boldsymbol{w} \otimes \boldsymbol{w}\right)\,, \\ \mu_4(\boldsymbol{w}) &= \left(\boldsymbol{w} \otimes \boldsymbol{w}\right)^\intercal \mathbf{M}_4 \left(\boldsymbol{w} \otimes \boldsymbol{w}\right)\,. \end{align}\]

Where:

  • $\boldsymbol{w}$: Portfolio weights vector $N \times 1$.
  • $\mu_2, \mu_3, \mu_4$: Raw central portfolio moments of order two, three and four. The skewness is not standardised and the kurtosis is not square-rooted.
  • $\mathbf{\Sigma}, \mathbf{M}_3, \mathbf{M}_4$: Covariance, coskewness and cokurtosis matrices, held by vr, sk and kt.
  • $s_{\sigma^2},\, s_{\mathrm{sk}},\, s_{\kappa}$: Respective scale factors from each sub-measure's settings.
  • $\otimes$: Kronecker product.

The functor and the JuMP model compute this same quantity from these same matrices. They differ only by the gap of the semidefinite relaxation, which [116] states is tight over a range of skewness values and not beyond it.

Fields

  • settings: Risk measure settings.
  • vr: Variance risk measure component.
  • sk: Skewness risk measure component.
  • kt: Kurtosis risk measure component.
  • pe: Optional prior estimator that fills every prior-derived slot the measure leaves unstated, from a single fit. A stated slot wins. See resolve_deferred_quantities.

Constructors

VarianceSkewKurtosis(;    settings::RiskMeasureSettings = RiskMeasureSettings(),    vr::Variance = Variance(),    sk::Skewness = Skewness(),    kt::Kurtosis = Kurtosis(),    pe::Option{<:AbstractPriorEstimator} = nothing) -> VarianceSkewKurtosis

Keywords correspond to the struct's fields.

Warning

The three children each state their quantities independently, so nothing makes sigma, sk and kt agree with each other. A caller who wants one consistent set names pe on the container alone and lets it fill all three from a single fit. A child that names its own quantity keeps it, and the pe fills only what is left.

Info

The constructor passes vr, sk and kt through no_risk_expr_risk_measure, so a child never registers a risk expression of its own. This is why the children show rke ┴ Bool: false below.

Propagated parameters

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

  • vr: Recursively updated via factory.
  • sk: Recursively updated via factory.
  • kt: 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:

JuMP Formulation

The JuMP model is the semidefinite relaxation of [116], equations 11 to 14. It relaxes the Kronecker products of the weights into the blocks of one positive semidefinite matrix, and reads each moment off a block with the trace operator.

\[\begin{align} \mathbf{M}^{(4)*} &= \begin{bmatrix} k & \boldsymbol{w}^\intercal & \left(\mathbf{L}_2 \mathrm{vec}(\mathbf{W}_1)\right)^\intercal \\ \boldsymbol{w} & \mathbf{W}_1 & \mathbf{W}_2^\intercal \\ \mathbf{L}_2 \mathrm{vec}(\mathbf{W}_1) & \mathbf{W}_2 & \mathbf{W}_3 \end{bmatrix} \succeq 0\,, \\ \mathcal{R}(\boldsymbol{w}) &= s_{\sigma^2} \mathrm{Tr}\left(\mathbf{\Sigma} \mathbf{W}_1\right) - s_{\mathrm{sk}} \mathrm{Tr}\left(\mathbf{M}_3 \mathbf{D}_2 \mathbf{W}_2\right) + s_{\kappa} \mathrm{Tr}\left(\mathbf{S}_2 \mathbf{M}_4 \mathbf{S}_2^\intercal \mathbf{W}_3\right)\,. \end{align}\]

Where:

  • $\boldsymbol{w}$: Portfolio weights vector $N \times 1$.
  • $k$: Homogenisation variable of the model.
  • $\mathbf{W}_1, \mathbf{W}_2, \mathbf{W}_3$: Relaxation blocks standing for $\boldsymbol{w}\boldsymbol{w}^\intercal$, $(\boldsymbol{w} \otimes \boldsymbol{w})\boldsymbol{w}^\intercal$ and $(\boldsymbol{w} \otimes \boldsymbol{w})(\boldsymbol{w} \otimes \boldsymbol{w})^\intercal$.
  • $\mathbf{\Sigma}, \mathbf{M}_3, \mathbf{M}_4$: Covariance, coskewness and cokurtosis matrices, from vr, sk and kt.
  • $\mathbf{D}_2, \mathbf{L}_2, \mathbf{S}_2$: Duplication, elimination and summation matrices.
  • $s_{\sigma^2},\, s_{\mathrm{sk}},\, s_{\kappa}$: Respective scale factors from each sub-measure's settings.

The skewness term takes a lower bound, because a larger skewness is preferable. The other two take upper bounds.

Info

A relaxation block stands in for an exact Kronecker product, so the model's value carries the relaxation gap. The functor reads the moments from the matrices directly and carries no gap. The two agree to the width of that gap.

Functor

(r::VarianceSkewKurtosis)(w::VecNum, X::MatNum, fees::Option{<:Fees} = nothing)

Computes the composite of equation 12 of [116] from vr.sigma, sk.sk and kt.kt. X and fees take part in no term. The moments are pinned by the matrices, and a central moment does not move when fees shifts every observation by the same constant.

Arguments

  • w: Portfolio weights vector assets × 1.
  • X::MatNum: Asset returns matrix ($T \times N$).
  • fees: Fees estimator or result.

Examples

julia> r = VarianceSkewKurtosis()VarianceSkewKurtosis  settings ┼ RiskMeasureSettings           │   scale ┼ Float64: 1.0           │      ub ┼ nothing           │     rke ┴ Bool: true        vr ┼ Variance           │   settings ┼ RiskMeasureSettings           │            │   scale ┼ Float64: 1.0           │            │      ub ┼ nothing           │            │     rke ┴ Bool: false           │      sigma ┼ nothing           │       chol ┼ nothing           │         rc ┼ nothing           │        alg ┴ SquaredSOCRiskExpr()        sk ┼ Skewness           │   settings ┼ MaxRiskMeasureSettings           │            │   scale ┼ Float64: 1.0           │            │      lb ┼ nothing           │            │     rke ┴ Bool: false           │         ve ┼ SimpleVariance           │            │          me ┼ SimpleExpectedReturns           │            │             │   w ┴ nothing           │            │           w ┼ nothing           │            │   corrected ┴ Bool: true           │         sk ┼ nothing           │          w ┼ nothing           │         mu ┼ nothing           │         pe ┴ nothing        kt ┼ Kurtosis           │   settings ┼ RiskMeasureSettings           │            │   scale ┼ Float64: 1.0           │            │      ub ┼ nothing           │            │     rke ┴ Bool: false           │          w ┼ nothing           │         mu ┼ nothing           │         kt ┼ nothing           │          N ┼ nothing           │       alg1 ┼ FullMoment()           │       alg2 ┼ SOCRiskExpr()           │         pe ┴ nothing        pe ┴ nothing

Related

References

  • [116] D. Cajas. Semidefinite Relaxation of Higher Portfolio Moments. Available at SSRN 5284483 (2025).
source
PortfolioOptimisers.port_opt_viewMethod
port_opt_view(
    r::Skewness,
    i,
    args...
) -> Skewness{MaxRiskMeasureSettings{__T_scale, __T_lb, __T_rke}, <:AbstractVarianceEstimator} where {__T_scale, __T_lb, __T_rke}

Return a view of Skewness r sliced to asset indices i.

Slices the expected returns mu for cluster-based optimisation. sk passes through: it is nothing, or it holds a Deferred Quantity, which crosses the view unresolved and then fits on the subset.

Related

source
PortfolioOptimisers.port_opt_viewMethod
port_opt_view(
    r::Skewness{<:Any, <:Any, <:AbstractMatrix{<:Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}}},
    i,
    args...
) -> Skewness{MaxRiskMeasureSettings{__T_scale, __T_lb, __T_rke}, <:AbstractVarianceEstimator} where {__T_scale, __T_lb, __T_rke}

Return a view of Skewness r sliced to asset indices i, also slicing the coskewness matrix sk.

Related

source
PortfolioOptimisers.no_bounds_no_risk_expr_risk_measureMethod
no_bounds_no_risk_expr_risk_measure(
    r::Skewness
) -> Skewness{MaxRiskMeasureSettings{Int64, Nothing, Bool}, <:AbstractVarianceEstimator}
no_bounds_no_risk_expr_risk_measure(
    r::Skewness,
    
) -> Skewness{MaxRiskMeasureSettings{Int64, Nothing, Bool}, <:AbstractVarianceEstimator}

Return a copy of Skewness r with rke = false and lb = nothing, removing bounds and disabling its contribution to the JuMP objective expression.

Related

source
PortfolioOptimisers.factoryMethod
factory(
    r::VarianceSkewKurtosis,
    pr::AbstractPriorResult,
    args...;
    kwargs...
) -> VarianceSkewKurtosis{RiskMeasureSettings{__T_scale, __T_ub, __T_rke}, _A, Skewness{__T_settings, __T_ve, __T_sk, __T_w, __T_mu, __T_pe}, _B, Nothing} where {__T_scale, __T_ub, __T_rke, _A, __T_settings, __T_ve, __T_sk, __T_w, __T_mu, __T_pe, _B}

Create an instance of VarianceSkewKurtosis by fanning pe out over its three children, then threading pr into each of them.

The container holds no quantity of its own, so @fprop alone would reach the children and leave pe standing — the measure would say one thing and compute another. This method resolves first, which is the same order the JuMP path already uses in set_risk_constraints!.

Related

source

References

[5]
D. Cajas. Advanced Portfolio Optimization: A Cutting-edge Quantitative Approach (Springer Nature Switzerland, 2025).
[116]
D. Cajas. Semidefinite Relaxation of Higher Portfolio Moments. Available at SSRN 5284483 (2025).