The source files can be found in examples/.

Regularisation

This example shows one of the simplest ways to improve the robustness of portfolios, regularisation penalties.

using PortfolioOptimisers, PrettyTables# Format for pretty tables.tsfmt = (v, i, j) -> begin    if j == 1        return Date(v)    else        return v    endend;resfmt = (v, i, j) -> begin    if j == 1        return v    else        return isa(v, Number) ? "$(round(v*100, digits=3)) %" : v    endend;mmtfmt = (v, i, j) -> begin    if i == j == 1        return v    else        return isa(v, Number) ? "$(round(v*100, digits=3)) %" : v    endend;summary_row = (data, j) -> begin    if j == 1        return "N/A"    else        return number_effective_assets(data[:, j])    endend
#11 (generic function with 1 method)

1. Setting up

We will use the same data as the previous example.

using CSV, TimeSeries, DataFrames, ClarabelX = TimeArray(CSV.File(joinpath(@__DIR__, "..", "SP500.csv.gz")); timestamp = :Date)[(end - 252):end]pretty_table(X[(end - 5):end]; formatters = [tsfmt])# Compute the returnsrd = prices_to_returns(X)pr = prior(EmpiricalPrior(), rd)slv = [Solver(; name = :clarabel1, solver = Clarabel.Optimizer,              settings = Dict("verbose" => false),              check_sol = (; allow_local = true, allow_almost = true)),       Solver(; name = :clarabel2, solver = Clarabel.Optimizer,              settings = Dict("verbose" => false, "max_step_fraction" => 0.95),              check_sol = (; allow_local = true, allow_almost = true)),       Solver(; name = :clarabel3, solver = Clarabel.Optimizer,              settings = Dict("verbose" => false, "max_step_fraction" => 0.9),              check_sol = (; allow_local = true, allow_almost = true)),       Solver(; name = :clarabel4, solver = Clarabel.Optimizer,              settings = Dict("verbose" => false, "max_step_fraction" => 0.85),              check_sol = (; allow_local = true, allow_almost = true)),       Solver(; name = :clarabel5, solver = Clarabel.Optimizer,              settings = Dict("verbose" => false, "max_step_fraction" => 0.8),              check_sol = (; allow_local = true, allow_almost = true)),       Solver(; name = :clarabel6, solver = Clarabel.Optimizer,              settings = Dict("verbose" => false, "max_step_fraction" => 0.75),              check_sol = (; allow_local = true, allow_almost = true)),       Solver(; name = :clarabel7, solver = Clarabel.Optimizer,              settings = Dict("verbose" => false, "max_step_fraction" => 0.70),              check_sol = (; allow_local = true, allow_almost = true))];
┌────────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┐
│  timestamp     AAPL      AMD      BAC      BBY      CVX       GE       HD      JNJ      JPM       KO      LLY      MRK     MSFT      PEP      PFE       PG      RRC      UNH      WMT      XOM │
│       Date  Float64  Float64  Float64  Float64  Float64  Float64  Float64  Float64  Float64  Float64  Float64  Float64  Float64  Float64  Float64  Float64  Float64  Float64  Float64  Float64 │
├────────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ 2022-12-20 │ 131.916 │   65.05 │  31.729 │  77.371 │ 169.497 │  62.604 │ 310.342 │ 173.109 │ 127.844 │  61.841 │  357.55 │ 108.229 │  240.67 │ 178.765 │  49.754 │ 147.661 │   25.65 │ 516.245 │ 142.919 │ 104.964 │
│ 2022-12-21 │ 135.057 │   67.68 │  32.212 │  78.729 │  171.49 │   64.67 │ 314.798 │  175.09 │ 129.282 │  62.836 │ 365.872 │ 109.611 │ 243.287 │ 180.017 │  50.084 │ 149.015 │  26.574 │ 523.519 │  144.04 │ 106.312 │
│ 2022-12-22 │ 131.846 │   63.86 │  31.927 │  78.563 │ 168.918 │  63.727 │ 311.604 │  174.45 │ 127.814 │  62.383 │ 363.187 │ 109.739 │ 237.077 │ 178.627 │  50.065 │ 149.359 │  25.232 │ 523.072 │ 142.354 │ 104.168 │
│ 2022-12-23 │ 131.477 │   64.52 │  32.005 │  79.432 │  174.14 │  63.742 │ 314.177 │ 174.893 │ 128.421 │  62.855 │ 365.762 │  110.35 │ 237.614 │ 179.781 │  50.249 │ 149.781 │  26.226 │  527.26 │ 142.641 │ 106.922 │
│ 2022-12-27 │ 129.652 │   63.27 │  32.065 │   79.93 │ 176.329 │  64.561 │ 314.985 │ 174.844 │ 128.871 │   63.24 │  362.76 │ 110.607 │ 235.852 │  180.58 │   49.57 │ 151.086 │  26.375 │ 527.935 │ 142.681 │ 108.408 │
│ 2022-12-28 │ 125.674 │   62.57 │  32.301 │  78.279 │ 173.728 │  63.883 │  311.22 │ 174.085 │ 129.575 │  62.609 │ 363.098 │ 109.581 │ 233.434 │ 179.278 │   49.25 │ 149.133 │  24.497 │ 524.422 │ 140.181 │ 106.627 │
└────────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┘

