The source files can be found in examples/.

Hyperparameter tuning

Hyperparameter tuning chooses the parameters of an estimator by how they score on the test folds of a cross-validation. This example shows the two searches of PortfolioOptimisers.jl, a grid search and a randomised search.

using PortfolioOptimisers, PrettyTablestsfmt = (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;

1. Setting up

We use the same five years of daily data as the cross-validation example.

As in the cross-validation example, the fields of the estimator you tune must be estimators, not precomputed results. The search fits each candidate again on each fold.

using CSV, TimeSeries, DataFrames, Clarabel, Statistics, StableRNGs, DistributionsX = TimeArray(CSV.File(joinpath(@__DIR__, "..", "SP500.csv.gz")); timestamp = :Date)[(end - 252 * 5):end]pretty_table(X[(end - 5):end]; formatters = [tsfmt])rd = prices_to_returns(X)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. Hyperparameter tuning

We tune a Stacking estimator, and the search works the same way for the other optimisation estimators, such as NestedClustered. A key of the grid is a string with the property path to the parameter, such as "opti[1].opt.l2.val". The search parses the string into an Accessors.jl lens, an object that returns a copy of the estimator with that one field changed.

A search needs a risk measure, r, to score every fold, and a cross-validation scheme, cv, which defaults to KFold. It also accepts a WalkForwardEstimator, a CombinatorialCrossValidation and a MultipleRandomised. Under a combinatorial scheme, it scores each path instead of each fold.

opt = JuMPOptimiser(; slv = slv)#! `l2` is `nothing` by default, and the key `l2.val` needs an `L2Regularisation` in it.optl2 = JuMPOptimiser(; slv = slv, l2 = L2Regularisation())r = MeanReturnRiskRatio(; rk = LowOrderMoment(; alg = SecondMoment()))st = Stacking(; opti = [MeanRisk(; opt = optl2), RiskBudgeting(; opt = opt)],              opto = MeanRisk(; opt = opt))
Stacking
      pe ┼ EmpiricalPrior
         │           ce ┼ PortfolioOptimisersCovariance
         │              │   ce ┼ Covariance
         │              │      │    me ┼ SimpleExpectedReturns
         │              │      │       │   w ┴ nothing
         │              │      │    ce ┼ GeneralCovariance
         │              │      │       │   ce ┼ SimpleCovariance: SimpleCovariance(true)
         │              │      │       │    w ┴ nothing
         │              │      │   alg ┼ FullMoment()
         │              │      │     w ┴ nothing
         │              │   mp ┼ MatrixProcessing
         │              │      │     pdm ┼ Posdef
         │              │      │         │      alg ┼ UnionAll: NearestCorrelationMatrix.Newton
         │              │      │         │   kwargs ┴ @NamedTuple{}: NamedTuple()
         │              │      │      dn ┼ nothing
         │              │      │      dt ┼ nothing
         │              │      │     alg ┼ nothing
         │              │      │   order ┴ NTuple{4, Symbol}: (:pdm, :dn, :dt, :alg)
         │           me ┼ SimpleExpectedReturns
         │              │   w ┴ nothing
         │      horizon ┼ nothing
         │   fill_limit ┼ nothing
         │        x_src ┴ nothing
      wb ┼ nothing
    fees ┼ nothing
    sets ┼ nothing
   scale ┼ nothing
    opti ┼ 2-element Vector{RiskJuMPOptimisationEstimator}
         │ MeanRisk ⋯
         │ RiskBudgeting ⋯
    opto ┼ MeanRisk
         │   opt ┼ JuMPOptimiser
         │       │        pe ┼ EmpiricalPrior
         │       │           │           ce ┼ PortfolioOptimisersCovariance
         │       │           │              │   ce ┼ Covariance
         │       │           │              │      │    me ┼ SimpleExpectedReturns
         │       │           │              │      │       │   w ┴ nothing
         │       │           │              │      │    ce ┼ GeneralCovariance
         │       │           │              │      │       │   ce ┼ SimpleCovariance: SimpleCovariance(true)
         │       │           │              │      │       │    w ┴ nothing
         │       │           │              │      │   alg ┼ FullMoment()
         │       │           │              │      │     w ┴ nothing
         │       │           │              │   mp ┼ MatrixProcessing
         │       │           │              │      │     pdm ┼ Posdef
         │       │           │              │      │         │      alg ┼ UnionAll: NearestCorrelationMatrix.Newton
         │       │           │              │      │         │   kwargs ┴ @NamedTuple{}: NamedTuple()
         │       │           │              │      │      dn ┼ nothing
         │       │           │              │      │      dt ┼ nothing
         │       │           │              │      │     alg ┼ nothing
         │       │           │              │      │   order ┴ NTuple{4, Symbol}: (:pdm, :dn, :dt, :alg)
         │       │           │           me ┼ SimpleExpectedReturns
         │       │           │              │   w ┴ nothing
         │       │           │      horizon ┼ nothing
         │       │           │   fill_limit ┼ nothing
         │       │           │        x_src ┴ nothing
         │       │       slv ┼ 7-element Vector{Solver}
         │       │           │ Solver ⋯
         │       │           │ Solver ⋯
         │       │           │ Solver ⋯
         │       │           │ Solver ⋯
         │       │           │ Solver ⋯
         │       │           │ Solver ⋯
         │       │           │ Solver ⋯
         │       │        wb ┼ WeightBounds
         │       │           │   lb ┼ Float64: 0.0
         │       │           │   ub ┴ Float64: 1.0
         │       │       bgt ┼ Float64: 1.0
         │       │      sbgt ┼ nothing
         │       │      gbgt ┼ nothing
         │       │        lt ┼ nothing
         │       │        st ┼ nothing
         │       │      lcse ┼ nothing
         │       │       cte ┼ nothing
         │       │    gcarde ┼ nothing
         │       │   sgcarde ┼ nothing
         │       │      smtx ┼ nothing
         │       │     sgmtx ┼ nothing
         │       │       slt ┼ nothing
         │       │       sst ┼ nothing
         │       │      sglt ┼ nothing
         │       │      sgst ┼ nothing
         │       │        tn ┼ nothing
         │       │      fees ┼ nothing
         │       │      sets ┼ nothing
         │       │        tr ┼ nothing
         │       │       ple ┼ nothing
         │       │       ret ┼ ArithmeticReturn
         │       │           │   settings ┼ JuMPReturnsSettings
         │       │           │            │   scale ┼ Float64: 1.0
         │       │           │            │      lb ┼ nothing
         │       │           │            │     rte ┼ Bool: true
         │       │           │            │     fee ┼ Bool: true
         │       │           │            │     mic ┴ Bool: true
         │       │           │        ucs ┼ nothing
         │       │           │         mu ┼ nothing
         │       │           │   mtx_sqrt ┴ EigenFallbackSquareRoot()
         │       │       sca ┼ SumScalariser()
         │       │      ccnt ┼ nothing
         │       │      cobj ┼ nothing
         │       │        sc ┼ Int64: 1
         │       │        so ┼ Int64: 1
         │       │        ss ┼ nothing
         │       │      card ┼ nothing
         │       │     scard ┼ nothing
         │       │       l2c ┼ nothing
         │       │       lpc ┼ nothing
         │       │     linfc ┼ nothing
         │       │        l1 ┼ nothing
         │       │        l2 ┼ nothing
         │       │        lp ┼ nothing
         │       │      linf ┼ nothing
         │       │      xbgt ┼ Bool: false
         │       │    strict ┴ Bool: false
         │     r ┼ Variance
         │       │    settings ┼ RiskMeasureSettings
         │       │             │   scale ┼ Float64: 1.0
         │       │             │      ub ┼ nothing
         │       │             │     rke ┴ Bool: true
         │       │       sigma ┼ nothing
         │       │        chol ┼ nothing
         │       │          rc ┼ nothing
         │       │         alg ┼ SquaredSOCRiskExpr()
         │       │    mtx_sqrt ┼ EigenFallbackSquareRoot()
         │       │   ratio_alg ┼ SquareRootRatio()
         │       │      corner ┴ nothing
         │   obj ┼ MinimumRisk()
         │    wi ┼ nothing
         │    fb ┴ nothing
      cv ┼ nothing
      wf ┼ IterativeWeightFinaliser
         │   iter ┴ Int64: 100
      ex ┼ Transducers.ThreadedEx{@NamedTuple{}}: Transducers.ThreadedEx()
      fb ┼ nothing
  strict ┼ Bool: false
    pcol ┴ RenormaliseActive()

GridSearchCrossValidation tries every point of a parameter grid with search_cross_validation, and keeps the point with the best mean test score.

A grid is a vector of pairs. The first item of a pair is the key of a parameter, and the second is a vector of the values to try. A dictionary of the same pairs also works. The search takes the product of the values in a grid. A Dict has no fixed order, which matters to a randomised search, as section 2.2 explains.

You can give a vector of grids. The search expands each grid on its own and joins the results into one list of candidates.

A literal vector of grids whose values have different types has an abstract element type, and the constructor throws a MethodError for it. concrete_typed_array narrows the element type to the union of the types of the grids, which the constructor accepts. A vector of dictionaries needs the same call.

We search four grids, and the search keeps the best candidate over all of them.

p = concrete_typed_array([["opti[2].opt.l1" =>                               range(; start = 0.0005, stop = 0.0008, length = 3),                           "opti[1].opt.l2.val" =>                               range(; start = 0.0004, stop = 0.0007, length = 3)],                          ["opti[1].opt.l2.val" =>                               range(; start = 0.0004, stop = 0.0007, length = 3)],                          ["opti[2].opt.l1" =>                               range(; start = 0.0009, stop = 0.0012, length = 3)],                          ["opti[2]" => [MeanRisk(; opt = opt, obj = MaximumUtility()),                                         MeanRisk(; opt = opt, obj = MaximumRatio())]]])gs_cv = GridSearchCrossValidation(p; r = r)
GridSearchCrossValidation
            p ┼ 4-element Vector{Union{Vector{Pair{String, StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64}}}, Vector{Pair{String, Vector{MeanRisk{JuMPOptimiser{EmpiricalPrior{PortfolioOptimisersCovariance{Covariance{SimpleExpectedReturns{Nothing, Nothing, Nothing}, GeneralCovariance{SimpleCovariance, Nothing, Nothing}, FullMoment, Nothing, Nothing, Nothing}, MatrixProcessing{Posdef{UnionAll, @NamedTuple{}}, Nothing, Nothing, Nothing, NTuple{4, Symbol}}, Nothing}, SimpleExpectedReturns{Nothing, Nothing, Nothing}, Nothing, Nothing, Nothing, Nothing, Nothing}, Vector{Solver{Symbol, UnionAll, __T_settings, @NamedTuple{allow_local::Bool, allow_almost::Bool}, Bool} where __T_settings}, WeightBounds{Float64, Float64}, Float64, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, ArithmeticReturn{JuMPReturnsSettings{Float64, Nothing, Bool, Bool, Bool}, Nothing, Nothing, EigenFallbackSquareRoot}, SumScalariser, Nothing, Nothing, Int64, Int64, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Bool, Bool, Nothing}, Variance{RiskMeasureSettings{Float64, Nothing, Bool}, Nothing, Nothing, Nothing, SquaredSOCRiskExpr, EigenFallbackSquareRoot, SquareRootRatio, Nothing}, __T_obj, Nothing, Nothing} where __T_obj}}}}}
           cv ┼ KFold
              │                   n ┼ Int64: 5
              │         purged_size ┼ Int64: 0
              │        embargo_size ┼ Int64: 0
              │                  wd ┼ nothing
              │                  fa ┼ nothing
              │   store_weight_path ┼ Bool: false
              │              strict ┴ Bool: false
            r ┼ MeanReturnRiskRatio
              │   settings ┼ HierarchicalRiskMeasureSettings
              │            │   scale ┴ Float64: 1.0
              │         rt ┼ MeanReturn
              │            │   settings ┼ HierarchicalRiskMeasureSettings
              │            │            │   scale ┴ Float64: 1.0
              │            │          w ┼ nothing
              │            │       flag ┴ Bool: false
              │         rk ┼ LowOrderMoment
              │            │   settings ┼ RiskMeasureSettings
              │            │            │   scale ┼ Float64: 1.0
              │            │            │      ub ┼ nothing
              │            │            │     rke ┴ Bool: true
              │            │          w ┼ nothing
              │            │         mu ┼ nothing
              │            │        alg ┼ SecondMoment
              │            │            │     ve ┼ SimpleVariance
              │            │            │        │          me ┼ nothing
              │            │            │        │           w ┼ nothing
              │            │            │        │   corrected ┴ Bool: true
              │            │            │   alg1 ┼ FullMoment()
              │            │            │   alg2 ┴ SquaredSOCRiskExpr()
              │        sca ┼ SumScalariser()
              │         rf ┴ Float64: 0.0
       scorer ┼ HighestMeanScore()
           ex ┼ Transducers.ThreadedEx{@NamedTuple{}}: Transducers.ThreadedEx()
  train_score ┼ Bool: false
       kwargs ┴ @NamedTuple{}: NamedTuple()

