Expected Risk

PortfolioOptimisers.resolve_risk_inputsFunction
resolve_risk_inputs(r::BaseRM_VecBaseRM, X::MatNum_Pr)

Turn a value-level data argument into the pair a kernel takes: the measure to evaluate, and the returns matrix to evaluate it on.

A prior result resolves the measure through factory — a Deferred Quantity becomes a value, an unstated slot takes the prior's field — and hands back pr.X. A ReturnsResult carries no moments, so it only unwraps its X. A matrix is already the pair.

Resolution happens once per entry point rather than once per evaluation, which is what keeps risk_contribution from refitting a deferred covariance 2N times.

Related

source
PortfolioOptimisers.original_returnsFunction
original_returns(X::MatNum_Pr)

Take the returns matrix the caller supplied out of whichever carrier holds it.

A prior result answers pr.original_X, a ReturnsResult answers its X, and a matrix answers itself. The three arms agree off a factor route, where pr.original_X === pr.X, and differ on one, where pr.X is the reconstruction F * transpose(M) .+ transpose(b).

This is the read resolve_factor_risk_inputs takes, and it is deliberately not the read resolve_risk_inputs takes. expected_risk evaluates the return distribution the prior asserts, which is pr.X. A factor attribution partitions risk into a factor part and a residual part, and the reconstruction has no residual, so it can only attribute noise to the second.

Arguments

  • X::MatNum_Pr: Returns matrix, prior result, or returns result.

Returns

  • X::MatNum: The returns matrix the caller supplied.

Related

source
PortfolioOptimisers.resolve_factor_risk_inputsFunction
resolve_factor_risk_inputs(r::BaseRM_VecBaseRM, X::MatNum_Pr)

Turn a value-level data argument into the pair a factor attribution takes: the measure to evaluate, and the returns matrix to evaluate it on.

The sibling of resolve_risk_inputs, and it differs in the second half only. The measure resolves the same way, so a Deferred Quantity is still fitted once rather than once per finite difference. The matrix is original_returns rather than pr.X.

Two seams and not one argument, because the two answers are both correct and neither is a default of the other. Every other caller of resolve_risk_inputs wants the distribution the prior asserts.

Related

source
PortfolioOptimisers.resolve_factor_regressionFunction
resolve_factor_regression(re::RegE_Reg, rd::ReturnsResult,
                          pr::Option{<:AbstractPriorResult} = nothing)

Pick the factor loadings a factor attribution decomposes against, from the three carriers that can supply them.

The precedence is fixed, and it is not a source selector:

  1. re when it is already a Regression result. A precomputed result is the caller stating the answer, and it needs no data.
  2. pr.rr when the prior carries a factor block. The loadings are then the ones fitted on pr.original_X, which is the matrix the risk is measured on, so the pair is matched by construction.
  3. regression(re, rd) otherwise, which needs rd.X and rd.F.
Warning

A stated regression estimator loses to a prior that carries loadings. re is honoured only when the prior has none. Pass the loadings as a precomputed Regression to override a factor prior, or pass the returns matrix rather than the prior to keep the refit.

Arguments

  • re::RegE_Reg: Regression result or estimator.
  • rd::ReturnsResult: Returns result carrying X and F.
  • pr::Option{<:AbstractPriorResult}: Prior result, or nothing when the caller passed a bare matrix.

Validation

  • When none of the three arms applies, throws an IsNothingError naming all three.

Returns

  • rr::AbstractRegressionResult: The factor loadings.

Related

source
PortfolioOptimisers.expected_riskFunction
expected_risk(r, args...; kwargs...)

Compute the expected value of a risk measure.

Generic function extended by concrete risk measure types. Each method computes the risk value associated with its risk measure type, given a portfolio (or its return distribution).

Related

source
PortfolioOptimisers.expected_risk_from_returnsMethod
expected_risk_from_returns(r::AbstractBaseRiskMeasure, X::VecNum; kwargs...) -> Number

Contract entry for evaluating a risk measure on an already-reduced net-return series X (ADR 0007). Consults supports_precomputed_returns: for an eligible measure it returns r(X); for an ineligible one it throws an explanatory ArgumentError instead of silently consuming X as weights (a WeightsInput measure) or hitting an opaque MethodError (a moment measure with a per-asset mu).

Internal call sites that hold a precomputed series — cross-validation prediction scoring — route through here rather than calling the functor directly.

Related

source
PortfolioOptimisers.expected_risk_from_returnsMethod
expected_risk_from_returns(
    r::Union{AbstractBaseRiskMeasure, AbstractVector{<:AbstractBaseRiskMeasure}},
    X::AbstractVector{<:AbstractVector{<:Union{var"#s89", var"#s88"} where {var"#s89"<:Number, var"#s88"<:AbstractJuMPScalar}}};
    kwargs...
) -> Any