2. Regularised portfolios

The optimal regularisation penalty value depends on the data, the investor preferences, and type of regularisation. The specific choice of penalty value is so volatile that it can only be estimated via grid search cross-validation or similar techniques, but the "optimal" (to some definition of optimal) value will also change over time as the market conditions change. Therefore, we will simply show how to set up and solve a regularised portfolio optimisation problem, without attempting to find the optimal penalty value.

We will use the same small penalty for all regularisations to illustrate how they differ.

  • L1 regularisation (also known as Lasso regularisation) adds a penalty proportional to the sum of the absolute values of the portfolio weights. This encourages sparsity in the portfolio, leading to fewer assets being selected.
  • L2 regularisation (also known as Ridge regularisation) adds a penalty proportional to the sum of the squares of the portfolio weights. This discourages large weights and promotes diversification.
  • Lp regularisation via LpRegularisation adds a penalty proportional to the p-norm of the portfolio weights, where p > 1 is a positive real number.
  • L-Inf regularisation adds a penalty proportional to the maximum absolute value of the portfolio weights. This limits the influence of any single asset in the portfolio.

2.1 Efficient frontier

opts = [JuMPOptimiser(; pe = pr, slv = slv, wb = WeightBounds(; lb = -1, ub = 1), sbgt = 1,                      bgt = 1,                      ret = ArithmeticReturn(;                                             settings = JuMPReturnsSettings(;                                                                            lb = Frontier(;                                                                                          N = 50)))),#        JuMPOptimiser(; pe = pr, slv = slv, wb = WeightBounds(; lb = -1, ub = 1), sbgt = 1,                      ret = ArithmeticReturn(;                                             settings = JuMPReturnsSettings(;                                                                            lb = Frontier(;                                                                                          N = 50))),                      bgt = 1, l1 = 4e-4),#        JuMPOptimiser(; pe = pr, slv = slv, wb = WeightBounds(; lb = -1, ub = 1), sbgt = 1,                      ret = ArithmeticReturn(;                                             settings = JuMPReturnsSettings(;                                                                            lb = Frontier(;                                                                                          N = 50))),                      bgt = 1, l2 = L2Regularisation(; val = 4e-4)),#        JuMPOptimiser(; pe = pr, slv = slv, wb = WeightBounds(; lb = -1, ub = 1), sbgt = 1,                      ret = ArithmeticReturn(;                                             settings = JuMPReturnsSettings(;                                                                            lb = Frontier(;                                                                                          N = 50))),                      bgt = 1, lp = LpRegularisation(; p = 5, val = 4e-4)),#        JuMPOptimiser(; pe = pr, slv = slv, wb = WeightBounds(; lb = -1, ub = 1), sbgt = 1,                      ret = ArithmeticReturn(;                                             settings = JuMPReturnsSettings(;                                                                            lb = Frontier(;                                                                                          N = 50))),                      bgt = 1, linf = 4e-4)]nocs = [MeanRisk(; opt = opt) for opt in opts]ress = optimise.(nocs)
5-element Vector{MeanRiskResult{JuMPOptimisationResult{ProcessedJuMPOptimiserAttributes{LowOrderPrior{Matrix{Float64}, Nothing, Vector{Float64}, Matrix{Float64}, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing}, WeightBounds{StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64}, StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64}}, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, ArithmeticReturn{JuMPReturnsSettings{Float64, Frontier{Int64, Int64, LinearBound}, Bool, Bool, Bool}, Nothing, Vector{Float64}}, SumScalariser}, Vector{OptimisationReturnCode}, Vector{JuMPOptimisationSolution}, Model}, Variance{RiskMeasureSettings{Float64, Nothing, Bool}, Matrix{Float64}, Nothing, Nothing, SquaredSOCRiskExpr}, Nothing}}:
 MeanRiskResult
  jr ┼ JuMPOptimisationResult
     │        pa ┼ ProcessedJuMPOptimiserAttributes
     │           │        pr ┼ LowOrderPrior
     │           │           │       X ┼ 252×20 Matrix{Float64}
     │           │           │     o_X ┼ nothing
     │           │           │      mu ┼ 20-element Vector{Float64}
     │           │           │   sigma ┼ 20×20 Matrix{Float64}
     │           │           │    chol ┼ nothing
     │           │           │       w ┼ nothing
     │           │           │     ens ┼ nothing
     │           │           │     kld ┼ nothing
     │           │           │      ow ┼ nothing
     │           │           │      rr ┼ nothing
     │           │           │     fpr ┼ nothing
     │           │           │       Z ┴ nothing
     │           │        wb ┼ WeightBounds
     │           │           │   lb ┼ 20-element StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64}
     │           │           │   ub ┴ 20-element StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64}
     │           │        lt ┼ nothing
     │           │        st ┼ nothing
     │           │      lcsr ┼ nothing
     │           │       ctr ┼ nothing
     │           │    gcardr ┼ nothing
     │           │   sgcardr ┼ nothing
     │           │      smtx ┼ nothing
     │           │     sgmtx ┼ nothing
     │           │       slt ┼ nothing
     │           │       sst ┼ nothing
     │           │      sglt ┼ nothing
     │           │      sgst ┼ nothing
     │           │        tn ┼ nothing
     │           │      fees ┼ nothing
     │           │       plr ┼ nothing
     │           │       ret ┼ ArithmeticReturn
     │           │           │   settings ┼ JuMPReturnsSettings
     │           │           │            │   scale ┼ Float64: 1.0
     │           │           │            │      lb ┼ Frontier
     │           │           │            │         │        N ┼ Int64: 50
     │           │           │            │         │   factor ┼ Int64: 1
     │           │           │            │         │    bound ┴ LinearBound()
     │           │           │            │     rte ┼ Bool: true
     │           │           │            │     fee ┼ Bool: true
     │           │           │            │     mic ┴ Bool: true
     │           │           │        ucs ┼ nothing
     │           │           │         mu ┴ 20-element Vector{Float64}
     │           │       sca ┴ SumScalariser()
     │   retcode ┼ 50-element Vector{OptimisationSuccess}
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │       sol ┼ 50-element Vector{JuMPOptimisationSolution}
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │     model ┼ A JuMP Model
     │           │ ├ solver: Clarabel
     │           │ ├ objective_sense: MIN_SENSE
     │           │ │ └ objective_function_type: QuadExpr
     │           │ ├ num_variables: 62
     │           │ ├ num_constraints: 50
     │           │ │ ├ AffExpr in MOI.EqualTo{Float64}: 3
     │           │ │ ├ AffExpr in MOI.GreaterThan{Float64}: 1
     │           │ │ ├ Vector{AffExpr} in MOI.Nonnegatives: 2
     │           │ │ ├ Vector{AffExpr} in MOI.Nonpositives: 2
     │           │ │ ├ Vector{AffExpr} in MOI.SecondOrderCone: 1
     │           │ │ ├ VariableRef in MOI.GreaterThan{Float64}: 40
     │           │ │ └ VariableRef in MOI.Parameter{Float64}: 1
     │           │ └ Names registered in the model
     │           │   └ :G, :bgt, :cdev_soc_1, :decomposition_contract, :dev_1, :k, :lbgt, :lw, :obj_expr, :ret, :ret_1, :ret_frontier, :ret_lb_1, :ret_lb_var_1, :ret_vec, :risk, :risk_vec, :sbgt, :sc, :so, :sw, :variance_flag, :variance_risk_1, :w, :w_lb, :w_lw, :w_sw, :w_ub
   r ┼ Variance
     │   settings ┼ RiskMeasureSettings
     │            │   scale ┼ Float64: 1.0
     │            │      ub ┼ nothing
     │            │     rke ┴ Bool: true
     │      sigma ┼ 20×20 Matrix{Float64}
     │       chol ┼ nothing
     │         rc ┼ nothing
     │        alg ┴ SquaredSOCRiskExpr()
  fb ┴ nothing

 MeanRiskResult
  jr ┼ JuMPOptimisationResult
     │        pa ┼ ProcessedJuMPOptimiserAttributes
     │           │        pr ┼ LowOrderPrior
     │           │           │       X ┼ 252×20 Matrix{Float64}
     │           │           │     o_X ┼ nothing
     │           │           │      mu ┼ 20-element Vector{Float64}
     │           │           │   sigma ┼ 20×20 Matrix{Float64}
     │           │           │    chol ┼ nothing
     │           │           │       w ┼ nothing
     │           │           │     ens ┼ nothing
     │           │           │     kld ┼ nothing
     │           │           │      ow ┼ nothing
     │           │           │      rr ┼ nothing
     │           │           │     fpr ┼ nothing
     │           │           │       Z ┴ nothing
     │           │        wb ┼ WeightBounds
     │           │           │   lb ┼ 20-element StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64}
     │           │           │   ub ┴ 20-element StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64}
     │           │        lt ┼ nothing
     │           │        st ┼ nothing
     │           │      lcsr ┼ nothing
     │           │       ctr ┼ nothing
     │           │    gcardr ┼ nothing
     │           │   sgcardr ┼ nothing
     │           │      smtx ┼ nothing
     │           │     sgmtx ┼ nothing
     │           │       slt ┼ nothing
     │           │       sst ┼ nothing
     │           │      sglt ┼ nothing
     │           │      sgst ┼ nothing
     │           │        tn ┼ nothing
     │           │      fees ┼ nothing
     │           │       plr ┼ nothing
     │           │       ret ┼ ArithmeticReturn
     │           │           │   settings ┼ JuMPReturnsSettings
     │           │           │            │   scale ┼ Float64: 1.0
     │           │           │            │      lb ┼ Frontier
     │           │           │            │         │        N ┼ Int64: 50
     │           │           │            │         │   factor ┼ Int64: 1
     │           │           │            │         │    bound ┴ LinearBound()
     │           │           │            │     rte ┼ Bool: true
     │           │           │            │     fee ┼ Bool: true
     │           │           │            │     mic ┴ Bool: true
     │           │           │        ucs ┼ nothing
     │           │           │         mu ┴ 20-element Vector{Float64}
     │           │       sca ┴ SumScalariser()
     │   retcode ┼ 50-element Vector{OptimisationSuccess}
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │       sol ┼ 50-element Vector{JuMPOptimisationSolution}
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │     model ┼ A JuMP Model
     │           │ ├ solver: Clarabel
     │           │ ├ objective_sense: MIN_SENSE
     │           │ │ └ objective_function_type: QuadExpr
     │           │ ├ num_variables: 63
     │           │ ├ num_constraints: 51
     │           │ │ ├ AffExpr in MOI.EqualTo{Float64}: 3
     │           │ │ ├ AffExpr in MOI.GreaterThan{Float64}: 1
     │           │ │ ├ Vector{AffExpr} in MOI.Nonnegatives: 2
     │           │ │ ├ Vector{AffExpr} in MOI.Nonpositives: 2
     │           │ │ ├ Vector{AffExpr} in MOI.NormOneCone: 1
     │           │ │ ├ Vector{AffExpr} in MOI.SecondOrderCone: 1
     │           │ │ ├ VariableRef in MOI.GreaterThan{Float64}: 40
     │           │ │ └ VariableRef in MOI.Parameter{Float64}: 1
     │           │ └ Names registered in the model
     │           │   └ :G, :bgt, :cdev_soc_1, :cl1_noc, :decomposition_contract, :dev_1, :k, :l1, :lbgt, :lw, :obj_expr, :op, :ret, :ret_1, :ret_frontier, :ret_lb_1, :ret_lb_var_1, :ret_vec, :risk, :risk_vec, :sbgt, :sc, :so, :sw, :t_l1, :variance_flag, :variance_risk_1, :w, :w_lb, :w_lw, :w_sw, :w_ub
   r ┼ Variance
     │   settings ┼ RiskMeasureSettings
     │            │   scale ┼ Float64: 1.0
     │            │      ub ┼ nothing
     │            │     rke ┴ Bool: true
     │      sigma ┼ 20×20 Matrix{Float64}
     │       chol ┼ nothing
     │         rc ┼ nothing
     │        alg ┴ SquaredSOCRiskExpr()
  fb ┴ nothing

 MeanRiskResult
  jr ┼ JuMPOptimisationResult
     │        pa ┼ ProcessedJuMPOptimiserAttributes
     │           │        pr ┼ LowOrderPrior
     │           │           │       X ┼ 252×20 Matrix{Float64}
     │           │           │     o_X ┼ nothing
     │           │           │      mu ┼ 20-element Vector{Float64}
     │           │           │   sigma ┼ 20×20 Matrix{Float64}
     │           │           │    chol ┼ nothing
     │           │           │       w ┼ nothing
     │           │           │     ens ┼ nothing
     │           │           │     kld ┼ nothing
     │           │           │      ow ┼ nothing
     │           │           │      rr ┼ nothing
     │           │           │     fpr ┼ nothing
     │           │           │       Z ┴ nothing
     │           │        wb ┼ WeightBounds
     │           │           │   lb ┼ 20-element StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64}
     │           │           │   ub ┴ 20-element StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64}
     │           │        lt ┼ nothing
     │           │        st ┼ nothing
     │           │      lcsr ┼ nothing
     │           │       ctr ┼ nothing
     │           │    gcardr ┼ nothing
     │           │   sgcardr ┼ nothing
     │           │      smtx ┼ nothing
     │           │     sgmtx ┼ nothing
     │           │       slt ┼ nothing
     │           │       sst ┼ nothing
     │           │      sglt ┼ nothing
     │           │      sgst ┼ nothing
     │           │        tn ┼ nothing
     │           │      fees ┼ nothing
     │           │       plr ┼ nothing
     │           │       ret ┼ ArithmeticReturn
     │           │           │   settings ┼ JuMPReturnsSettings
     │           │           │            │   scale ┼ Float64: 1.0
     │           │           │            │      lb ┼ Frontier
     │           │           │            │         │        N ┼ Int64: 50
     │           │           │            │         │   factor ┼ Int64: 1
     │           │           │            │         │    bound ┴ LinearBound()
     │           │           │            │     rte ┼ Bool: true
     │           │           │            │     fee ┼ Bool: true
     │           │           │            │     mic ┴ Bool: true
     │           │           │        ucs ┼ nothing
     │           │           │         mu ┴ 20-element Vector{Float64}
     │           │       sca ┴ SumScalariser()
     │   retcode ┼ 50-element Vector{OptimisationSuccess}
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │       sol ┼ 50-element Vector{JuMPOptimisationSolution}
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │     model ┼ A JuMP Model
     │           │ ├ solver: Clarabel
     │           │ ├ objective_sense: MIN_SENSE
     │           │ │ └ objective_function_type: QuadExpr
     │           │ ├ num_variables: 63
     │           │ ├ num_constraints: 51
     │           │ │ ├ AffExpr in MOI.EqualTo{Float64}: 3
     │           │ │ ├ AffExpr in MOI.GreaterThan{Float64}: 1
     │           │ │ ├ Vector{AffExpr} in MOI.Nonnegatives: 2
     │           │ │ ├ Vector{AffExpr} in MOI.Nonpositives: 2
     │           │ │ ├ Vector{AffExpr} in MOI.SecondOrderCone: 2
     │           │ │ ├ VariableRef in MOI.GreaterThan{Float64}: 40
     │           │ │ └ VariableRef in MOI.Parameter{Float64}: 1
     │           │ └ Names registered in the model
     │           │   └ :G, :bgt, :cdev_soc_1, :cl2_soc_1, :decomposition_contract, :dev_1, :k, :l2_1, :lbgt, :lw, :obj_expr, :op, :ret, :ret_1, :ret_frontier, :ret_lb_1, :ret_lb_var_1, :ret_vec, :risk, :risk_vec, :sbgt, :sc, :so, :sw, :t_l2_1, :variance_flag, :variance_risk_1, :w, :w_lb, :w_lw, :w_sw, :w_ub
   r ┼ Variance
     │   settings ┼ RiskMeasureSettings
     │            │   scale ┼ Float64: 1.0
     │            │      ub ┼ nothing
     │            │     rke ┴ Bool: true
     │      sigma ┼ 20×20 Matrix{Float64}
     │       chol ┼ nothing
     │         rc ┼ nothing
     │        alg ┴ SquaredSOCRiskExpr()
  fb ┴ nothing

 MeanRiskResult
  jr ┼ JuMPOptimisationResult
     │        pa ┼ ProcessedJuMPOptimiserAttributes
     │           │        pr ┼ LowOrderPrior
     │           │           │       X ┼ 252×20 Matrix{Float64}
     │           │           │     o_X ┼ nothing
     │           │           │      mu ┼ 20-element Vector{Float64}
     │           │           │   sigma ┼ 20×20 Matrix{Float64}
     │           │           │    chol ┼ nothing
     │           │           │       w ┼ nothing
     │           │           │     ens ┼ nothing
     │           │           │     kld ┼ nothing
     │           │           │      ow ┼ nothing
     │           │           │      rr ┼ nothing
     │           │           │     fpr ┼ nothing
     │           │           │       Z ┴ nothing
     │           │        wb ┼ WeightBounds
     │           │           │   lb ┼ 20-element StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64}
     │           │           │   ub ┴ 20-element StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64}
     │           │        lt ┼ nothing
     │           │        st ┼ nothing
     │           │      lcsr ┼ nothing
     │           │       ctr ┼ nothing
     │           │    gcardr ┼ nothing
     │           │   sgcardr ┼ nothing
     │           │      smtx ┼ nothing
     │           │     sgmtx ┼ nothing
     │           │       slt ┼ nothing
     │           │       sst ┼ nothing
     │           │      sglt ┼ nothing
     │           │      sgst ┼ nothing
     │           │        tn ┼ nothing
     │           │      fees ┼ nothing
     │           │       plr ┼ nothing
     │           │       ret ┼ ArithmeticReturn
     │           │           │   settings ┼ JuMPReturnsSettings
     │           │           │            │   scale ┼ Float64: 1.0
     │           │           │            │      lb ┼ Frontier
     │           │           │            │         │        N ┼ Int64: 50
     │           │           │            │         │   factor ┼ Int64: 1
     │           │           │            │         │    bound ┴ LinearBound()
     │           │           │            │     rte ┼ Bool: true
     │           │           │            │     fee ┼ Bool: true
     │           │           │            │     mic ┴ Bool: true
     │           │           │        ucs ┼ nothing
     │           │           │         mu ┴ 20-element Vector{Float64}
     │           │       sca ┴ SumScalariser()
     │   retcode ┼ 50-element Vector{OptimisationSuccess}
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │       sol ┼ 50-element Vector{JuMPOptimisationSolution}
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │     model ┼ A JuMP Model
     │           │ ├ solver: Clarabel
     │           │ ├ objective_sense: MIN_SENSE
     │           │ │ └ objective_function_type: QuadExpr
     │           │ ├ num_variables: 83
     │           │ ├ num_constraints: 71
     │           │ │ ├ AffExpr in MOI.EqualTo{Float64}: 4
     │           │ │ ├ AffExpr in MOI.GreaterThan{Float64}: 1
     │           │ │ ├ Vector{AffExpr} in MOI.Nonnegatives: 2
     │           │ │ ├ Vector{AffExpr} in MOI.Nonpositives: 2
     │           │ │ ├ Vector{AffExpr} in MOI.SecondOrderCone: 1
     │           │ │ ├ Vector{AffExpr} in MOI.PowerCone{Float64}: 20
     │           │ │ ├ VariableRef in MOI.GreaterThan{Float64}: 40
     │           │ │ └ VariableRef in MOI.Parameter{Float64}: 1
     │           │ └ Names registered in the model
     │           │   └ :G, :bgt, :cdev_soc_1, :clp_1, :cslp_1, :decomposition_contract, :dev_1, :k, :lbgt, :lp_1, :lw, :obj_expr, :op, :r_lp_1, :ret, :ret_1, :ret_frontier, :ret_lb_1, :ret_lb_var_1, :ret_vec, :risk, :risk_vec, :sbgt, :sc, :so, :sw, :t_lp_1, :variance_flag, :variance_risk_1, :w, :w_lb, :w_lw, :w_sw, :w_ub
   r ┼ Variance
     │   settings ┼ RiskMeasureSettings
     │            │   scale ┼ Float64: 1.0
     │            │      ub ┼ nothing
     │            │     rke ┴ Bool: true
     │      sigma ┼ 20×20 Matrix{Float64}
     │       chol ┼ nothing
     │         rc ┼ nothing
     │        alg ┴ SquaredSOCRiskExpr()
  fb ┴ nothing

 MeanRiskResult
  jr ┼ JuMPOptimisationResult
     │        pa ┼ ProcessedJuMPOptimiserAttributes
     │           │        pr ┼ LowOrderPrior
     │           │           │       X ┼ 252×20 Matrix{Float64}
     │           │           │     o_X ┼ nothing
     │           │           │      mu ┼ 20-element Vector{Float64}
     │           │           │   sigma ┼ 20×20 Matrix{Float64}
     │           │           │    chol ┼ nothing
     │           │           │       w ┼ nothing
     │           │           │     ens ┼ nothing
     │           │           │     kld ┼ nothing
     │           │           │      ow ┼ nothing
     │           │           │      rr ┼ nothing
     │           │           │     fpr ┼ nothing
     │           │           │       Z ┴ nothing
     │           │        wb ┼ WeightBounds
     │           │           │   lb ┼ 20-element StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64}
     │           │           │   ub ┴ 20-element StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64}
     │           │        lt ┼ nothing
     │           │        st ┼ nothing
     │           │      lcsr ┼ nothing
     │           │       ctr ┼ nothing
     │           │    gcardr ┼ nothing
     │           │   sgcardr ┼ nothing
     │           │      smtx ┼ nothing
     │           │     sgmtx ┼ nothing
     │           │       slt ┼ nothing
     │           │       sst ┼ nothing
     │           │      sglt ┼ nothing
     │           │      sgst ┼ nothing
     │           │        tn ┼ nothing
     │           │      fees ┼ nothing
     │           │       plr ┼ nothing
     │           │       ret ┼ ArithmeticReturn
     │           │           │   settings ┼ JuMPReturnsSettings
     │           │           │            │   scale ┼ Float64: 1.0
     │           │           │            │      lb ┼ Frontier
     │           │           │            │         │        N ┼ Int64: 50
     │           │           │            │         │   factor ┼ Int64: 1
     │           │           │            │         │    bound ┴ LinearBound()
     │           │           │            │     rte ┼ Bool: true
     │           │           │            │     fee ┼ Bool: true
     │           │           │            │     mic ┴ Bool: true
     │           │           │        ucs ┼ nothing
     │           │           │         mu ┴ 20-element Vector{Float64}
     │           │       sca ┴ SumScalariser()
     │   retcode ┼ 50-element Vector{OptimisationSuccess}
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │           │ OptimisationSuccess ⋯
     │       sol ┼ 50-element Vector{JuMPOptimisationSolution}
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │           │ JuMPOptimisationSolution ⋯
     │     model ┼ A JuMP Model
     │           │ ├ solver: Clarabel
     │           │ ├ objective_sense: MIN_SENSE
     │           │ │ └ objective_function_type: QuadExpr
     │           │ ├ num_variables: 63
     │           │ ├ num_constraints: 51
     │           │ │ ├ AffExpr in MOI.EqualTo{Float64}: 3
     │           │ │ ├ AffExpr in MOI.GreaterThan{Float64}: 1
     │           │ │ ├ Vector{AffExpr} in MOI.Nonnegatives: 2
     │           │ │ ├ Vector{AffExpr} in MOI.Nonpositives: 2
     │           │ │ ├ Vector{AffExpr} in MOI.NormInfinityCone: 1
     │           │ │ ├ Vector{AffExpr} in MOI.SecondOrderCone: 1
     │           │ │ ├ VariableRef in MOI.GreaterThan{Float64}: 40
     │           │ │ └ VariableRef in MOI.Parameter{Float64}: 1
     │           │ └ Names registered in the model
     │           │   └ :G, :bgt, :cdev_soc_1, :clinf_nic, :decomposition_contract, :dev_1, :k, :lbgt, :linf, :lw, :obj_expr, :op, :ret, :ret_1, :ret_frontier, :ret_lb_1, :ret_lb_var_1, :ret_vec, :risk, :risk_vec, :sbgt, :sc, :so, :sw, :t_linf, :variance_flag, :variance_risk_1, :w, :w_lb, :w_lw, :w_sw, :w_ub
   r ┼ Variance
     │   settings ┼ RiskMeasureSettings
     │            │   scale ┼ Float64: 1.0
     │            │      ub ┼ nothing
     │            │     rke ┴ Bool: true
     │      sigma ┼ 20×20 Matrix{Float64}
     │       chol ┼ nothing
     │         rc ┼ nothing
     │        alg ┴ SquaredSOCRiskExpr()
  fb ┴ nothing