We run the search. The four grids give 3 × 3 + 3 + 3 + 2 = 17 candidates. The result has these fields.

  • opt is the best estimator.
  • test_scores has one row per fold and one column per candidate.
  • train_scores is nothing unless you set train_score = true.
  • lens_grid and val_grid give the keys and the values of every candidate.
  • idx is the index of the best candidate.

The best candidate has the highest mean test score. The search negates a measure for which a lower value is better, such as a risk measure, and keeps a ratio as it is. Here the measure is a ratio, and the highest mean ratio wins.

gs_res1 = search_cross_validation(st, gs_cv, rd)
SearchCrossValidationResult
           opt ┼ Stacking
               │       pe ┼ EmpiricalPrior
               │          │           ce ┼ PortfolioOptimisersCovariance
               │          │              │   ce ┼ Covariance
               │          │              │      │    me ┼ SimpleExpectedReturns
               │          │              │      │       │   w ┴ nothing
               │          │              │      │    ce ┼ GeneralCovariance
               │          │              │      │       │   ce ┼ SimpleCovariance: SimpleCovariance(true)
               │          │              │      │       │    w ┴ nothing
               │          │              │      │   alg ┼ FullMoment()
               │          │              │      │     w ┴ nothing
               │          │              │   mp ┼ MatrixProcessing
               │          │              │      │     pdm ┼ Posdef
               │          │              │      │         │      alg ┼ UnionAll: NearestCorrelationMatrix.Newton
               │          │              │      │         │   kwargs ┴ @NamedTuple{}: NamedTuple()
               │          │              │      │      dn ┼ nothing
               │          │              │      │      dt ┼ nothing
               │          │              │      │     alg ┼ nothing
               │          │              │      │   order ┴ NTuple{4, Symbol}: (:pdm, :dn, :dt, :alg)
               │          │           me ┼ SimpleExpectedReturns
               │          │              │   w ┴ nothing
               │          │      horizon ┼ nothing
               │          │   fill_limit ┼ nothing
               │          │        x_src ┴ nothing
               │       wb ┼ nothing
               │     fees ┼ nothing
               │     sets ┼ nothing
               │    scale ┼ nothing
               │     opti ┼ 2-element Vector{RiskJuMPOptimisationEstimator}
               │          │ MeanRisk ⋯
               │          │ RiskBudgeting ⋯
               │     opto ┼ MeanRisk
               │          │   opt ┼ JuMPOptimiser
               │          │       │        pe ┼ EmpiricalPrior
               │          │       │           │           ce ┼ PortfolioOptimisersCovariance
               │          │       │           │              │   ce ┼ Covariance
               │          │       │           │              │      │    me ┼ SimpleExpectedReturns
               │          │       │           │              │      │       │   w ┴ nothing
               │          │       │           │              │      │    ce ┼ GeneralCovariance
               │          │       │           │              │      │       │   ce ┼ SimpleCovariance: SimpleCovariance(true)
               │          │       │           │              │      │       │    w ┴ nothing
               │          │       │           │              │      │   alg ┼ FullMoment()
               │          │       │           │              │      │     w ┴ nothing
               │          │       │           │              │   mp ┼ MatrixProcessing
               │          │       │           │              │      │     pdm ┼ Posdef
               │          │       │           │              │      │         │      alg ┼ UnionAll: NearestCorrelationMatrix.Newton
               │          │       │           │              │      │         │   kwargs ┴ @NamedTuple{}: NamedTuple()
               │          │       │           │              │      │      dn ┼ nothing
               │          │       │           │              │      │      dt ┼ nothing
               │          │       │           │              │      │     alg ┼ nothing
               │          │       │           │              │      │   order ┴ NTuple{4, Symbol}: (:pdm, :dn, :dt, :alg)
               │          │       │           │           me ┼ SimpleExpectedReturns
               │          │       │           │              │   w ┴ nothing
               │          │       │           │      horizon ┼ nothing
               │          │       │           │   fill_limit ┼ nothing
               │          │       │           │        x_src ┴ nothing
               │          │       │       slv ┼ 7-element Vector{Solver}
               │          │       │           │ Solver ⋯
               │          │       │           │ Solver ⋯
               │          │       │           │ Solver ⋯
               │          │       │           │ Solver ⋯
               │          │       │           │ Solver ⋯
               │          │       │           │ Solver ⋯
               │          │       │           │ Solver ⋯
               │          │       │        wb ┼ WeightBounds
               │          │       │           │   lb ┼ Float64: 0.0
               │          │       │           │   ub ┴ Float64: 1.0
               │          │       │       bgt ┼ Float64: 1.0
               │          │       │      sbgt ┼ nothing
               │          │       │      gbgt ┼ nothing
               │          │       │        lt ┼ nothing
               │          │       │        st ┼ nothing
               │          │       │      lcse ┼ nothing
               │          │       │       cte ┼ nothing
               │          │       │    gcarde ┼ nothing
               │          │       │   sgcarde ┼ nothing
               │          │       │      smtx ┼ nothing
               │          │       │     sgmtx ┼ nothing
               │          │       │       slt ┼ nothing
               │          │       │       sst ┼ nothing
               │          │       │      sglt ┼ nothing
               │          │       │      sgst ┼ nothing
               │          │       │        tn ┼ nothing
               │          │       │      fees ┼ nothing
               │          │       │      sets ┼ nothing
               │          │       │        tr ┼ nothing
               │          │       │       ple ┼ nothing
               │          │       │       ret ┼ ArithmeticReturn
               │          │       │           │   settings ┼ JuMPReturnsSettings
               │          │       │           │            │   scale ┼ Float64: 1.0
               │          │       │           │            │      lb ┼ nothing
               │          │       │           │            │     rte ┼ Bool: true
               │          │       │           │            │     fee ┼ Bool: true
               │          │       │           │            │     mic ┴ Bool: true
               │          │       │           │        ucs ┼ nothing
               │          │       │           │         mu ┼ nothing
               │          │       │           │   mtx_sqrt ┴ EigenFallbackSquareRoot()
               │          │       │       sca ┼ SumScalariser()
               │          │       │      ccnt ┼ nothing
               │          │       │      cobj ┼ nothing
               │          │       │        sc ┼ Int64: 1
               │          │       │        so ┼ Int64: 1
               │          │       │        ss ┼ nothing
               │          │       │      card ┼ nothing
               │          │       │     scard ┼ nothing
               │          │       │       l2c ┼ nothing
               │          │       │       lpc ┼ nothing
               │          │       │     linfc ┼ nothing
               │          │       │        l1 ┼ nothing
               │          │       │        l2 ┼ nothing
               │          │       │        lp ┼ nothing
               │          │       │      linf ┼ nothing
               │          │       │      xbgt ┼ Bool: false
               │          │       │    strict ┴ Bool: false
               │          │     r ┼ Variance
               │          │       │    settings ┼ RiskMeasureSettings
               │          │       │             │   scale ┼ Float64: 1.0
               │          │       │             │      ub ┼ nothing
               │          │       │             │     rke ┴ Bool: true
               │          │       │       sigma ┼ nothing
               │          │       │        chol ┼ nothing
               │          │       │          rc ┼ nothing
               │          │       │         alg ┼ SquaredSOCRiskExpr()
               │          │       │    mtx_sqrt ┼ EigenFallbackSquareRoot()
               │          │       │   ratio_alg ┼ SquareRootRatio()
               │          │       │      corner ┴ nothing
               │          │   obj ┼ MinimumRisk()
               │          │    wi ┼ nothing
               │          │    fb ┴ nothing
               │       cv ┼ nothing
               │       wf ┼ IterativeWeightFinaliser
               │          │   iter ┴ Int64: 100
               │       ex ┼ Transducers.ThreadedEx{@NamedTuple{}}: Transducers.ThreadedEx()
               │       fb ┼ nothing
               │   strict ┼ Bool: false
               │     pcol ┴ RenormaliseActive()
   test_scores ┼ 5×17 Matrix{Float64}
  train_scores ┼ nothing
     lens_grid ┼ 17-element Vector{Vector{ComposedFunction{O, Accessors.PropertyLens{:opti}} where O}}
      val_grid ┼ 17-element Vector{Tuple{Any, Vararg{Float64}}}
           idx ┴ Int64: 6

