The source files can be found in user_guide/.
Risk measures
The previous page showed which optimiser to call. This page lists what you can ask it to minimise, the risk measure in its r field. The library has many risk measures, and a name does not always tell you what the measure is. Several well-known measures, such as the mean absolute deviation, the semi-variance and the Gini mean difference, are not types. Each is a setting of a generic type, and a short alias builds it.
This page is a reference. It answers three questions:
- What measures exist, and what does each penalise?
- Which optimisers accept it?
- What is its short alias, and what does that alias expand to?
We compute every table below from the types of the library and from supports_risk_measure, so the tables list what the optimisers accept. The one-line meanings are written by hand, and the docs build fails if a measure has none.
using PortfolioOptimisers, CSV, TimeSeries, DataFrames, PrettyTables, InteractiveUtils, StatsPlots, GraphRecipes1. How a measure is used
A risk measure has two uses.
Inside an optimiser, a measure is a configuration. You pass it to the r field, and the optimiser turns it into constraints and an objective term.
Outside an optimiser, a measure is an object that you call on a portfolio to get a number. expected_risk is one call for every measure. A measure takes one of three inputs: the net returns of the portfolio, the weights with the returns and the fees, or the weights alone. expected_risk gives each measure the input that it takes. We compute six measures on the equal-weighted portfolio.
X = TimeArray(CSV.File(joinpath(@__DIR__, "../examples/SP500.csv.gz")); timestamp = :Date)[(end - 252):end]rd = prices_to_returns(X)pr = prior(EmpiricalPrior(), rd)w = optimise(EqualWeighted(), rd).wmeasures = [SD(), MAD(), CVaR(), CDaR(), MDD(), UCI()]pretty_table(DataFrame("Measure" => ["StandardDeviation", "MAD (LowOrderMoment)", "ConditionalValueatRisk", "ConditionalDrawdownatRisk", "MaximumDrawdown", "UlcerIndex"], "Risk of the equal-weighted portfolio" => [expected_risk(factory(r, pr), w, pr.X) for r in measures]))┌───────────────────────────┬──────────────────────────────────────┐
│ Measure │ Risk of the equal-weighted portfolio │
│ String │ Float64 │
├───────────────────────────┼──────────────────────────────────────┤
│ StandardDeviation │ 0.0128283 │
│ MAD (LowOrderMoment) │ 0.00980733 │
│ ConditionalValueatRisk │ 0.0286097 │
│ ConditionalDrawdownatRisk │ 0.134511 │
│ MaximumDrawdown │ 0.147839 │
│ UlcerIndex │ 0.0613099 │
└───────────────────────────┴──────────────────────────────────────┘factory binds a measure to a prior. It fills sigma for Variance and StandardDeviation, and mu for the moment measures. It also gives the observation weights of the prior to the measures that take them, such as ConditionalValueatRisk. Without factory, such a measure gives every observation the same weight. The optimisers call factory on every measure, and you can call it on any measure. EntropicValueatRisk, RelativisticValueatRisk and their drawdown forms solve a subproblem to compute the risk. Before you call one of them outside an optimiser, put a Solver in its slv field.
If you give expected_risk the prior, as in expected_risk(r, w, pr), it calls factory for you. So you call factory yourself only when you want the bound measure. If you give it a returns matrix, and a field of the measure holds a DeferredQuantity, expected_risk throws an error, because it has no prior to compute the quantity from.
The fields sigma, mu, kt and sk each take a value or an estimator that computes it. The optimiser computes the estimator on the prior of each run, including each cross-validation fold and each resampled subset. The subset resampling example shows it.
2. The three usage classes
Each measure belongs to one of three classes, and the class sets where you can use it. The Optimisers column of every table below comes from the class:
| Class | Optimisers column | Meaning |
|---|---|---|
RiskMeasure | JuMP + clustering | Has a JuMP formulation, which is convex for most measures and mixed-integer for a few. You can use it in MeanRisk, RiskBudgeting, NearOptimalCentering, FactorRiskContribution and the clustering optimisers. |
HierarchicalRiskMeasure | clustering only | Has no JuMP formulation. Only a clustering optimiser can compute it, from the returns. MeanRisk throws a TypeError when you pass one. |
NonOptimisationRiskMeasure | diagnostic only | Is not a target of an optimisation. It is a quantity to report, such as ExpectedReturn or Skewness, or a ratio that scores a portfolio in cross-validation. |
The meta-optimisers, NestedClustered, Stacking and SubsetResampling, have no r of their own. Each accepts a measure only when every optimiser it holds accepts it, so the tables do not list them. Ask for the case you have:
supports_risk_measure(MeanRisk, ConditionalValueatRisk)supports_risk_measure(MeanRisk, EqualRisk)supported_risk_measures(HierarchicalRiskParity)The three calls return true, false and OptimisationRiskMeasure. EqualRisk is a measure that only a clustering optimiser can use.
3. The catalogue
Each table gives the meaning of each measure in one line, its alias and its class. The tables group the measures by the part of the returns that they measure. Every name is exported and has a docstring. The docstrings are on the public API pages on risk measures. Each docstring gives the signature and the fields of its measure, and most also give references. ?ConditionalValueatRisk in the REPL shows the same docstring.
rm_alias = Dict{Symbol, String}()for n in names(PortfolioOptimisers) v = getfield(PortfolioOptimisers, n) if isa(v, Type) && v <: PortfolioOptimisers.AbstractBaseRiskMeasure && nameof(v) != n rm_alias[nameof(v)] = String(n) endendfunction usage_class(T) return if supports_risk_measure(MeanRisk, T) "JuMP + clustering" elseif supports_risk_measure(HierarchicalRiskParity, T) "clustering only" else "diagnostic only" endendcatalogue = ["Dispersion and moments" => [:Variance => "Portfolio variance from a covariance matrix, the default `r`.", :StandardDeviation => "Square root of the variance, in the units of the returns.", :UncertaintySetVariance => "Worst-case variance over an uncertainty set of covariance matrices.", :LowOrderMoment => "Generic low-order moment measure, which includes the mean absolute deviation. Section 4 lists its aliases.", :HighOrderMoment => "Generic third and fourth moment measure. Section 4 lists its aliases.", :MedianAbsoluteDeviation => "Median absolute deviation, a robust counterpart of `MAD()`.", :Kurtosis => "Square root of the fourth central moment of the portfolio returns.", :NegativeSkewness => "Downside asymmetry from the coskewness tensor.", :VarianceSkewKurtosis => "Variance, skewness, and kurtosis combined in one expression.", :BrownianDistanceVariance => "Upper bound on the distance variance of the portfolio returns, built from the distances between observations."], "Tail: X-at-Risk" => [:WorstRealisation => "The single worst observed loss.", :ValueatRisk => "The `alpha` quantile of the loss distribution. The default formulation is mixed-integer.", :ConditionalValueatRisk => "Mean loss beyond the `alpha` quantile, also called expected shortfall.", :DistributionallyRobustConditionalValueatRisk => "CVaR under a Wasserstein ball around the empirical distribution.", :EntropicValueatRisk => "Upper bound on VaR and on CVaR, computed with an exponential cone.", :RelativisticValueatRisk => "Power-cone family between EVaR (`kappa → 0`) and the worst realisation (`kappa → 1`).", :PowerNormValueatRisk => "Power-norm tail measure parameterised by the norm order."], "Tail ranges (both sides)" => [:Range => "Best realisation minus worst realisation.", :ValueatRiskRange => "Loss-side VaR plus gain-side VaR.", :ConditionalValueatRiskRange => "Loss-side CVaR plus gain-side CVaR.", :DistributionallyRobustConditionalValueatRiskRange => "Two-sided distributionally robust CVaR.", :EntropicValueatRiskRange => "Two-sided entropic VaR.", :RelativisticValueatRiskRange => "Two-sided relativistic VaR.", :PowerNormValueatRiskRange => "Two-sided power-norm VaR.", :GenericValueatRiskRange => "Any pair of tail measures, one per side of the distribution."], "Drawdown: uncompounded" => [:AverageDrawdown => "Mean depth of the drawdown path.", :UlcerIndex => "Root mean square of the drawdown depths.", :MaximumDrawdown => "Deepest peak-to-trough loss.", :DrawdownatRisk => "The `alpha` quantile of the drawdown path, a mixed-integer formulation.", :ConditionalDrawdownatRisk => "Mean drawdown beyond the `alpha` quantile.", :DistributionallyRobustConditionalDrawdownatRisk => "CDaR under a Wasserstein ball.", :EntropicDrawdownatRisk => "Exponential-cone bound on the drawdown quantile.", :RelativisticDrawdownatRisk => "Power-cone drawdown family between EDaR (`kappa → 0`) and the maximum drawdown (`kappa → 1`).", :PowerNormDrawdownatRisk => "Power-norm drawdown measure."], "Drawdown: compounded (relative)" => [:RelativeAverageDrawdown => "Average drawdown of the compounded wealth path.", :RelativeUlcerIndex => "Ulcer index of the compounded wealth path.", :RelativeMaximumDrawdown => "Maximum drawdown of the compounded wealth path.", :RelativeDrawdownatRisk => "Drawdown-at-risk of the compounded wealth path.", :RelativeConditionalDrawdownatRisk => "Conditional drawdown-at-risk, compounded.", :RelativeEntropicDrawdownatRisk => "Entropic drawdown-at-risk, compounded.", :RelativeRelativisticDrawdownatRisk => "Relativistic drawdown-at-risk, compounded.", :RelativePowerNormDrawdownatRisk => "Power-norm drawdown-at-risk, compounded."], "Ordered weights arrays" => [:OrderedWeightsArray => "A weight on each sorted return. Section 4 lists its aliases.", :OrderedWeightsArrayRange => "An OWA applied to both sides of the distribution."], "Path and mandate" => [:TrackingRiskMeasure => "Deviation of the portfolio's returns from a benchmark.", :RiskTrackingRiskMeasure => "Risk of the weight difference from a benchmark, or the gap between the two risks.", :TurnoverRiskMeasure => "Distance from the previous weights; penalises trading."], "Composite and structural" => [:EqualRisk => "The same risk for every portfolio, so a hierarchical optimiser splits each cluster evenly.", :RiskRatio => "Ratio of two measures, used as a hierarchical objective.", :NoRisk => "Zero risk, for a problem with no risk term."], "Non-optimisation (diagnostics and scoring)" => [:ExpectedReturn => "Prior expected return of the portfolio.", :MeanReturn => "Realised mean return of the portfolio.", :Skewness => "Standardised skewness of the return distribution.", :ThirdCentralMoment => "Unstandardised third central moment.", :NonOptimisationRiskRatio => "Ratio of any two non-optimisation measures.", :ExpectedReturnRiskRatio => "Prior expected return over risk, a Sharpe-style score.", :MeanReturnRiskRatio => "Realised mean return over risk."]]function leaf_measures(T, acc = Type[]) subs = subtypes(T) isempty(subs) ? push!(acc, T) : foreach(S -> leaf_measures(S, acc), subs) return accendall_measures = Set(nameof.(leaf_measures(PortfolioOptimisers.AbstractBaseRiskMeasure)))listed = [first(p) for (_, fam) in catalogue for p in fam]@assert allunique(listed)@assert Set(listed) == all_measuresfunction family_table(name) entries = catalogue[findfirst(p -> first(p) == name, catalogue)][2] return DataFrame("Measure" => [String(first(e)) for e in entries], "Alias" => [get(rm_alias, first(e), "") for e in entries], "Meaning" => [last(e) for e in entries], "Optimisers" => [usage_class(getfield(PortfolioOptimisers, first(e))) for e in entries])end;Dispersion and moments
pretty_table(family_table("Dispersion and moments"))┌──────────────────────────┬────────────┬───────────────────────────────────────────────────────────────────────────────────────────────────────────────┬───────────────────┐
│ Measure │ Alias │ Meaning │ Optimisers │
│ String │ String │ String │ String │
├──────────────────────────┼────────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────┼───────────────────┤
│ Variance │ │ Portfolio variance from a covariance matrix, the default `r`. │ JuMP + clustering │
│ StandardDeviation │ SD │ Square root of the variance, in the units of the returns. │ JuMP + clustering │
│ UncertaintySetVariance │ UcVariance │ Worst-case variance over an uncertainty set of covariance matrices. │ JuMP + clustering │
│ LowOrderMoment │ │ Generic low-order moment measure, which includes the mean absolute deviation. Section 4 lists its aliases. │ JuMP + clustering │
│ HighOrderMoment │ │ Generic third and fourth moment measure. Section 4 lists its aliases. │ clustering only │
│ MedianAbsoluteDeviation │ │ Median absolute deviation, a robust counterpart of `MAD()`. │ clustering only │
│ Kurtosis │ │ Square root of the fourth central moment of the portfolio returns. │ JuMP + clustering │
│ NegativeSkewness │ │ Downside asymmetry from the coskewness tensor. │ JuMP + clustering │
│ VarianceSkewKurtosis │ VSK │ Variance, skewness, and kurtosis combined in one expression. │ JuMP + clustering │
│ BrownianDistanceVariance │ BDVariance │ Upper bound on the distance variance of the portfolio returns, built from the distances between observations. │ JuMP + clustering │
└──────────────────────────┴────────────┴───────────────────────────────────────────────────────────────────────────────────────────────────────────────┴───────────────────┘Tail measures
pretty_table(family_table("Tail: X-at-Risk"))┌──────────────────────────────────────────────┬────────┬──────────────────────────────────────────────────────────────────────────────────────────┬───────────────────┐
│ Measure │ Alias │ Meaning │ Optimisers │
│ String │ String │ String │ String │
├──────────────────────────────────────────────┼────────┼──────────────────────────────────────────────────────────────────────────────────────────┼───────────────────┤
│ WorstRealisation │ WR │ The single worst observed loss. │ JuMP + clustering │
│ ValueatRisk │ VaR │ The `alpha` quantile of the loss distribution. The default formulation is mixed-integer. │ JuMP + clustering │
│ ConditionalValueatRisk │ CVaR │ Mean loss beyond the `alpha` quantile, also called expected shortfall. │ JuMP + clustering │
│ DistributionallyRobustConditionalValueatRisk │ DRCVaR │ CVaR under a Wasserstein ball around the empirical distribution. │ JuMP + clustering │
│ EntropicValueatRisk │ EVaR │ Upper bound on VaR and on CVaR, computed with an exponential cone. │ JuMP + clustering │
│ RelativisticValueatRisk │ RLVaR │ Power-cone family between EVaR (`kappa → 0`) and the worst realisation (`kappa → 1`). │ JuMP + clustering │
│ PowerNormValueatRisk │ PNVaR │ Power-norm tail measure parameterised by the norm order. │ JuMP + clustering │
└──────────────────────────────────────────────┴────────┴──────────────────────────────────────────────────────────────────────────────────────────┴───────────────────┘Tail ranges (both sides)
pretty_table(family_table("Tail ranges (both sides)"))┌───────────────────────────────────────────────────┬───────────┬──────────────────────────────────────────────────────────────┬───────────────────┐
│ Measure │ Alias │ Meaning │ Optimisers │
│ String │ String │ String │ String │
├───────────────────────────────────────────────────┼───────────┼──────────────────────────────────────────────────────────────┼───────────────────┤
│ Range │ RG │ Best realisation minus worst realisation. │ JuMP + clustering │
│ ValueatRiskRange │ VaR_RG │ Loss-side VaR plus gain-side VaR. │ JuMP + clustering │
│ ConditionalValueatRiskRange │ CVaR_RG │ Loss-side CVaR plus gain-side CVaR. │ JuMP + clustering │
│ DistributionallyRobustConditionalValueatRiskRange │ DRCVaR_RG │ Two-sided distributionally robust CVaR. │ JuMP + clustering │
│ EntropicValueatRiskRange │ EVaR_RG │ Two-sided entropic VaR. │ JuMP + clustering │
│ RelativisticValueatRiskRange │ RLVaR_RG │ Two-sided relativistic VaR. │ JuMP + clustering │
│ PowerNormValueatRiskRange │ PNVaR_RG │ Two-sided power-norm VaR. │ JuMP + clustering │
│ GenericValueatRiskRange │ GVaR_RG │ Any pair of tail measures, one per side of the distribution. │ JuMP + clustering │
└───────────────────────────────────────────────────┴───────────┴──────────────────────────────────────────────────────────────┴───────────────────┘Drawdowns of uncompounded returns
pretty_table(family_table("Drawdown: uncompounded"))┌─────────────────────────────────────────────────┬────────┬───────────────────────────────────────────────────────────────────────────────────────────────┬───────────────────┐
│ Measure │ Alias │ Meaning │ Optimisers │
│ String │ String │ String │ String │
├─────────────────────────────────────────────────┼────────┼───────────────────────────────────────────────────────────────────────────────────────────────┼───────────────────┤
│ AverageDrawdown │ ADD │ Mean depth of the drawdown path. │ JuMP + clustering │
│ UlcerIndex │ UCI │ Root mean square of the drawdown depths. │ JuMP + clustering │
│ MaximumDrawdown │ MDD │ Deepest peak-to-trough loss. │ JuMP + clustering │
│ DrawdownatRisk │ DaR │ The `alpha` quantile of the drawdown path, a mixed-integer formulation. │ JuMP + clustering │
│ ConditionalDrawdownatRisk │ CDaR │ Mean drawdown beyond the `alpha` quantile. │ JuMP + clustering │
│ DistributionallyRobustConditionalDrawdownatRisk │ DRCDaR │ CDaR under a Wasserstein ball. │ JuMP + clustering │
│ EntropicDrawdownatRisk │ EDaR │ Exponential-cone bound on the drawdown quantile. │ JuMP + clustering │
│ RelativisticDrawdownatRisk │ RLDaR │ Power-cone drawdown family between EDaR (`kappa → 0`) and the maximum drawdown (`kappa → 1`). │ JuMP + clustering │
│ PowerNormDrawdownatRisk │ PNDaR │ Power-norm drawdown measure. │ JuMP + clustering │
└─────────────────────────────────────────────────┴────────┴───────────────────────────────────────────────────────────────────────────────────────────────┴───────────────────┘Drawdowns of compounded returns
The Relative* measures compute the drawdown on the compounded wealth, not on the cumulative sum of the returns. They have no convex JuMP formulation, so they are all clustering only.
pretty_table(family_table("Drawdown: compounded (relative)"))┌────────────────────────────────────┬─────────┬─────────────────────────────────────────────────┬─────────────────┐
│ Measure │ Alias │ Meaning │ Optimisers │
│ String │ String │ String │ String │
├────────────────────────────────────┼─────────┼─────────────────────────────────────────────────┼─────────────────┤
│ RelativeAverageDrawdown │ R_ADD │ Average drawdown of the compounded wealth path. │ clustering only │
│ RelativeUlcerIndex │ R_UCI │ Ulcer index of the compounded wealth path. │ clustering only │
│ RelativeMaximumDrawdown │ R_MDD │ Maximum drawdown of the compounded wealth path. │ clustering only │
│ RelativeDrawdownatRisk │ R_DaR │ Drawdown-at-risk of the compounded wealth path. │ clustering only │
│ RelativeConditionalDrawdownatRisk │ R_CDaR │ Conditional drawdown-at-risk, compounded. │ clustering only │
│ RelativeEntropicDrawdownatRisk │ R_EDaR │ Entropic drawdown-at-risk, compounded. │ clustering only │
│ RelativeRelativisticDrawdownatRisk │ R_RLDaR │ Relativistic drawdown-at-risk, compounded. │ clustering only │
│ RelativePowerNormDrawdownatRisk │ R_PNDaR │ Power-norm drawdown-at-risk, compounded. │ clustering only │
└────────────────────────────────────┴─────────┴─────────────────────────────────────────────────┴─────────────────┘Ordered weights arrays
pretty_table(family_table("Ordered weights arrays"))┌──────────────────────────┬────────┬──────────────────────────────────────────────────────────────┬───────────────────┐
│ Measure │ Alias │ Meaning │ Optimisers │
│ String │ String │ String │ String │
├──────────────────────────┼────────┼──────────────────────────────────────────────────────────────┼───────────────────┤
│ OrderedWeightsArray │ OWA │ A weight on each sorted return. Section 4 lists its aliases. │ JuMP + clustering │
│ OrderedWeightsArrayRange │ │ An OWA applied to both sides of the distribution. │ JuMP + clustering │
└──────────────────────────┴────────┴──────────────────────────────────────────────────────────────┴───────────────────┘Path and mandate
pretty_table(family_table("Path and mandate"))┌─────────────────────────┬────────┬───────────────────────────────────────────────────────────────────────────────────┬───────────────────┐
│ Measure │ Alias │ Meaning │ Optimisers │
│ String │ String │ String │ String │
├─────────────────────────┼────────┼───────────────────────────────────────────────────────────────────────────────────┼───────────────────┤
│ TrackingRiskMeasure │ TrRM │ Deviation of the portfolio's returns from a benchmark. │ JuMP + clustering │
│ RiskTrackingRiskMeasure │ RkTrRM │ Risk of the weight difference from a benchmark, or the gap between the two risks. │ JuMP + clustering │
│ TurnoverRiskMeasure │ TnRM │ Distance from the previous weights; penalises trading. │ JuMP + clustering │
└─────────────────────────┴────────┴───────────────────────────────────────────────────────────────────────────────────┴───────────────────┘Composite and structural
pretty_table(family_table("Composite and structural"))┌───────────┬────────┬────────────────────────────────────────────────────────────────────────────────────────────┬───────────────────┐
│ Measure │ Alias │ Meaning │ Optimisers │
│ String │ String │ String │ String │
├───────────┼────────┼────────────────────────────────────────────────────────────────────────────────────────────┼───────────────────┤
│ EqualRisk │ │ The same risk for every portfolio, so a hierarchical optimiser splits each cluster evenly. │ clustering only │
│ RiskRatio │ │ Ratio of two measures, used as a hierarchical objective. │ clustering only │
│ NoRisk │ │ Zero risk, for a problem with no risk term. │ JuMP + clustering │
└───────────┴────────┴────────────────────────────────────────────────────────────────────────────────────────────┴───────────────────┘Non-optimisation (diagnostics and scoring)
You cannot put these measures in an r field. They score a portfolio after the optimisation, and they score the folds of a cross-validation. See validation and tuning.
pretty_table(family_table("Non-optimisation (diagnostics and scoring)"))┌──────────────────────────┬───────────────┬────────────────────────────────────────────────────────┬─────────────────┐
│ Measure │ Alias │ Meaning │ Optimisers │
│ String │ String │ String │ String │
├──────────────────────────┼───────────────┼────────────────────────────────────────────────────────┼─────────────────┤
│ ExpectedReturn │ │ Prior expected return of the portfolio. │ diagnostic only │
│ MeanReturn │ │ Realised mean return of the portfolio. │ diagnostic only │
│ Skewness │ │ Standardised skewness of the return distribution. │ diagnostic only │
│ ThirdCentralMoment │ │ Unstandardised third central moment. │ diagnostic only │
│ NonOptimisationRiskRatio │ NonOptRkRatio │ Ratio of any two non-optimisation measures. │ diagnostic only │
│ ExpectedReturnRiskRatio │ │ Prior expected return over risk, a Sharpe-style score. │ diagnostic only │
│ MeanReturnRiskRatio │ │ Realised mean return over risk. │ diagnostic only │
└──────────────────────────┴───────────────┴────────────────────────────────────────────────────────┴─────────────────┘4. Generic measures and their aliases
Three of the types above are generic. LowOrderMoment, HighOrderMoment and OrderedWeightsArray each compute a family of measures, and the alg or w field selects the member. You can write MAD() for LowOrderMoment(; alg = MeanAbsoluteDeviation()). Each row below is an exported alias that builds a measure in one call. An alias that builds a HighOrderMoment gives a measure that only a clustering optimiser accepts.
We read the Expands to column off the object that each alias builds, so the column shows what the alias builds in this version.
alias_ctors = [("FLM", FLM, "First lower partial moment."), ("MAD", MAD, "Mean absolute deviation."), ("SCM", SCM, "Second central moment: scenario variance or standard deviation."), ("SLM", SLM, "Second lower moment: scenario semi-variance."), ("ECM", ECM, "Central even moment of order `2p`."), ("ELM", ELM, "Lower even moment of order `2p`."), ("TLM", TLM, "Third lower moment."), ("SSK", SSK, "Standardised third lower moment: semi-skewness."), ("FTCM", FTCM, "Fourth central moment."), ("FTLM", FTLM, "Fourth lower moment."), ("KT", KT, "Standardised fourth central moment: kurtosis."), ("SKT", SKT, "Standardised fourth lower moment: semi-kurtosis."), ("OWA_GMD", OWA_GMD, "Gini mean difference."), ("OWA_CVaR", OWA_CVaR, "CVaR as an OWA."), ("OWA_TG", OWA_TG, "Tail Gini."), ("OWA_WR", OWA_WR, "Worst realisation as an OWA."), ("OWA_RG", OWA_RG, "Range as an OWA."), ("OWA_CVaR_RG", OWA_CVaR_RG, "Two-sided CVaR as an OWA."), ("OWA_TG_RG", OWA_TG_RG, "Two-sided tail Gini."), ("OWA_LMoment", OWA_LMoment, "L-moment weights of order `k`.")]function expands_to(m) if isa(m, OrderedWeightsArray) return "w = $(isa(m.w, Function) ? nameof(m.w) : nameof(typeof(m.w)))" end parts, a = String[], m.alg while true push!(parts, String(nameof(typeof(a)))) if hasproperty(a, :alg1) push!(parts, String(nameof(typeof(a.alg1)))) end if hasproperty(a, :alg) && isa(a.alg, PortfolioOptimisers.AbstractAlgorithm) a = a.alg else break end end return join(parts, " → ")endpretty_table(DataFrame("Alias" => [a[1] * "()" for a in alias_ctors], "Builds" => [String(nameof(typeof(a[2]()))) for a in alias_ctors], "Expands to" => [expands_to(a[2]()) for a in alias_ctors], "Meaning" => [a[3] for a in alias_ctors]))┌───────────────┬─────────────────────┬─────────────────────────────────────────────────────────┬─────────────────────────────────────────────────────────────────┐
│ Alias │ Builds │ Expands to │ Meaning │
│ String │ String │ String │ String │
├───────────────┼─────────────────────┼─────────────────────────────────────────────────────────┼─────────────────────────────────────────────────────────────────┤
│ FLM() │ LowOrderMoment │ FirstLowerMoment │ First lower partial moment. │
│ MAD() │ LowOrderMoment │ MeanAbsoluteDeviation │ Mean absolute deviation. │
│ SCM() │ LowOrderMoment │ SecondMoment → FullMoment │ Second central moment: scenario variance or standard deviation. │
│ SLM() │ LowOrderMoment │ SecondMoment → SemiMoment │ Second lower moment: scenario semi-variance. │
│ ECM() │ LowOrderMoment │ EvenMoment → FullMoment │ Central even moment of order `2p`. │
│ ELM() │ LowOrderMoment │ EvenMoment → SemiMoment │ Lower even moment of order `2p`. │
│ TLM() │ HighOrderMoment │ ThirdLowerMoment │ Third lower moment. │
│ SSK() │ HighOrderMoment │ StandardisedHighOrderMoment → ThirdLowerMoment │ Standardised third lower moment: semi-skewness. │
│ FTCM() │ HighOrderMoment │ FourthMoment → FullMoment │ Fourth central moment. │
│ FTLM() │ HighOrderMoment │ FourthMoment → SemiMoment │ Fourth lower moment. │
│ KT() │ HighOrderMoment │ StandardisedHighOrderMoment → FourthMoment → FullMoment │ Standardised fourth central moment: kurtosis. │
│ SKT() │ HighOrderMoment │ StandardisedHighOrderMoment → FourthMoment → SemiMoment │ Standardised fourth lower moment: semi-kurtosis. │
│ OWA_GMD() │ OrderedWeightsArray │ w = owa_gmd │ Gini mean difference. │
│ OWA_CVaR() │ OrderedWeightsArray │ w = OrderedWeightsArrayConditionalValueatRisk │ CVaR as an OWA. │
│ OWA_TG() │ OrderedWeightsArray │ w = OrderedWeightsArrayTailGini │ Tail Gini. │
│ OWA_WR() │ OrderedWeightsArray │ w = owa_wr │ Worst realisation as an OWA. │
│ OWA_RG() │ OrderedWeightsArray │ w = owa_rg │ Range as an OWA. │
│ OWA_CVaR_RG() │ OrderedWeightsArray │ w = OrderedWeightsArrayConditionalValueatRiskRange │ Two-sided CVaR as an OWA. │
│ OWA_TG_RG() │ OrderedWeightsArray │ w = OrderedWeightsArrayTailGiniRange │ Two-sided tail Gini. │
│ OWA_LMoment() │ OrderedWeightsArray │ w = LinearMoment │ L-moment weights of order `k`. │
└───────────────┴─────────────────────┴─────────────────────────────────────────────────────────┴─────────────────────────────────────────────────────────────────┘MAD builds a LowOrderMoment with MeanAbsoluteDeviation, the deviation around the mean. It is a RiskMeasure, so every optimiser with an r field accepts it. MedianAbsoluteDeviation is a different type. By default it measures the deviation around the median, and only a clustering optimiser accepts it.
5. Choosing a measure
The choice depends on what you want to penalise:
- If the returns are about symmetric and you care about their spread, use
Variance, the default, orStandardDeviation. - If a loss in the left tail matters more than the spread, start with
ConditionalValueatRisk.EntropicValueatRiskis an upper bound on it, so it penalises the tail more.RelativisticValueatRiskgeneralises the entropic value at risk, and it tends to the entropic value at risk as its parameterkappagoes to zero. - If the path of the wealth matters as well as the distribution of the returns, use a drawdown measure, such as
MaximumDrawdownorConditionalDrawdownatRisk. - If you do not trust the estimate of the covariance, use
UncertaintySetVariance. - If you want to give a weight to each sorted return, use
OrderedWeightsArray. - If trading costs matter, add
TurnoverRiskMeasureto your main measure. It penalises the distance from the previous weights. To penalise the distance of the portfolio's returns from a benchmark, addTrackingRiskMeasure.
Multiple Risk Measures shows how an optimiser combines several measures in one objective. These pages cover the measures in depth: OWA Risk Measures, Brownian Distance, Skew and Kurtosis, Drawdown Risk Measures, and Exotic Tail Risk Measures.
6. The measures on the distribution of the returns
plot_histogram draws the histogram of the returns of the equal-weighted portfolio, with a vertical line for each of several measures. One line marks the mean. Three lines mark the mean less the standard deviation, less the mean absolute deviation and less the Gini mean difference. The other lines mark the value at risk, the conditional value at risk, the tail Gini and the worst return. The value at risk is a quantile of the returns. The conditional value at risk is the mean of the returns below that quantile, so its line is further to the left. The curve is the density of the Normal distribution fitted to the returns. Where the histogram rises above the curve in the left tail, the returns have a fatter tail than the Normal. reference = false removes the curve.
plot_histogram(w, rd)This page was generated using Literate.jl.