Let's plot the efficient frontiers.

using StatsPlots, GraphRecipesr = Variance()
Variance
  settings ┼ RiskMeasureSettings
           │   scale ┼ Float64: 1.0
           │      ub ┼ nothing
           │     rke ┴ Bool: true
     sigma ┼ nothing
      chol ┼ nothing
        rc ┼ nothing
       alg ┴ SquaredSOCRiskExpr()

No regularisation portfolio weights.

plot_stacked_area_composition(ress[1].w, rd.nx;                              kwargs = (; xlabel = "Portfolios", ylabel = "Weight",                                        title = "No regularisation", legend = :outerright))
Example block output

No regularisation frontier.

plot_measures(ress[1].w, pr; x = r, y = ExpectedReturn(; rt = ress[1].ret),              c = ExpectedReturnRiskRatio(; rt = ress[1].ret, rk = r, rf = 4.2 / 100 / 252),              title = "No regularisation", xlabel = "Variance",              ylabel = "Arithmetic Return", colorbar_title = "\nRisk/Return Ratio",              right_margin = 6Plots.mm)
Example block output

L1 regularisation portfolio weights. As expected, the portfolio is sparsified, with fewer assets with non-zero weight.

plot_stacked_area_composition(ress[2].w, rd.nx;                              kwargs = (; xlabel = "Portfolios", ylabel = "Weight",                                        title = "L1 regularisation", legend = :outerright))
Example block output