The table gives the keys and the values of the best candidate. The loop after it prints every value next to the same field read from the chosen estimator.

pretty_table(DataFrame("Lens" => gs_res1.lens_grid[gs_res1.idx],                       "Value" => collect(gs_res1.val_grid[gs_res1.idx])))for (lens, val) in zip(gs_res1.lens_grid[gs_res1.idx], gs_res1.val_grid[gs_res1.idx])    println("$(lpad("lens:", 12)) $lens\n$(lpad("val:", 12)) $val\n$(lpad("Field value:", 12)) $(lens(gs_res1.opt))\n")end
┌────────────────────────────────────────────────────────────┬─────────┐
│                                                       Lens │   Value │
│ ComposedFunction{O, Accessors.PropertyLens{:opti}} where O │ Float64 │
├────────────────────────────────────────────────────────────┼─────────┤
│                                           _.opti[2].opt.l1 │  0.0008 │
│                                       _.opti[1].opt.l2.val │ 0.00055 │
└────────────────────────────────────────────────────────────┴─────────┘
       lens: (@o _.opti[2].opt.l1)
        val: 0.0008
Field value: 0.0008

       lens: (@o _.opti[1].opt.l2.val)
        val: 0.00055
Field value: 0.00055

We optimise the best estimator on the full data and plot its weights.

