Expected Risk
PortfolioOptimisers.MatNum_Pr — Type
const MatNum_Pr = Union{<:MatNum, <:AbstractPriorResult, <:ReturnsResult}Union of matrix-like types accepted as the data argument in risk_contribution and related functions.
Related
PortfolioOptimisers.RkRatioRM — Type
const RkRatioRM = Union{<:RiskRatio, <:NonOptimisationRiskRatio}Union of all risk-ratio risk measures, where the expected risk is defined as the ratio of two component risk values.
Related
PortfolioOptimisers.resolve_risk_inputs — Function
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
PortfolioOptimisers.original_returns — Function
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
PortfolioOptimisers.resolve_factor_risk_inputs — Function
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
PortfolioOptimisers.resolve_factor_regression — Function
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:
rewhen it is already aRegressionresult. A precomputed result is the caller stating the answer, and it needs no data.pr.rrwhen the prior carries a factor block. The loadings are then the ones fitted onpr.original_X, which is the matrix the risk is measured on, so the pair is matched by construction.regression(re, rd)otherwise, which needsrd.Xandrd.F.
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 carryingXandF.pr::Option{<:AbstractPriorResult}: Prior result, ornothingwhen the caller passed a bare matrix.
Validation
- When none of the three arms applies, throws an
IsNothingErrornaming all three.
Returns
rr::AbstractRegressionResult: The factor loadings.
Related
PortfolioOptimisers.expected_risk — Function
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
PortfolioOptimisers.expected_risk_from_returns — Function
expected_risk_from_returns(r, X; kwargs...)Compute the expected risk of a measure from a precomputed net-return series.
Generic function extended by concrete risk measure types that support the precomputed-returns contract. Only measures with supports_precomputed_returns(r) == true should implement this method.
Related
PortfolioOptimisers.supports_precomputed_returns — Method
supports_precomputed_returns(
r::Union{NonOptimisationRiskRatio, RiskRatio}
) -> Any
Return whether RkRatioRM r supports evaluation on a precomputed return series.
Returns true only when both constituent risk measures support precomputed returns.
Related
PortfolioOptimisers.supports_precomputed_returns — Method
supports_precomputed_returns(r::MeanReturnRiskRatio) -> Any
Return whether MeanReturnRiskRatio r supports evaluation on a precomputed return series.
Returns true only when both the return measure rt and the risk measure rk support precomputed returns.
Related
PortfolioOptimisers.expected_risk_from_returns — Method
expected_risk_from_returns(r::AbstractBaseRiskMeasure, X::VecNum; kwargs...) -> NumberContract 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
PortfolioOptimisers.expected_risk_from_returns — Method
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
PortfolioOptimisers.number_effective_assets — Function
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
PortfolioOptimisers.adjusted_risk — Function
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
PortfolioOptimisers.risk_contribution — Function
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...
) -> VectorCompute 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: Iftrue, returns marginal risk contributions (without $w_i$ weighting).sca::Scalariser = SumScalariser(): Scalariser combining a vectorr. 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_riskreports. 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.
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
PortfolioOptimisers.factor_risk_contribution — Function
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...
) -> VectorCompute 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 onpr.X(resolve_factor_risk_inputs). The two differ under a factor prior, wherepr.Xis the reconstructionF * transpose(M) .+ transpose(b). That matrix has ranksize(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 ownrrover 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
PortfolioOptimisers.rolling_window_measure — Function
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 vectorr. Inert on a single measure.
Validation
1 <= window <= size(X, 1), else aDomainErrornamingwindow.
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