L1 regularisation frontier. The sparsification makes the pareto front non-smooth.

plot_measures(ress[2].w, pr; x = r, y = ExpectedReturn(; rt = ress[2].ret),              c = ExpectedReturnRiskRatio(; rt = ress[1].ret, rk = r, rf = 4.2 / 100 / 252),              title = "L1 regularisation", xlabel = "Variance",              ylabel = "Arithmetic Return", colorbar_title = "\nRisk/Return Ratio",              right_margin = 6Plots.mm)
Example block output

L2 regularisation portfolio weights. Even values of p-norms smooth out the weights, leading to more diversified portfolios. The higher the value, the more highly penalised larger deviations from the mean weight become. This is similar to how moments of even order behave.

plot_stacked_area_composition(ress[3].w, rd.nx;                              kwargs = (; xlabel = "Portfolios", ylabel = "Weight",                                        title = "L2 regularisation", legend = :outerright))
Example block output

L2 regularisation frontier.

plot_measures(ress[3].w, pr; x = r, y = ExpectedReturn(; rt = ress[3].ret),              c = ExpectedReturnRiskRatio(; rt = ress[1].ret, rk = r, rf = 4.2 / 100 / 252),              title = "L2 regularisation", xlabel = "Variance",              ylabel = "Arithmetic Return", colorbar_title = "\nRisk/Return Ratio",              right_margin = 6Plots.mm)
Example block output