using StatsPlots, GraphRecipesres_gs1 = optimise(gs_res1.opt, rd)plot_composition(res_gs1, rd)
Example block output

RandomisedSearchCrossValidation samples values from the grid, and then runs a grid search over the samples with search_cross_validation. It takes the same grids as GridSearchCrossValidation. A parameter can also take a Distributions.Distribution in place of a vector of values.

The search samples every parameter on its own, and n_iter sets the number of samples.

  • From a distribution, it draws n_iter values.
  • From a vector, it draws min(n_iter, length(v)) values. It draws without replacement, unless the grid also holds a distribution. Then it draws with replacement, and it can draw a value twice.

Then it takes the product of the samples in each grid, as the grid search does. A vector of grids works as it does for GridSearchCrossValidation.

The search draws from one random number generator, rng, grid by grid and parameter by parameter. The order of the grids and of the parameters therefore changes the samples. To repeat a search, keep that order fixed. Use an OrderedDict from OrderedCollections or a vector for each grid.

2.2.1 Sampling from a predefined parameter space

We sample from the same grids as before, with n_iter = 2. Every value is in a vector. The search draws two values for each parameter, without replacement.

rs_cv1 = RandomisedSearchCrossValidation(p; rng = StableRNG(42), r = r, n_iter = 2)
RandomisedSearchCrossValidation
            p ┼ 4-element Vector{Union{Vector{Pair{String, StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64}}}, Vector{Pair{String, Vector{MeanRisk{JuMPOptimiser{EmpiricalPrior{PortfolioOptimisersCovariance{Covariance{SimpleExpectedReturns{Nothing, Nothing, Nothing}, GeneralCovariance{SimpleCovariance, Nothing, Nothing}, FullMoment, Nothing, Nothing, Nothing}, MatrixProcessing{Posdef{UnionAll, @NamedTuple{}}, Nothing, Nothing, Nothing, NTuple{4, Symbol}}, Nothing}, SimpleExpectedReturns{Nothing, Nothing, Nothing}, Nothing, Nothing, Nothing, Nothing, Nothing}, Vector{Solver{Symbol, UnionAll, __T_settings, @NamedTuple{allow_local::Bool, allow_almost::Bool}, Bool} where __T_settings}, WeightBounds{Float64, Float64}, Float64, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, ArithmeticReturn{JuMPReturnsSettings{Float64, Nothing, Bool, Bool, Bool}, Nothing, Nothing, EigenFallbackSquareRoot}, SumScalariser, Nothing, Nothing, Int64, Int64, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Bool, Bool, Nothing}, Variance{RiskMeasureSettings{Float64, Nothing, Bool}, Nothing, Nothing, Nothing, SquaredSOCRiskExpr, EigenFallbackSquareRoot, SquareRootRatio, Nothing}, __T_obj, Nothing, Nothing} where __T_obj}}}}}
           cv ┼ KFold
              │                   n ┼ Int64: 5
              │         purged_size ┼ Int64: 0
              │        embargo_size ┼ Int64: 0
              │                  wd ┼ nothing
              │                  fa ┼ nothing
              │   store_weight_path ┼ Bool: false
              │              strict ┴ Bool: false
            r ┼ MeanReturnRiskRatio
              │   settings ┼ HierarchicalRiskMeasureSettings
              │            │   scale ┴ Float64: 1.0
              │         rt ┼ MeanReturn
              │            │   settings ┼ HierarchicalRiskMeasureSettings
              │            │            │   scale ┴ Float64: 1.0
              │            │          w ┼ nothing
              │            │       flag ┴ Bool: false
              │         rk ┼ LowOrderMoment
              │            │   settings ┼ RiskMeasureSettings
              │            │            │   scale ┼ Float64: 1.0
              │            │            │      ub ┼ nothing
              │            │            │     rke ┴ Bool: true
              │            │          w ┼ nothing
              │            │         mu ┼ nothing
              │            │        alg ┼ SecondMoment
              │            │            │     ve ┼ SimpleVariance
              │            │            │        │          me ┼ nothing
              │            │            │        │           w ┼ nothing
              │            │            │        │   corrected ┴ Bool: true
              │            │            │   alg1 ┼ FullMoment()
              │            │            │   alg2 ┴ SquaredSOCRiskExpr()
              │        sca ┼ SumScalariser()
              │         rf ┴ Float64: 0.0
       scorer ┼ HighestMeanScore()
           ex ┼ Transducers.ThreadedEx{@NamedTuple{}}: Transducers.ThreadedEx()
       n_iter ┼ Int64: 2
          rng ┼ StableRNGs.LehmerRNG: StableRNGs.LehmerRNG(state=0x00000000000000000000000000000055)
         seed ┼ nothing
  train_score ┼ Bool: false
       kwargs ┴ @NamedTuple{}: NamedTuple()