Evaluate a risk measure on each element of a vector of precomputed return series.

Maps expected_risk_from_returns over each Xi in X.

Related

source
PortfolioOptimisers.number_effective_assetsFunction
number_effective_assets(w::VecNum)

Compute the effective number of assets (Herfindahl-Hirschman inverse index).

Mathematical definition

\[\begin{align} N_{\mathrm{eff}} &= \frac{1}{\sum_i w_i^2}\,. \end{align}\]

Where:

  • $N_{\mathrm{eff}}$: Effective number of assets.
  • $\boldsymbol{w}$: Portfolio weights vector $N \times 1$.

Returns the number of equally-weighted assets that would produce the same level of concentration as the given weight vector w.

Arguments

  • w::VecNum: Portfolio weight vector.

Returns

  • Number: Effective number of assets.

Related

source
PortfolioOptimisers.adjusted_riskFunction
adjusted_risk(sca::Scalariser, r::BaseRM_VecBaseRM, w::VecNum, X::MatNum,
              fees::Option{<:Fees}, delta::Number; kwargs...)

Evaluate the risk at w with the homogeneity correction already applied, for one measure or several.

The internal seam that lets risk_contribution keep one body across the multiplicity. It exists because the correction cannot be applied to the aggregate.

adjust_risk_contribution is a homogeneity correction: it divides by the measure's own degree, so that Σᵢ wᵢ·rcᵢ recovers the measure's value by Euler's identity. A mixed vector such as [Variance(), ConditionalValueatRisk()] is a sum of a degree-2 and a degree-1 function, so it has no single degree and adjusting the aggregate is not merely awkward but impossible.

Adjusting each element before the scalariser restores the identity exactly:

Σᵢ wᵢ·rcᵢ  =  Σₖ sₖ·aₖ·Σᵢ wᵢ·∂ρₖ/∂wᵢ  =  Σₖ sₖ·aₖ·degₖ·ρₖ  =  Σₖ sₖ·ρₖ

which is expected_risk(rs, w, X, fees) under SumScalariser. The invariant survives an arbitrary mixture of homogeneity degrees, and it survives only because the correction sits inside the loop.

sca is inert on a single measure and scale is inert on a single measure, exactly as they are in expected_risk.

Related

source
PortfolioOptimisers.risk_contributionFunction
risk_contribution(
    r::BaseRM_VecBaseRM,
    w::VecNum,
    X::MatNum_Pr,
    fees::Option{<:Fees} = nothing;
    delta::Number = 1e-6,
    marginal::Bool = false,
    sca::Scalariser = SumScalariser(),
    kwargs...
) -> Vector

Compute the risk contribution of each asset to the total portfolio risk using numerical differentiation.

Mathematical definition

The risk contribution of asset $i$ is defined as:

\[\begin{align} \mathrm{RC}_i &= w_i \cdot \frac{\partial \rho(\boldsymbol{w})}{\partial w_i}\,. \end{align}\]

Where:

  • $\mathrm{RC}_i$: Risk contribution of asset $i$.
  • $\boldsymbol{w}$: Portfolio weights vector $N \times 1$.
  • $\rho$: Portfolio risk measure.
  • $w_i$: Weight of asset $i$.

The partial derivative is approximated using a two-sided finite difference with step size delta. When marginal = true, the function omits the weighting by $w_i$ (i.e., only the marginal risk $\partial \rho / \partial w_i$ is returned).

Arguments

  • r::BaseRM_VecBaseRM: Risk measure to differentiate, or a vector of them.
  • w::VecNum: Portfolio weights vector.
  • X::MatNum_Pr: Asset returns matrix or prior result.
  • fees::Option{<:Fees}: Optional fee structure.

Keyword Arguments

  • delta::Number = 1e-6: Finite difference step size.
  • marginal::Bool = false: If true, returns marginal risk contributions (without $w_i$ weighting).
  • sca::Scalariser = SumScalariser(): Scalariser combining a vector r. Inert on a single measure.

Returns

  • Vector: Risk contributions (or marginal risks) for each asset.

Details

  • A prior result resolves the measure once, before the loop (resolve_risk_inputs), so a Deferred Quantity is fitted once rather than once per finite difference.
  • A vector of measures differentiates the aggregate, which is the figure expected_risk reports. The homogeneity correction is applied per element inside the loop (adjusted_risk), so Σᵢ wᵢ·rcᵢ recovers the aggregate exactly even when the elements have different homogeneity degrees.
Warning

All four scalarisers are admitted, and MaxScalariser and MinScalariser are exact almost everywhere. Wherever the argmax is unique the aggregate's decomposition is the winning element's own, scaled. The figure degrades only at a near-exact tie between two scaled measures, where the argmax can flip between the w+δ and w−δ points and an asset's figure becomes a chord across the kink. At such a point the subgradient is genuinely a set, so no answer is uniquely correct.

