X at Risk: private API

PortfolioOptimisers.ValueatRiskFormulationType
abstract type ValueatRiskFormulation <: AbstractAlgorithm

Abstract supertype for all Value-at-Risk formulation algorithms.

The formulation selects the estimand, not only the encoding. MIPValueatRisk reports the empirical quantile of the sample, and DistributionValueatRisk reports the quantile of a fitted parametric distribution. The two are different numbers on the same data, and a measure that holds one reports that one in its optimisation model and in its functor alike.

All concrete and/or abstract types representing the formulation for computing Value-at-Risk (e.g., mixed-integer programming, distribution-based) should be subtypes of ValueatRiskFormulation.

Related

source
PortfolioOptimisers.compute_value_at_risk_zFunction
compute_value_at_risk_z(
    dist::Distributions.Normal,
    alpha::Number
) -> Any

Compute the lower-tail z-score for a parametric VaR at significance level alpha.

Returns the complementary quantile for Normal and scaled Student-t distributions, and the closed-form expression for the Laplace distribution.

Arguments

  • dist: Distribution instance (Normal, TDist, or Laplace).
  • alpha::Number: Significance level.

Returns

  • z::Number: Lower-tail z-score for the parametric VaR.

Related

source
PortfolioOptimisers.compute_value_at_risk_czFunction
compute_value_at_risk_cz(
    dist::Distributions.Normal,
    alpha::Number
) -> Any

Compute the upper-tail z-score for a parametric VaR at significance level alpha.

Used for the high (upper) bound in VaR range constraints. Returns the lower quantile for Normal and scaled Student-t distributions, and the closed-form expression for Laplace.

Arguments

  • dist: Distribution instance (Normal, TDist, or Laplace).
  • alpha::Number: Significance level.

Returns

  • z::Number: Upper-tail z-score for the parametric VaR.

Related

source
PortfolioOptimisers.resolve_deferred_quantitiesMethod
resolve_deferred_quantities(x, ) -> StandardDeviation
resolve_deferred_quantities(x, , ) -> StandardDeviation

Resolve every Deferred Quantity held by x against prior result pr, returning a struct of the same type whose deferred slots hold plain values.

This resolves the deferred state and nothing else. A slot left unstated stays nothing, so whichever fallback the consumer already applies — sel on the factory path, chol_sigma_selector and its siblings on the JuMP path — keeps working unchanged. The two paths are separate: a JuMP model builder reads the risk measure's slots directly and never calls factory, so both entry points resolve.

Given a prior result the rule has two halves. Container recursion is derived from deferred_slots, so a type that only holds children needs no method at all. A type that resolves a quantity of its own defines a method, which overrides the derived one. Writing that half per type — rather than per field — is what lets slots that travel together be resolved together: a deferred sigma supplies chol from the same fit, so the pair is never mixed across two sources.

slv is the effective solver, and it is what a Calibration Rule in the same struct reads. It carries the value the optimisation settled on, so a rule resolves against one solver on both routes. On the factory route the @cprop selection has already put that solver on the struct, so the argument stays at its default. On the JuMP route no selection runs, so set_risk_constraints! reads the solver off the estimator and threads it here. A type that carries a solver of its own settles it locally as sel(x.slv, slv), beside the observation weights it already settles that way, and a type that carries none gives its rules none on either route.

Algorithm

  1. Return x unchanged. This method is the arm for a second argument that is not a prior result: with no prior in hand nothing can be fitted, so the deferred state travels on.

A more specific method dominates this one on a prior result: the one that deferred_slots derives for a container, and the hand-written one of a type that resolves a quantity of its own.

Related

source
resolve_deferred_quantities(x, pr::AbstractPriorResult, slv = nothing)

Resolve the children that deferred_slots declared and the slots that calibration_slots declared, and return x itself when none of them changed.

This is the derived half of the resolution rule. A container declares its children once and both entry points follow: factory reaches them through @fprop, and the JuMP builders reach them through this method. Neither needs a forwarding method per container.

A type that resolves a quantity of its own overrides this with its own method, which is more specific. So the derivation carries container recursion alone, and never guesses how a matrix, a tensor or the centre a moment was taken about comes out of a fit.

Both channels end in one rebuild: a measure that carries both kinds of slot must not be rebuilt twice. resolve_calibration_slots states the calibration half and returns its resolved slots rather than a rebuilt object, and the two answers merge here. The deferred half merges last, so it wins a key both channels declare. A container names one child in both, and the child the recursion resolved is the one to keep.