The first grid has two parameters and gives 2 × 2 = 4 candidates. The other three grids give 2 candidates each, for 4 + 2 + 2 + 2 = 10 in total.

rs_res1 = search_cross_validation(st, rs_cv1, rd)
SearchCrossValidationResult
           opt ┼ Stacking
               │       pe ┼ EmpiricalPrior
               │          │           ce ┼ PortfolioOptimisersCovariance
               │          │              │   ce ┼ Covariance
               │          │              │      │    me ┼ SimpleExpectedReturns
               │          │              │      │       │   w ┴ nothing
               │          │              │      │    ce ┼ GeneralCovariance
               │          │              │      │       │   ce ┼ SimpleCovariance: SimpleCovariance(true)
               │          │              │      │       │    w ┴ nothing
               │          │              │      │   alg ┼ FullMoment()
               │          │              │      │     w ┴ nothing
               │          │              │   mp ┼ MatrixProcessing
               │          │              │      │     pdm ┼ Posdef
               │          │              │      │         │      alg ┼ UnionAll: NearestCorrelationMatrix.Newton
               │          │              │      │         │   kwargs ┴ @NamedTuple{}: NamedTuple()
               │          │              │      │      dn ┼ nothing
               │          │              │      │      dt ┼ nothing
               │          │              │      │     alg ┼ nothing
               │          │              │      │   order ┴ NTuple{4, Symbol}: (:pdm, :dn, :dt, :alg)
               │          │           me ┼ SimpleExpectedReturns
               │          │              │   w ┴ nothing
               │          │      horizon ┼ nothing
               │          │   fill_limit ┼ nothing
               │          │        x_src ┴ nothing
               │       wb ┼ nothing
               │     fees ┼ nothing
               │     sets ┼ nothing
               │    scale ┼ nothing
               │     opti ┼ 2-element Vector{RiskJuMPOptimisationEstimator}
               │          │ MeanRisk ⋯
               │          │ RiskBudgeting ⋯
               │     opto ┼ MeanRisk
               │          │   opt ┼ JuMPOptimiser
               │          │       │        pe ┼ EmpiricalPrior
               │          │       │           │           ce ┼ PortfolioOptimisersCovariance
               │          │       │           │              │   ce ┼ Covariance
               │          │       │           │              │      │    me ┼ SimpleExpectedReturns
               │          │       │           │              │      │       │   w ┴ nothing
               │          │       │           │              │      │    ce ┼ GeneralCovariance
               │          │       │           │              │      │       │   ce ┼ SimpleCovariance: SimpleCovariance(true)
               │          │       │           │              │      │       │    w ┴ nothing
               │          │       │           │              │      │   alg ┼ FullMoment()
               │          │       │           │              │      │     w ┴ nothing
               │          │       │           │              │   mp ┼ MatrixProcessing
               │          │       │           │              │      │     pdm ┼ Posdef
               │          │       │           │              │      │         │      alg ┼ UnionAll: NearestCorrelationMatrix.Newton
               │          │       │           │              │      │         │   kwargs ┴ @NamedTuple{}: NamedTuple()
               │          │       │           │              │      │      dn ┼ nothing
               │          │       │           │              │      │      dt ┼ nothing
               │          │       │           │              │      │     alg ┼ nothing
               │          │       │           │              │      │   order ┴ NTuple{4, Symbol}: (:pdm, :dn, :dt, :alg)
               │          │       │           │           me ┼ SimpleExpectedReturns
               │          │       │           │              │   w ┴ nothing
               │          │       │           │      horizon ┼ nothing
               │          │       │           │   fill_limit ┼ nothing
               │          │       │           │        x_src ┴ nothing
               │          │       │       slv ┼ 7-element Vector{Solver}
               │          │       │           │ Solver ⋯
               │          │       │           │ Solver ⋯
               │          │       │           │ Solver ⋯
               │          │       │           │ Solver ⋯
               │          │       │           │ Solver ⋯
               │          │       │           │ Solver ⋯
               │          │       │           │ Solver ⋯
               │          │       │        wb ┼ WeightBounds
               │          │       │           │   lb ┼ Float64: 0.0
               │          │       │           │   ub ┴ Float64: 1.0
               │          │       │       bgt ┼ Float64: 1.0
               │          │       │      sbgt ┼ nothing
               │          │       │      gbgt ┼ nothing
               │          │       │        lt ┼ nothing
               │          │       │        st ┼ nothing
               │          │       │      lcse ┼ nothing
               │          │       │       cte ┼ nothing
               │          │       │    gcarde ┼ nothing
               │          │       │   sgcarde ┼ nothing
               │          │       │      smtx ┼ nothing
               │          │       │     sgmtx ┼ nothing
               │          │       │       slt ┼ nothing
               │          │       │       sst ┼ nothing
               │          │       │      sglt ┼ nothing
               │          │       │      sgst ┼ nothing
               │          │       │        tn ┼ nothing
               │          │       │      fees ┼ nothing
               │          │       │      sets ┼ nothing
               │          │       │        tr ┼ nothing
               │          │       │       ple ┼ nothing
               │          │       │       ret ┼ ArithmeticReturn
               │          │       │           │   settings ┼ JuMPReturnsSettings
               │          │       │           │            │   scale ┼ Float64: 1.0
               │          │       │           │            │      lb ┼ nothing
               │          │       │           │            │     rte ┼ Bool: true
               │          │       │           │            │     fee ┼ Bool: true
               │          │       │           │            │     mic ┴ Bool: true
               │          │       │           │        ucs ┼ nothing
               │          │       │           │         mu ┼ nothing
               │          │       │           │   mtx_sqrt ┴ EigenFallbackSquareRoot()
               │          │       │       sca ┼ SumScalariser()
               │          │       │      ccnt ┼ nothing
               │          │       │      cobj ┼ nothing
               │          │       │        sc ┼ Int64: 1
               │          │       │        so ┼ Int64: 1
               │          │       │        ss ┼ nothing
               │          │       │      card ┼ nothing
               │          │       │     scard ┼ nothing
               │          │       │       l2c ┼ nothing
               │          │       │       lpc ┼ nothing
               │          │       │     linfc ┼ nothing
               │          │       │        l1 ┼ nothing
               │          │       │        l2 ┼ nothing
               │          │       │        lp ┼ nothing
               │          │       │      linf ┼ nothing
               │          │       │      xbgt ┼ Bool: false
               │          │       │    strict ┴ Bool: false
               │          │     r ┼ Variance
               │          │       │    settings ┼ RiskMeasureSettings
               │          │       │             │   scale ┼ Float64: 1.0
               │          │       │             │      ub ┼ nothing
               │          │       │             │     rke ┴ Bool: true
               │          │       │       sigma ┼ nothing
               │          │       │        chol ┼ nothing
               │          │       │          rc ┼ nothing
               │          │       │         alg ┼ SquaredSOCRiskExpr()
               │          │       │    mtx_sqrt ┼ EigenFallbackSquareRoot()
               │          │       │   ratio_alg ┼ SquareRootRatio()
               │          │       │      corner ┴ nothing
               │          │   obj ┼ MinimumRisk()
               │          │    wi ┼ nothing
               │          │    fb ┴ nothing
               │       cv ┼ nothing
               │       wf ┼ IterativeWeightFinaliser
               │          │   iter ┴ Int64: 100
               │       ex ┼ Transducers.ThreadedEx{@NamedTuple{}}: Transducers.ThreadedEx()
               │       fb ┼ nothing
               │   strict ┼ Bool: false
               │     pcol ┴ RenormaliseActive()
   test_scores ┼ 5×10 Matrix{Float64}
  train_scores ┼ nothing
     lens_grid ┼ 10-element Vector{Vector{ComposedFunction{O, Accessors.PropertyLens{:opti}} where O}}
      val_grid ┼ 10-element Vector{Tuple{Any, Vararg{Float64}}}
           idx ┴ Int64: 6