Lp regularisation portfolio weights. The higher the value of p, the closer the behaviour is to L-Inf regularisation, where the maximum absolute weight is penalised. This leads to portfolios where all weights are more similar in magnitude, but does not smear the negative weights into positive values like the L2 norm.

plot_stacked_area_composition(ress[4].w, rd.nx;                              kwargs = (; xlabel = "Portfolios", ylabel = "Weight",                                        title = "Lp (p = 5) regularisation",                                        legend = :outerright))
Example block output

Lp regularisation frontier.

plot_measures(ress[4].w, pr; x = r, y = ExpectedReturn(; rt = ress[4].ret),              c = ExpectedReturnRiskRatio(; rt = ress[1].ret, rk = r, rf = 4.2 / 100 / 252),              title = "Lp (p = 5) regularisation", xlabel = "Variance",              ylabel = "Arithmetic Return", colorbar_title = "\nRisk/Return Ratio",              right_margin = 6Plots.mm)
Example block output

L-Inf regularisation portfolio weights.

plot_stacked_area_composition(ress[5].w, rd.nx;                              kwargs = (; xlabel = "Portfolios", ylabel = "Weight",                                        title = "L-Inf regularisation",                                        legend = :outerright))
Example block output

L-Inf regularisation frontier.

plot_measures(ress[5].w, pr; x = r, y = ExpectedReturn(; rt = ress[5].ret),              c = ExpectedReturnRiskRatio(; rt = ress[1].ret, rk = r, rf = 4.2 / 100 / 252),              title = "L-Inf regularisation", xlabel = "Variance",              ylabel = "Arithmetic Return", colorbar_title = "\nRisk/Return Ratio",              right_margin = 6Plots.mm)
Example block output