slv is the effective solver, and the recursion threads it to every child. A container states no solver of its own, so it changes none: each child settles the one it was handed against the one it carries.

Algorithm

  1. Read the slots x declares with deferred_slots, giving slots.
  2. Read the resolved calibration slots with resolve_calibration_slots, giving calibrated.
  3. Return x unchanged when both are empty. A type with neither kind of slot needs no method of its own.
  4. Resolve every entry of slots with resolve_deferred_child, threading pr and slv to each, giving resolved.
  5. Refuse a slot the recursion left unresolved with assert_declared_slot_resolver.
  6. Hand merge(calibrated, resolved) to rebuild_with_slots, which returns x itself when no entry moved and a rebuilt copy when one did.

Returns

  • x itself when no slot moved, and a rebuilt copy of x when one did.

Related

source
resolve_deferred_quantities(
    x::ValueatRisk,
    pr::AbstractPriorResult
) -> ValueatRisk
resolve_deferred_quantities(
    x::ValueatRisk,
    pr::AbstractPriorResult,
    slv
) -> ValueatRisk

Resolve the significance level alpha of a ValueatRisk against prior result pr, and resolve the formulation alg beside it.

alpha takes a Calibration Rule in place of the number, so it resolves here. The rebuild goes through rebuild_with_slots, and the inner constructor it calls re-runs 0 < alpha < 1 on the calibrated number: a rule that returns a value the slot does not admit is refused at fold time, by the guard a caller's own number meets.

This method is more specific than the derived recursion, so it takes over the alg slot that deferred_slots declares. It resolves that slot through resolve_deferred_child, which is the verb the derivation would have used.

The effective observation weights are computed locally as sel(x.w, pr.w) and threaded to the rule. The measure carries no solver of its own, so it hands the rule the one it was given.

Related

source
PortfolioOptimisers.resolve_deferred_quantitiesMethod
resolve_deferred_quantities(x, ) -> StandardDeviation
resolve_deferred_quantities(x, , ) -> StandardDeviation

Resolve every Deferred Quantity held by x against prior result pr, returning a struct of the same type whose deferred slots hold plain values.

This resolves the deferred state and nothing else. A slot left unstated stays nothing, so whichever fallback the consumer already applies — sel on the factory path, chol_sigma_selector and its siblings on the JuMP path — keeps working unchanged. The two paths are separate: a JuMP model builder reads the risk measure's slots directly and never calls factory, so both entry points resolve.

Given a prior result the rule has two halves. Container recursion is derived from deferred_slots, so a type that only holds children needs no method at all. A type that resolves a quantity of its own defines a method, which overrides the derived one. Writing that half per type — rather than per field — is what lets slots that travel together be resolved together: a deferred sigma supplies chol from the same fit, so the pair is never mixed across two sources.

slv is the effective solver, and it is what a Calibration Rule in the same struct reads. It carries the value the optimisation settled on, so a rule resolves against one solver on both routes. On the factory route the @cprop selection has already put that solver on the struct, so the argument stays at its default. On the JuMP route no selection runs, so set_risk_constraints! reads the solver off the estimator and threads it here. A type that carries a solver of its own settles it locally as sel(x.slv, slv), beside the observation weights it already settles that way, and a type that carries none gives its rules none on either route.

Algorithm

  1. Return x unchanged. This method is the arm for a second argument that is not a prior result: with no prior in hand nothing can be fitted, so the deferred state travels on.

A more specific method dominates this one on a prior result: the one that deferred_slots derives for a container, and the hand-written one of a type that resolves a quantity of its own.

Related

source
resolve_deferred_quantities(x, pr::AbstractPriorResult, slv = nothing)

Resolve the children that deferred_slots declared and the slots that calibration_slots declared, and return x itself when none of them changed.

This is the derived half of the resolution rule. A container declares its children once and both entry points follow: factory reaches them through @fprop, and the JuMP builders reach them through this method. Neither needs a forwarding method per container.

A type that resolves a quantity of its own overrides this with its own method, which is more specific. So the derivation carries container recursion alone, and never guesses how a matrix, a tensor or the centre a moment was taken about comes out of a fit.