We read the best candidate of the randomised search in the same way.

pretty_table(DataFrame("Lens" => rs_res1.lens_grid[rs_res1.idx],                       "Value" => collect(rs_res1.val_grid[rs_res1.idx])))for (lens, val) in zip(rs_res1.lens_grid[rs_res1.idx], rs_res1.val_grid[rs_res1.idx])    println("$(lpad("lens:", 12)) $lens\n$(lpad("val:", 12)) $val\n$(lpad("Field value:", 12)) $(lens(rs_res1.opt))\n")endres_rs1 = optimise(rs_res1.opt, rd)plot_composition(res_rs1, rd)
Example block output

2.2.2 Sampling from a distribution

We now mix vectors and distributions, with n_iter = 5. This grid needs no concrete_typed_array. A distribution among the values makes the literal a vector of vectors of Pair{String, Any}, which the constructor of RandomisedSearchCrossValidation accepts. The constructor checks that every value is a vector or a distribution. A grid of vectors alone still needs concrete_typed_array.

p = [["opti[2].opt.l1" => range(; start = 0.0005, stop = 0.0008, length = 3),      "opti[1].opt.l2.val" => LogUniform(0.0003, 0.1)],     ["opti[1].opt.l2.val" => LogUniform(0.001, 0.1)],     ["opti[2].opt.l1" => range(; start = 0.0009, stop = 0.0012, length = 3)],     ["opti[2]" => [MeanRisk(; opt = opt, obj = MaximumUtility()),                    MeanRisk(; opt = opt, obj = MaximumRatio())]]]rs_cv2 = RandomisedSearchCrossValidation(p; rng = StableRNG(42), r = r, n_iter = 5)
RandomisedSearchCrossValidation
            p ┼ 4-element Vector{Vector{Pair{String, Any}}}
           cv ┼ KFold
              │                   n ┼ Int64: 5
              │         purged_size ┼ Int64: 0
              │        embargo_size ┼ Int64: 0
              │                  wd ┼ nothing
              │                  fa ┼ nothing
              │   store_weight_path ┼ Bool: false
              │              strict ┴ Bool: false
            r ┼ MeanReturnRiskRatio
              │   settings ┼ HierarchicalRiskMeasureSettings
              │            │   scale ┴ Float64: 1.0
              │         rt ┼ MeanReturn
              │            │   settings ┼ HierarchicalRiskMeasureSettings
              │            │            │   scale ┴ Float64: 1.0
              │            │          w ┼ nothing
              │            │       flag ┴ Bool: false
              │         rk ┼ LowOrderMoment
              │            │   settings ┼ RiskMeasureSettings
              │            │            │   scale ┼ Float64: 1.0
              │            │            │      ub ┼ nothing
              │            │            │     rke ┴ Bool: true
              │            │          w ┼ nothing
              │            │         mu ┼ nothing
              │            │        alg ┼ SecondMoment
              │            │            │     ve ┼ SimpleVariance
              │            │            │        │          me ┼ nothing
              │            │            │        │           w ┼ nothing
              │            │            │        │   corrected ┴ Bool: true
              │            │            │   alg1 ┼ FullMoment()
              │            │            │   alg2 ┴ SquaredSOCRiskExpr()
              │        sca ┼ SumScalariser()
              │         rf ┴ Float64: 0.0
       scorer ┼ HighestMeanScore()
           ex ┼ Transducers.ThreadedEx{@NamedTuple{}}: Transducers.ThreadedEx()
       n_iter ┼ Int64: 5
          rng ┼ StableRNGs.LehmerRNG: StableRNGs.LehmerRNG(state=0x00000000000000000000000000000055)
         seed ┼ nothing
  train_score ┼ Bool: false
       kwargs ┴ @NamedTuple{}: NamedTuple()