2.2 Minimum risk portfolios

Lets view only the minimum risk portfolios for each regularisation to get more insight into what regularisation does.

opts = [JuMPOptimiser(; pe = pr, slv = slv, wb = WeightBounds(; lb = -1, ub = 1), sbgt = 1,                      bgt = 1),# no regularisation        JuMPOptimiser(; pe = pr, slv = slv, wb = WeightBounds(; lb = -1, ub = 1), sbgt = 1,                      bgt = 1, l1 = 4e-4),# L1 regularisation        JuMPOptimiser(; pe = pr, slv = slv, wb = WeightBounds(; lb = -1, ub = 1), sbgt = 1,                      bgt = 1, l2 = L2Regularisation(; val = 4e-4)),# L2 regularisation        JuMPOptimiser(; pe = pr, slv = slv, wb = WeightBounds(; lb = -1, ub = 1), sbgt = 1,                      bgt = 1, lp = LpRegularisation(; p = 5, val = 4e-4)),# Lp regularisation with p = 5        JuMPOptimiser(; pe = pr, slv = slv, wb = WeightBounds(; lb = -1, ub = 1), sbgt = 1,                      bgt = 1, linf = 4e-4)]# L-Inf regularisationnocs = [MeanRisk(; opt = opt) for opt in opts]ress = optimise.(nocs)pretty_table(DataFrame(:Assets => rd.nx, :No_Reg => ress[1].w, :L1 => ress[2].w,                       :L2 => ress[3].w, :L5 => ress[4].w, :LInf => ress[5].w);             formatters = [resfmt], summary_rows = [summary_row],             summary_row_labels = ["# Eff. Assets"])
┌───────────────┬────────┬───────────┬──────────┬──────────┬──────────┬──────────┐
│                Assets     No_Reg        L1        L2        L5      LInf │
│                String    Float64   Float64   Float64   Float64   Float64 │
├───────────────┼────────┼───────────┼──────────┼──────────┼──────────┼──────────┤
│               │   AAPL │ -11.866 % │    0.0 % │  1.136 % │ -3.026 % │ -5.751 % │
│               │    AMD │   -1.55 % │    0.0 % │ -2.963 % │ -6.029 % │ -7.437 % │
│               │    BAC │   -5.46 % │    0.0 % │  3.488 % │   4.28 % │  1.181 % │
│               │    BBY │  -3.234 % │    0.0 % │  1.035 % │ -1.015 % │ -1.935 % │
│               │    CVX │   9.487 % │  7.415 % │   6.57 % │  7.553 % │  7.879 % │
│               │     GE │   5.203 % │  0.823 % │  3.871 % │  5.501 % │  6.838 % │
│               │     HD │   3.621 % │    0.0 % │  4.194 % │  6.143 % │  7.879 % │
│               │    JNJ │  40.958 % │ 36.981 % │ 10.221 % │   9.02 % │  7.879 % │
│               │    JPM │   7.738 % │  0.762 % │  4.252 % │  5.446 % │  7.879 % │
│               │     KO │    12.0 % │ 11.098 % │  7.952 % │  8.217 % │  7.879 % │
│               │    LLY │  -7.707 % │    0.0 % │  5.655 % │  6.507 % │  7.878 % │
│               │    MRK │  19.792 % │ 17.462 % │  9.638 % │  8.719 % │  7.879 % │
│               │   MSFT │   8.105 % │    0.0 % │  2.536 % │  4.917 % │  7.071 % │
│               │    PEP │    13.7 % │  8.969 % │  7.992 % │  8.234 % │  7.879 % │
│               │    PFE │  -4.513 % │    0.0 % │  5.999 % │  6.673 % │  7.879 % │
│               │     PG │   1.787 % │  2.399 % │  7.873 % │  8.145 % │  7.879 % │
│               │    RRC │   -1.68 % │    0.0 % │  0.153 % │   -1.8 % │ -2.388 % │
│               │    UNH │  -1.188 % │    0.0 % │  5.939 % │  6.861 % │  7.879 % │
│               │    WMT │   9.161 % │  9.356 % │  8.205 % │   8.32 % │  7.879 % │
│               │    XOM │   5.649 % │  4.734 % │  6.254 % │  7.334 % │  7.879 % │
├───────────────┼────────┼───────────┼──────────┼──────────┼──────────┼──────────┤
│ # Eff. Assets │    N/A │   3.28601 │  4.88263 │  13.8946 │   11.588 │    9.971 │
└───────────────┴────────┴───────────┴──────────┴──────────┴──────────┴──────────┘

The effect of each regularisation depends on the relative values of the objective function with respect to the value of the relevant norm of the optimised portfolio weights multiplied by the penalty.

Generally, regularised portfolios tend to have more effective assets than unregularised ones. The number of effective assets is different to the sparsity in that it measures the concentration of weights as 1/(w ⋅ w), rather than counting the number of non-zero (or near zero) weights. Usually, the larger the number of effective assets, the more diversified the portfolio. Sparsity is a non-smooth measure, while the number of effective assets is smooth, so a portfolio can have higher sparsity and still have a larger number of effective assets.

It is possible to combine multiple regularisation penalties in the same optimisation problem by simultaneously specifying multiple regularisation keywords in the JuMPOptimiser. This can be useful to combine the benefits of different regularisations, such as sparsity and diversification, but can make the optimisation more difficult to solve and interpret.


This page was generated using Literate.jl.