Related

source
PortfolioOptimisers.factor_risk_contributionFunction
factor_risk_contribution(
    r::BaseRM_VecBaseRM,
    w::VecNum,
    X::MatNum_Pr,
    fees::Option{<:Fees} = nothing;
    re::RegE_Reg = StepwiseRegression(),
    rd::ReturnsResult = ReturnsResult(),
    delta::Number = 1e-6,
    kwargs...
) -> Vector

Compute the risk contribution of each factor (and the idiosyncratic component) to the total portfolio risk using a factor regression.

Mathematical definition

The factor risk contributions partition total portfolio risk into factor-specific components using the Brinson attribution framework:

\[\begin{align} \mathrm{FRC}_k &= (\mathbf{B}^\intercal \boldsymbol{w})_k \cdot (\mathbf{B}^{-\intercal} \nabla \rho)_k\,. \end{align}\]

Where:

  • $\mathrm{FRC}_k$: Risk contribution of factor $k$.
  • $\boldsymbol{w}$: Portfolio weights vector $N \times 1$.
  • $\mathbf{B}$: Factor loading matrix $N \times K$, estimated by regression.
  • $\nabla \rho$: Gradient of the risk measure with respect to the weights.

Arguments

  • r::BaseRM_VecBaseRM: Risk measure to decompose, or a vector of them.
  • w::VecNum: Portfolio weights vector.
  • X::MatNum_Pr: Asset returns matrix or prior result.
  • fees::Option{<:Fees}: Optional fee structure.

Keyword Arguments

  • re::RegE_Reg = StepwiseRegression(): Regression estimator for factor loadings.
  • rd::ReturnsResult = ReturnsResult(): Returns result providing factor data.
  • delta::Number = 1e-6: Finite difference step size.

Returns

  • Vector: Risk contributions for each factor, with the last element being the idiosyncratic (off-factor) contribution.

Details

  • The gradient is taken on original_returns — the returns the caller supplied — and not on pr.X (resolve_factor_risk_inputs). The two differ under a factor prior, where pr.X is the reconstruction F * transpose(M) .+ transpose(b). That matrix has rank size(F, 2) and carries no residual, so the off-factor term of a series-reducing measure reports the intercept's share rather than idiosyncratic risk, and can come out negative.
  • A consequence: under a factor prior the parts sum to the risk on the caller's returns, and not to expected_risk(r, w, pr). A measure whose kernel reads a moment rather than the series — Variance, StandardDeviation, DistributionValueatRisk — is unaffected either way, because it never reduces the returns matrix.
  • The loadings come from resolve_factor_regression, which prefers the prior's own rr over a refit, so the loadings and the returns are the pair the prior was fitted on. A stated regression estimator therefore loses to a prior that carries a factor block.
  • A prior result resolves the measure once, before the loop (resolve_factor_risk_inputs), so a Deferred Quantity is fitted once rather than once per finite difference.

Related

source
PortfolioOptimisers.rolling_window_measureFunction
rolling_window_measure(
    r::Union{AbstractBaseRiskMeasure, AbstractVector{<:AbstractBaseRiskMeasure}},
    w::AbstractVector{<:Union{var"#s89", var"#s88"} where {var"#s89"<:Number, var"#s88"<:AbstractJuMPScalar}},
    X::AbstractMatrix{<:Union{var"#s89", var"#s88"} where {var"#s89"<:Number, var"#s88"<:AbstractJuMPScalar}},
    fees::Union{Nothing, Fees},
    window::Integer;
    sca,
    kwargs...
) -> Any

Compute the expected risk of a risk measure over rolling windows of the returns data.

Arguments

  • r::BaseRM_VecBaseRM: Risk measure to evaluate, or a vector of them.
  • w::VecNum: Portfolio weights vector.
  • X::MatNum: Asset returns matrix.
  • fees::Option{<:Fees}: Optional fee structure.
  • window::Integer: Size of the rolling window (number of periods).

Keyword Arguments

  • sca::Scalariser = SumScalariser(): Scalariser combining a vector r. Inert on a single measure.

Validation

  • 1 <= window <= size(X, 1), else a DomainError naming window.

The window is checked here rather than left to the risk kernel. A non-positive window indexes X out of bounds and surfaces as a bare BoundsError from inside whichever measure r names, and a window longer than the sample produces an empty vector of risks that reads as a legitimate result. Both are caller errors, so both are refused at the boundary — the same discipline plot_rolling_measure applies to its own rolling keyword.

Returns

  • risks::VecNum: Expected risk values for each rolling window.

Related

source