The first grid holds a distribution. The search draws 5 values from it, and 3 values with replacement from the vector of three. The second grid gives 5 values from its distribution. The third and fourth grids hold only vectors and give their 3 and 2 values. That makes 3 × 5 + 5 + 3 + 2 = 25 candidates. A draw with replacement can repeat a value, and then two candidates are the same.

rs_res2 = search_cross_validation(st, rs_cv2, rd)
SearchCrossValidationResult
           opt ┼ Stacking
               │       pe ┼ EmpiricalPrior
               │          │           ce ┼ PortfolioOptimisersCovariance
               │          │              │   ce ┼ Covariance
               │          │              │      │    me ┼ SimpleExpectedReturns
               │          │              │      │       │   w ┴ nothing
               │          │              │      │    ce ┼ GeneralCovariance
               │          │              │      │       │   ce ┼ SimpleCovariance: SimpleCovariance(true)
               │          │              │      │       │    w ┴ nothing
               │          │              │      │   alg ┼ FullMoment()
               │          │              │      │     w ┴ nothing
               │          │              │   mp ┼ MatrixProcessing
               │          │              │      │     pdm ┼ Posdef
               │          │              │      │         │      alg ┼ UnionAll: NearestCorrelationMatrix.Newton
               │          │              │      │         │   kwargs ┴ @NamedTuple{}: NamedTuple()
               │          │              │      │      dn ┼ nothing
               │          │              │      │      dt ┼ nothing
               │          │              │      │     alg ┼ nothing
               │          │              │      │   order ┴ NTuple{4, Symbol}: (:pdm, :dn, :dt, :alg)
               │          │           me ┼ SimpleExpectedReturns
               │          │              │   w ┴ nothing
               │          │      horizon ┼ nothing
               │          │   fill_limit ┼ nothing
               │          │        x_src ┴ nothing
               │       wb ┼ nothing
               │     fees ┼ nothing
               │     sets ┼ nothing
               │    scale ┼ nothing
               │     opti ┼ 2-element Vector{RiskJuMPOptimisationEstimator}
               │          │ MeanRisk ⋯
               │          │ RiskBudgeting ⋯
               │     opto ┼ MeanRisk
               │          │   opt ┼ JuMPOptimiser
               │          │       │        pe ┼ EmpiricalPrior
               │          │       │           │           ce ┼ PortfolioOptimisersCovariance
               │          │       │           │              │   ce ┼ Covariance
               │          │       │           │              │      │    me ┼ SimpleExpectedReturns
               │          │       │           │              │      │       │   w ┴ nothing
               │          │       │           │              │      │    ce ┼ GeneralCovariance
               │          │       │           │              │      │       │   ce ┼ SimpleCovariance: SimpleCovariance(true)
               │          │       │           │              │      │       │    w ┴ nothing
               │          │       │           │              │      │   alg ┼ FullMoment()
               │          │       │           │              │      │     w ┴ nothing
               │          │       │           │              │   mp ┼ MatrixProcessing
               │          │       │           │              │      │     pdm ┼ Posdef
               │          │       │           │              │      │         │      alg ┼ UnionAll: NearestCorrelationMatrix.Newton
               │          │       │           │              │      │         │   kwargs ┴ @NamedTuple{}: NamedTuple()
               │          │       │           │              │      │      dn ┼ nothing
               │          │       │           │              │      │      dt ┼ nothing
               │          │       │           │              │      │     alg ┼ nothing
               │          │       │           │              │      │   order ┴ NTuple{4, Symbol}: (:pdm, :dn, :dt, :alg)
               │          │       │           │           me ┼ SimpleExpectedReturns
               │          │       │           │              │   w ┴ nothing
               │          │       │           │      horizon ┼ nothing
               │          │       │           │   fill_limit ┼ nothing
               │          │       │           │        x_src ┴ nothing
               │          │       │       slv ┼ 7-element Vector{Solver}
               │          │       │           │ Solver ⋯
               │          │       │           │ Solver ⋯
               │          │       │           │ Solver ⋯
               │          │       │           │ Solver ⋯
               │          │       │           │ Solver ⋯
               │          │       │           │ Solver ⋯
               │          │       │           │ Solver ⋯
               │          │       │        wb ┼ WeightBounds
               │          │       │           │   lb ┼ Float64: 0.0
               │          │       │           │   ub ┴ Float64: 1.0
               │          │       │       bgt ┼ Float64: 1.0
               │          │       │      sbgt ┼ nothing
               │          │       │      gbgt ┼ nothing
               │          │       │        lt ┼ nothing
               │          │       │        st ┼ nothing
               │          │       │      lcse ┼ nothing
               │          │       │       cte ┼ nothing
               │          │       │    gcarde ┼ nothing
               │          │       │   sgcarde ┼ nothing
               │          │       │      smtx ┼ nothing
               │          │       │     sgmtx ┼ nothing
               │          │       │       slt ┼ nothing
               │          │       │       sst ┼ nothing
               │          │       │      sglt ┼ nothing
               │          │       │      sgst ┼ nothing
               │          │       │        tn ┼ nothing
               │          │       │      fees ┼ nothing
               │          │       │      sets ┼ nothing
               │          │       │        tr ┼ nothing
               │          │       │       ple ┼ nothing
               │          │       │       ret ┼ ArithmeticReturn
               │          │       │           │   settings ┼ JuMPReturnsSettings
               │          │       │           │            │   scale ┼ Float64: 1.0
               │          │       │           │            │      lb ┼ nothing
               │          │       │           │            │     rte ┼ Bool: true
               │          │       │           │            │     fee ┼ Bool: true
               │          │       │           │            │     mic ┴ Bool: true
               │          │       │           │        ucs ┼ nothing
               │          │       │           │         mu ┼ nothing
               │          │       │           │   mtx_sqrt ┴ EigenFallbackSquareRoot()
               │          │       │       sca ┼ SumScalariser()
               │          │       │      ccnt ┼ nothing
               │          │       │      cobj ┼ nothing
               │          │       │        sc ┼ Int64: 1
               │          │       │        so ┼ Int64: 1
               │          │       │        ss ┼ nothing
               │          │       │      card ┼ nothing
               │          │       │     scard ┼ nothing
               │          │       │       l2c ┼ nothing
               │          │       │       lpc ┼ nothing
               │          │       │     linfc ┼ nothing
               │          │       │        l1 ┼ nothing
               │          │       │        l2 ┼ nothing
               │          │       │        lp ┼ nothing
               │          │       │      linf ┼ nothing
               │          │       │      xbgt ┼ Bool: false
               │          │       │    strict ┴ Bool: false
               │          │     r ┼ Variance
               │          │       │    settings ┼ RiskMeasureSettings
               │          │       │             │   scale ┼ Float64: 1.0
               │          │       │             │      ub ┼ nothing
               │          │       │             │     rke ┴ Bool: true
               │          │       │       sigma ┼ nothing
               │          │       │        chol ┼ nothing
               │          │       │          rc ┼ nothing
               │          │       │         alg ┼ SquaredSOCRiskExpr()
               │          │       │    mtx_sqrt ┼ EigenFallbackSquareRoot()
               │          │       │   ratio_alg ┼ SquareRootRatio()
               │          │       │      corner ┴ nothing
               │          │   obj ┼ MinimumRisk()
               │          │    wi ┼ nothing
               │          │    fb ┴ nothing
               │       cv ┼ nothing
               │       wf ┼ IterativeWeightFinaliser
               │          │   iter ┴ Int64: 100
               │       ex ┼ Transducers.ThreadedEx{@NamedTuple{}}: Transducers.ThreadedEx()
               │       fb ┼ nothing
               │   strict ┼ Bool: false
               │     pcol ┴ RenormaliseActive()
   test_scores ┼ 5×25 Matrix{Float64}
  train_scores ┼ nothing
     lens_grid ┼ 25-element Vector{Vector{ComposedFunction{O, Accessors.PropertyLens{:opti}} where O}}
      val_grid ┼ 25-element Vector{Tuple{Any, Vararg{Float64}}}
           idx ┴ Int64: 4

We read off the best candidate of the second search.

pretty_table(DataFrame("Lens" => rs_res2.lens_grid[rs_res2.idx],                       "Value" => collect(rs_res2.val_grid[rs_res2.idx])))for (lens, val) in zip(rs_res2.lens_grid[rs_res2.idx], rs_res2.val_grid[rs_res2.idx])    println("$(lpad("lens:", 12)) $lens\n$(lpad("val:", 12)) $val\n$(lpad("Field value:", 12)) $(lens(rs_res2.opt))\n")endres_rs2 = optimise(rs_res2.opt, rd)plot_composition(res_rs2, rd)
Example block output

The plot puts the weights of the three best portfolios side by side: the grid search, the randomised search over vectors, and the randomised search with distributions.

plot_stacked_bar_composition([res_gs1, res_rs1, res_rs2], rd)
Example block output

You can tune any estimator that cross-validation accepts. You can also tune a Pipeline, and the pipelines example tunes an asset filter and a gap fill.


This page was generated using Literate.jl.