Both channels end in one rebuild: a measure that carries both kinds of slot must not be rebuilt twice. resolve_calibration_slots states the calibration half and returns its resolved slots rather than a rebuilt object, and the two answers merge here. The deferred half merges last, so it wins a key both channels declare. A container names one child in both, and the child the recursion resolved is the one to keep.

slv is the effective solver, and the recursion threads it to every child. A container states no solver of its own, so it changes none: each child settles the one it was handed against the one it carries.

Algorithm

  1. Read the slots x declares with deferred_slots, giving slots.
  2. Read the resolved calibration slots with resolve_calibration_slots, giving calibrated.
  3. Return x unchanged when both are empty. A type with neither kind of slot needs no method of its own.
  4. Resolve every entry of slots with resolve_deferred_child, threading pr and slv to each, giving resolved.
  5. Refuse a slot the recursion left unresolved with assert_declared_slot_resolver.
  6. Hand merge(calibrated, resolved) to rebuild_with_slots, which returns x itself when no entry moved and a rebuilt copy when one did.

Returns

  • x itself when no slot moved, and a rebuilt copy of x when one did.

Related

source
resolve_deferred_quantities(
    x::ValueatRiskRange,
    pr::AbstractPriorResult
) -> ValueatRiskRange
resolve_deferred_quantities(
    x::ValueatRiskRange,
    pr::AbstractPriorResult,
    slv
) -> ValueatRiskRange

Resolve the two significance levels of a ValueatRiskRange against prior result pr, and resolve the formulation alg beside them.

Each tail carries its own slot and its own bound, so a stated tail rule and a stated head rule resolve independently. beta defaults to alpha, so a rule stated on the loss side alone reaches both ends: the rule states the method and the slot states the end. The rebuild goes through rebuild_with_slots, whose positional call runs the inner constructor and re-runs both range checks on the calibrated numbers.

This method is more specific than the derived recursion, so it takes over the alg slot that deferred_slots declares, through resolve_deferred_child.

Related

source
PortfolioOptimisers.absolute_drawdown_vecFunction
absolute_drawdown_vec(x::VecNum) -> Vector

Compute the absolute drawdown series for a single-asset return vector.

Each element of the result is the difference between the current cumulative return and its running maximum (always ≤ 0).

The running maximum starts at zero, so the drawdown is measured against the initial portfolio value rather than against the first observation.

x is read, never written: the accumulator and the running peak are carried in scalars, so any AbstractVector works — a column view, a range, an immutable array.

Arguments

  • x::VecNum: Return series vector.

Returns

  • Vector: Drawdown vector of the same length as x.

Related

source
PortfolioOptimisers.relative_drawdown_vecMethod
relative_drawdown_vec(x)

Compute the relative drawdown vector for a vector of portfolio returns.

Returns the relative drawdown at each time step, computed as the current portfolio value relative to its running maximum.

The running maximum starts at one, so the drawdown is measured against the initial portfolio value rather than against the first observation.

x is read, never written: the compounding factor and the running peak are carried in scalars, so any AbstractVector works — a column view, a range, an immutable array.

Arguments

  • x: Vector of portfolio returns.

Returns

  • Relative drawdown vector.

Related

source
PortfolioOptimisers.drawdown_at_riskFunction
drawdown_at_risk(dd::VecNum, alpha::Real, ::Nothing) -> Number
drawdown_at_risk(dd::VecNum, alpha::Real, w::VecNum) -> Number

Aggregate a drawdown series into its Drawdown-at-Risk at level alpha.

This is the shared aggregation kernel behind DrawdownatRisk and RelativeDrawdownatRisk: the two measures differ only in the drawdown series they feed it (absolute_drawdown_vec and relative_drawdown_vec respectively), so the tail selection lives here once.

dd is consumed in place — the unweighted method reorders it via partialsort!. Callers pass a freshly computed drawdown vector.

Dispatch on the third argument selects the weighting scheme, so callers resolve observation weights with get_observation_weights and let dispatch do the rest.

  • ::Nothing: unweighted, the alpha-quantile of the drawdown series by rank.
  • w::VecNum: weighted, the drawdown at which the cumulative observation weight first reaches alpha.

Arguments

  • dd::VecNum: Drawdown series, all entries ≤ 0. Consumed in place.
  • alpha::Real: Significance level, 0 < alpha < 1.
  • w: Resolved observation weights, or nothing for the unweighted aggregation.

Returns

  • Number: Drawdown-at-Risk, returned as a positive loss.

Related

source