Skip to content
13

Base

01_Base.jl implements the most basal symbols used in PortfolioOptimisers.jl.

PortfolioOptimisers Module

PortfolioOptimisers.jl

CategoryBadge
Docs[
Stable Documentation
](https://dcelisgarza.github.io/PortfolioOptimisers.jl/stable) [
Development documentation
](https://dcelisgarza.github.io/PortfolioOptimisers.jl/dev)
CI[
Test workflow status
](https://github.com/dcelisgarza/PortfolioOptimisers.jl/actions/workflows/Test.yml?query=branch%3Amain) [
Docs workflow Status
](https://github.com/dcelisgarza/PortfolioOptimisers.jl/actions/workflows/Docs.yml?query=branch%3Amain) [
Aqua
](https://github.com/dcelisgarza/PortfolioOptimisers.jl/actions/workflows/Aqua.yml)
Coverage[
Coverage
](https://codecov.io/gh/dcelisgarza/PortfolioOptimisers.jl)
Contribute[
Contributor Covenant
](https://github.com/dcelisgarza/PortfolioOptimisers.jl/blob/main/CODE_OF_CONDUCT.md)
Misc[
BestieTemplate
](https://github.com/JuliaBesties/BestieTemplate.jl)

<!– Build Status DOI –>

<!– All Contributors –>

Investing conveys real risk, the entire point of portfolio optimisation is to minimise it to tolerable levels. The examples use outdated data and a variety of stocks (including what I consider to be meme stocks) for demonstration purposes only. None of the information in this documentation should be taken as financial advice. Any advice is limited to improving portfolio construction, most of which is common investment and statistical knowledge.

Portfolio optimisation is the science of either:

  • Minimising risk whilst keeping returns to acceptable levels.

  • Maximising returns whilst keeping risk to acceptable levels.

To some definition of acceptable, and with any number of additional constraints available to the optimisation type.

There exist myriad statistical, pre- and post-processing, optimisations, and constraints that allow one to explore an extensive landscape of "optimal" portfolios.

PortfolioOptimisers.jl is an attempt at providing as many of these as possible under a single banner. We make extensive use of Julia's type system, module extensions, and multiple dispatch to simplify development and maintenance.

Please visit the documentation for details on the vast feature list.

Installation

PortfolioOptimisers.jl is a registered package, so installation is as simple as:

julia
julia> using Pkg

julia> Pkg.add(PackageSpec(; name = "PortfolioOptimisers"))

Roadmap

  • For a roadmap of planned and desired features in no particular order please refer to Issue #37.

  • Some docstrings are incomplete and/or outdated, please refer to Issue #58 for details on what docstrings have been completed in the dev branch.

Quick-start

The library is quite powerful and extremely flexible. Here is what a very basic end-to-end workflow can look like. The examples contain more thorough explanations and demos. The API docs contain toy examples of the many, many features.

First we import the packages we will need for the example.

  • StatsPlots and GraphRecipes is needed to load the plotting extension.

  • Clarabel and HiGHS are the optimisers we will use.

  • YFinance and TimeSeries for downloading and preprocessing price data.

  • PrettyTables and DataFrames for displaying the results.

julia
# Import module and plotting extension.
using PortfolioOptimisers, StatsPlots, GraphRecipes
# Import optimisers.
using Clarabel, HiGHS
# Download data.
using YFinance, TimeSeries
# Pretty printing.
using PrettyTables, DataFrames

# Format for pretty tables.
fmt1 = (v, i, j) -> begin
    if j == 1
        return Date(v)
    else
        return v
    end
end;
fmt2 = (v, i, j) -> begin
    if j  (1, 2, 3)
        return v
    else
        return isa(v, Number) ? "$(round(v*100, digits=3)) %" : v
    end
end

# Function to convert prices to time array.
function stock_price_to_time_array(x)
    # Only get the keys that are not ticker or datetime.
    coln = collect(keys(x))[3:end]
    # Convert the dictionary into a matrix.
    m = hcat([x[k] for k in coln]...)
    return TimeArray(x["timestamp"], m, Symbol.(coln), x["ticker"])
end

# Tickers to download. These are popular meme stocks, use something better.
assets = sort!(["SOUN", "RIVN", "GME", "AMC", "SOFI", "ENVX", "ANVS", "LUNR", "EOSE", "SMR",
                "NVAX", "UPST", "ACHR", "RKLB", "MARA", "LGVN", "LCID", "CHPT", "MAXN",
                "BB"])

# Prices date range.
Date_0 = "2024-01-01"
Date_1 = "2025-10-05"

# Download the price data using YFinance.
prices = get_prices.(assets; startdt = Date_0, enddt = Date_1)
prices = stock_price_to_time_array.(prices)
prices = hcat(prices...)
cidx = colnames(prices)[occursin.(r"adj", string.(colnames(prices)))]
prices = prices[cidx]
TimeSeries.rename!(prices, Symbol.(assets))
pretty_table(prices[(end - 5):end]; formatters = [fmt1])

# Compute the returns.
rd = prices_to_returns(prices)

# Define the continuous solver.
slv = Solver(; name = :clarabel1, solver = Clarabel.Optimizer,
             settings = Dict("verbose" => false, "max_step_fraction" => 0.9),
             check_sol = (; allow_local = true, allow_almost = true))

# `PortfolioOptimisers.jl` implements a number of optimisation types as estimators. All the ones which use mathematical optimisation require a `JuMPOptimiser` structure which defines general solver constraints. This structure in turn requires an instance (or vector) of `Solver`.
opt = JuMPOptimiser(; slv = slv);

# Vanilla (Markowitz) mean risk optimisation, i.e. minimum variance portfolio
mr = MeanRisk(; opt = opt)

# Perform the optimisation, res.w contains the optimal weights.
res = optimise(mr, rd)

# Define the MIP solver for finite discrete allocation.
mip_slv = Solver(; name = :highs1, solver = HiGHS.Optimizer,
                 settings = Dict("log_to_console" => false),
                 check_sol = (; allow_local = true, allow_almost = true));

# Discrete finite allocation.
da = DiscreteAllocation(; slv = mip_slv)

# Perform the finite discrete allocation, uses the final asset
# prices, and an available cash amount. This is for us mortals
# without infinite wealth.
mip_res = optimise(da, res.w, vec(values(prices[end])), 4206.90)

df = DataFrame(:assets => rd.nx, :shares => mip_res.shares, :cost => mip_res.cost,
               :opt_weights => res.w, :mip_weights => mip_res.w)
pretty_table(df; formatters = [fmt2])

# Plot the portfolio cumulative returns of the finite allocation portfolio.
plot_ptf_cumulative_returns(mip_res.w, rd.X; ts = rd.ts, compound = true)
Fig. 1
julia
# Furthermore, we can also plot the risk contribution per asset. For this, we must provide an instance of the risk measure we want to use with the appropriate statistics/parameters. We can do this by using the `factory` function (recommended when doing so programmatically), or manually set the quantities ourselves.
plot_risk_contribution(factory(Variance(), res.pr), mip_res.w, rd.X; nx = rd.nx,
                       percentage = true)

# This awkwardness is due to the fact that `PortfolioOptimisers.jl` tries to decouple the risk measures from optimisation estimators and results. However, the advantage of this approach is that it lets us use multiple different risk measures as part of the risk expression, or as risk limits in optimisations. We explore this further in the [examples](https://dcelisgarza.github.io/PortfolioOptimisers.jl/stable/examples/00_Examples_Introduction).
Fig. 2
julia
# We can also plot the returns' histogram and probability density.
plot_histogram(mip_res.w, rd.X; slv = slv)
Fig. 3
julia
# Plot compounded or uncompounded drawdowns.
plot_drawdowns(mip_res.w, rd.X; slv = slv, ts = rd.ts, compound = true)
Fig. 4source

Base abstract types

PortfolioOptimisers.jl is designed in a deliberately structured and hierarchical way. Enabling us to create self-contained, independent, composable processes. These abstract types form the basis of this hierarchy.

PortfolioOptimisers.AbstractEstimator Type
julia
abstract type AbstractEstimator

Abstract supertype for all estimator types in PortfolioOptimisers.jl.

All custom estimators should subtype AbstractEstimator.

Estimators consume data to estimate parameters or models. Some estimators may utilise different algorithms. These can range from simple implementation details that don't change the result much but may have different numerical characteristics, to entirely different methodologies or algorithms yielding different results.

Related

source
PortfolioOptimisers.AbstractAlgorithm Type
julia
abstract type AbstractAlgorithm

Abstract supertype for all algorithm types in PortfolioOptimisers.jl.

All algorithms should subtype AbstractAlgorithm.

Algorithms are often used by estimators to perform specific tasks. These can be in the form of simple implementation details to entirely different procedures for estimating a quantity.

Related

source
PortfolioOptimisers.AbstractResult Type
julia
abstract type AbstractResult

Abstract supertype for all result types in PortfolioOptimisers.jl.

All result objects should subtype AbstractResult.

Result types encapsulate the outcomes of estimators. This makes dispatch and usage more straightforward, especially when the results encapsulate a wide range of information.

Related

source
PortfolioOptimisers.DynamicAbstractWeights Type
julia
abstract type DynamicAbstractWeights <: AbstractEstimator

Abstract supertype for dynamically computed observation weight estimators.

DynamicAbstractWeights subtypes are used when observation weights must be computed from data (rather than supplied directly as a numeric vector). They are passed to estimators that accept an ObsWeights argument and evaluated at fit time.

Interfaces

In order to implement a new dynamic observation weight estimator which will work seamlessly with the library, subtype DynamicAbstractWeights with all necessary parameters struct, and implement the following methods:

  • get_observation_weights(w::DynamicAbstractWeights, X::VecNum; kwargs...) -> StatsBase.AbstractWeights: Returns observation weights for a 1D vector X.

  • get_observation_weights(w::DynamicAbstractWeights, X::MatNum; dims::Int = 1, kwargs...) -> StatsBase.AbstractWeights: Returns observation weights for a 2D matrix X, with dims specifying the dimension along which to compute weights.

Arguments

  • w: Subtype of DynamicAbstractWeights with all necessary parameters.

  • X: Data matrix or vector.

  • dims: Dimension along which to compute weights for a 2D matrix X.

  • kwargs...: Additional keyword arguments passed to the weight computation function.

Returns

  • w::StatsBase.AbstractWeights: Observation weights for the input data X.

Examples

We can create a dummy dynamic observation weight estimator as follows:

julia
julia> struct MyWeights{T} <: PortfolioOptimisers.DynamicAbstractWeights
           half_life::T
           function MyWeights(half_life::Integer)
               if half_life < one(half_life)
                   throw(ArgumentError("half_life must be a positive integer"))
               end
               return new{typeof(half_life)}(half_life)
           end
       end

julia> function MyWeights(; half_life::Integer = 5)
           return MyWeights(half_life)
       end
MyWeights

julia> function PortfolioOptimisers.get_observation_weights(w::PortfolioOptimisers.DynamicAbstractWeights,
                                                            X::PortfolioOptimisers.VecNum;
                                                            kwargs...)
           lambda = 2^(-inv(w.half_life))
           return eweights(1:length(X), lambda; scale = true)
       end

julia> function PortfolioOptimisers.get_observation_weights(w::PortfolioOptimisers.DynamicAbstractWeights,
                                                            X::PortfolioOptimisers.MatNum;
                                                            dims::Int = 1, kwargs...)
           lambda = 2^(-inv(w.half_life))
           return eweights(1:size(X, dims), lambda; scale = true)
       end

julia> PortfolioOptimisers.get_observation_weights(MyWeights(), 1:10)
10-element Weights{Float64, Float64, Vector{Float64}}:
 1.0207079199119523e-8
 7.88499313633082e-8
 6.091176089370138e-7
 4.705448122809607e-6
 3.63496994859362e-5
 0.00028080229942667527
 0.002169204490777577
 0.016757156662950766
 0.12944943670387588
 1.0

julia> PortfolioOptimisers.get_observation_weights(MyWeights(), ones(3, 10); dims = 2)
10-element Weights{Float64, Float64, Vector{Float64}}:
 1.0207079199119523e-8
 7.88499313633082e-8
 6.091176089370138e-7
 4.705448122809607e-6
 3.63496994859362e-5
 0.00028080229942667527
 0.002169204490777577
 0.016757156662950766
 0.12944943670387588
 1.0

Related

source

Pretty printing

PortfolioOptimisers.jl's types tend to contain quite a lot of information, these functions enable pretty printing so they are easier to interpret.

PortfolioOptimisers.@define_pretty_show Macro
julia
define_pretty_show(T, flag::Bool = true)

Macro to define a custom pretty-printing Base.show method for types in PortfolioOptimisers.jl.

This macro generates a show method that displays the type name and all fields in a readable, aligned format. For fields that are themselves custom types or collections, the macro recursively applies pretty-printing for nested structures. Handles compact and multiline IO contexts gracefully.

Arguments

  • T: The type for which to define the pretty-printing method.

Returns

  • Defines a Base.show(io::IO, obj::T) method for the given type.

Details

  • Prints the type name and all fields with aligned labels.

  • Recursively pretty-prints nested custom types and collections.

  • Handles compact and multiline IO contexts.

  • Displays matrix fields with their size and type.

  • Lists a vector of pretty-printable structs as a "N-element Vector{Name}" summary followed by one collapsed line per element (each a wrapper-type name, with a trailing " ⋯" when the element has fields). Long listings are truncated head-and-tail with a "⋮" line, bounded by compact_show_budget.

  • Collapses an oversized nested struct field to Name ⋯ when its rendered height exceeds compact_show_budget; see set_compact_show!.

  • Skips fields that are not present or are nothing.

Related

source
PortfolioOptimisers.has_pretty_show_method Function
julia
has_pretty_show_method(_) -> Bool

Default method indicating whether a type has a custom pretty-printing show method.

Overloading this method to return true indicates that type already has a custom pretty-printing method.

Arguments

  • ::Any: Any type.

Returns

  • flag::Bool: false by default, indicating no custom pretty-printing method.

Related

source
PortfolioOptimisers.set_compact_show! Function
julia
set_compact_show!(x::Bool)
set_compact_show!(n::Integer)

Configure whether @define_pretty_show collapses large nested structs.

  • set_compact_show!(false): disable collapsing (always expand fully).

  • set_compact_show!(true): enable collapsing with an automatic, terminal-size-derived budget.

  • set_compact_show!(n): enable collapsing with a fixed line budget n.

Collapsing only ever applies to height-limited output (get(io, :limit, false)), i.e. the interactive REPL. Non-limited output (string, repr, file writes) always expands fully. The documentation build disables this so rendered docs keep full detail. Individual calls can override the global setting with the :po_compact IO property (false, true, or an Int).

Related

source
PortfolioOptimisers.COMPACT_SHOW Constant

Global control for collapsing large nested structs in @define_pretty_show output.

Holds one of:

  • false: collapsing disabled; nested structs always expand fully.

  • true: collapsing enabled with an automatic, terminal-size-derived line budget.

  • n::Int: collapsing enabled with a fixed line budget of n.

Set via set_compact_show!. Read (together with the per-call :po_compact IO property) by compact_show_budget.

source
PortfolioOptimisers.compact_show_budget Function
julia
compact_show_budget(io::IO) -> Any

Resolve the line budget that triggers collapsing a nested struct rendered by @define_pretty_show.

The per-call :po_compact IO property takes precedence over the global COMPACT_SHOW setting; both accept false (disabled), true (automatic budget), or an Int (fixed budget). The automatic budget is max(8, displaysize(io)[1] - 4), so only subtrees that nearly fill or exceed the terminal collapse.

Returns

  • nothing when collapsing is disabled.

  • budget::Int (the maximum number of rendered lines a nested struct may occupy before collapsing) otherwise.

Related

source
PortfolioOptimisers.pretty_show_vector_summary Function
julia
pretty_show_vector_summary(val::AbstractVector) -> String

Build the single-line summary for a vector field rendered by @define_pretty_show.

Returns a string of the form "N-element Vector{Name}". A vector is treated as homogeneous when every element shares the same wrapper-type name (so elements that differ only in type parameters are still homogeneous): a homogeneous vector uses that common wrapper name, otherwise the wrapper of the element type, falling back to the raw eltype for Unions.

Arguments

  • val: Non-empty vector whose elements all have a custom pretty-printing method.

Returns

  • summary::String: Single-line "N-element Vector{Name}" summary.

Related

source
PortfolioOptimisers.pretty_show_vector_element Function
julia
pretty_show_vector_element(v) -> String

Render a single vector element as a collapsed line for @define_pretty_show.

Every element of a listed vector is shown as just its wrapper-type name. When the element is a struct with fields, a trailing " ⋯" marks it as a collapsed struct (consistent with how an over-budget struct field collapses to Name ⋯); fieldless elements are left bare.

Related

source
PortfolioOptimisers.pretty_show_vector_body Function
julia
pretty_show_vector_body(
    io::IO,
    lines::AbstractVector{<:AbstractString}
) -> Any

Apply the shared collapse budget to the per-element lines of a vector rendered by @define_pretty_show.

The budget comes from compact_show_budget, so vector truncation honours the same :limit gate, global set_compact_show! setting, and per-call :po_compact override as struct collapsing. When the budget is nothing (disabled, unlimited output, or override-off) every line is returned. Otherwise, when the listing exceeds the budget it is split head-and-tail, mirroring how Base truncates long arrays, with a single "⋮" line marking the elision.

Arguments

Returns

  • body::Vector{String}: Lines to print, possibly truncated with a "⋮" separator.

Related

source

Utilities

Custom types are the bread and butter of PorfolioOptimisers.jl, the following types and utilities are non-specific and used throughout the library.

PortfolioOptimisers.VecScalar Type
julia
struct VecScalar{__T_v, __T_s} <: AbstractResult

Represents a composite result containing a vector and a scalar in PortfolioOptimisers.jl.

Encapsulates a vector and a scalar value, commonly used for storing results that combine both types of data (e.g., weighted statistics, risk measures).

Fields

  • v: Vector component.

  • s: Scalar component.

Constructors

julia
VecScalar(;
    v::VecNum,
    s::Number
) -> VecScalar

Keywords correspond to the struct's fields.

Validation

  • v: !isempty(v) and all(isfinite, v).

  • s: isfinite(s).

Examples

julia
julia> VecScalar([1.0, 2.0, 3.0], 4.2)
VecScalar
  v ┼ Vector{Float64}: [1.0, 2.0, 3.0]
  s ┴ Float64: 4.2

Related

source
PortfolioOptimisers.AbstractEstimatorValueAlgorithm Type
julia
abstract type AbstractEstimatorValueAlgorithm <: AbstractAlgorithm

Abstract supertype for all estimator value algorithm types in PortfolioOptimisers.jl.

Subtypes of AbstractEstimatorValueAlgorithm implement algorithms for computing constraint result values. These are used to extend or modify the behavior of estimators in a composable and modular fashion.

Interfaces

In order to implement a new estimator value algorithm which will work seamlessly with the library, subtype AbstractEstimatorValueAlgorithm with all necessary parameters struct, and implement the following method:

  • estimator_to_val(alg::AbstractEstimatorValueAlgorithm, sets::AssetSets, val::Option{<:Number} = nothing, key::Option{<:AbstractString} = nothing; datatype::DataType = Float64, strict::Bool = false) -> Num_VecNum: Converts an estimator value dictionary to a numeric or vector of numeric value. Usually this should compute some version of:
    • val = ifelse(isnothing(val), <default value use with datatype element type>, val): Computes the default value to use if val is nothing.

    • nx = sets.dict[ifelse(isnothing(key), sets.key, key)]: Gets the universe to use for mapping values to features.

Arguments

  • alg: Concrete subtype of AbstractEstimatorValueAlgorithm.

  • sets: Sets used to map estimator values to features.

  • val: Default value to use for the estimator. If nothing, the estimator provides the default value.

  • key: Key to specify the asset universe in sets.dict. If nothing, the key is taken from sets.key.

  • datatype: Data type to use for the result in case val is nothing.

  • strict: Whether to throw an error if sets does not contain the desired value in sets.dict[key].

Returns

  • val::Num_VecNum: The numeric or vector of numeric value.

Examples

We can create a dummy estimator value algorithm as follows:

julia
julia> struct MyIncreasingValue <: PortfolioOptimisers.AbstractEstimatorValueAlgorithm end

julia> function PortfolioOptimisers.estimator_to_val(alg::MyIncreasingValue, sets::AssetSets,
                                                     val::PortfolioOptimisers.Option{<:Number} = nothing,
                                                     key::PortfolioOptimisers.Option{<:AbstractString} = nothing;
                                                     datatype::DataType = Float64,
                                                     strict::Bool = false)
           val = ifelse(isnothing(val), zero(datatype), val)
           nx = sets.dict[ifelse(isnothing(key), sets.key, key)]
           arr = ((1 - val):(length(nx) - val))
           return arr
       end

julia> sets = AssetSets(; dict = Dict("nx" => ["sha", "bis", "man"]))
AssetSets
   key ┼ String: "nx"
  ukey ┼ String: "ux"
  dict ┴ Dict{String, Vector{String}}: Dict("nx" => ["sha", "bis", "man"])

julia> estimator_to_val(MyIncreasingValue(), sets)
1.0:1.0:3.0

Related

source
PortfolioOptimisers.get_observation_weights Function
julia
get_observation_weights(
    w::Option{<:ObsWeights},
    args...;
    kwargs...
) -> Option{<:VecNum}

Get the observation weights for statistical estimation.

Arguments

  • w: Optional observation weights vector observations × 1, or a concrete subtype of DynamicAbstractWeights. If nothing, the computation is unweighted.

  • args: Additional positional arguments (ignored).

  • kwargs: Additional keyword arguments (ignored).

Returns

Related

source

Error types

Many of the types defined in PortfolioOptimisers.jl make use of extensive data validation to ensure values meet various criteria. This simplifies the implementation of methods, and improves performance and by delegating as many checks as possible to variable instantiation. In cases where validation cannot be performed at variable instantiation, they are performed as soon as possible within functions.

PortfolioOptimisers.jl aims to catch potential data validation issues as soon as possible and in an informative manner, in order to do so it makes use of a few custom error types.

PortfolioOptimisers.PortfolioOptimisersError Type
julia
abstract type PortfolioOptimisersError <: Exception

Abstract supertype for all custom exception types in PortfolioOptimisers.jl.

All error types specific to PortfolioOptimisers.jl should be subtypes of PortfolioOptimisersError.

Related

source
Base.showerror Method
julia
showerror(io::IO, err::PortfolioOptimisersError) -> Any

Print human-readable representation of PortfolioOptimisersError subtypes to io, stripping parametric type suffixes.

source
PortfolioOptimisers.IsNothingError Type
julia
struct IsNothingError{__T_msg} <: PortfolioOptimisersError

Exception type thrown when an argument or value is unexpectedly nothing.

Fields

  • msg: Error message describing the condition that triggered the exception.

Constructors

julia
IsNothingError(msg)

Arguments correspond to the fields above.

Examples

julia
julia> throw(IsNothingError("Input data must not be nothing"))
ERROR: IsNothingError: Input data must not be nothing
Stacktrace:
 [1] top-level scope
   @ none:1

Related

source
PortfolioOptimisers.IsEmptyError Type
julia
struct IsEmptyError{__T_msg} <: PortfolioOptimisersError

Exception type thrown when an argument or value is unexpectedly empty.

Fields

  • msg: Error message describing the condition that triggered the exception.

Constructors

julia
IsEmptyError(msg)

Arguments correspond to the fields above.

Examples

julia
julia> throw(IsEmptyError("Input array must not be empty"))
ERROR: IsEmptyError: Input array must not be empty
Stacktrace:
 [1] top-level scope
   @ none:1

Related

source
PortfolioOptimisers.IsNonFiniteError Type
julia
struct IsNonFiniteError{__T_msg} <: PortfolioOptimisersError

Exception type thrown when an argument or value is unexpectedly non-finite (e.g., contains NaN or Inf).

Fields

  • msg: Error message describing the condition that triggered the exception.

Constructors

julia
IsNonFiniteError(msg)

Arguments correspond to the fields above.

Examples

julia
julia> throw(IsNonFiniteError("Input array contains non-finite values"))
ERROR: IsNonFiniteError: Input array contains non-finite values
Stacktrace:
 [1] top-level scope
   @ none:1

Related

source

Assertions

In order to increase correctness, robustness, and safety, we make extensive use of defensive programming. The following functions perform some of these validations and are usually called at variable instantiation.

PortfolioOptimisers.assert_nonempty_nonneg_finite_val Function
julia
assert_nonempty_nonneg_finite_val(
    val::Union{<:AbstractDict, <:VecPair, <:ArrNum, Pair, Number},
    val_sym::Union{Symbol,<:AbstractString} = :val
)
assert_nonempty_nonneg_finite_val(args...)

Validate that the input value is non-empty, non-negative and finite.

Arguments

  • val: Input value to validate.

  • val_sym: Symbolic name used in the error messages.

Returns

  • nothing.

Details

  • val: Input value to validate.
    • ::AbstractDict: !isempty(val), any(isfinite, values(val)), all(x -> x >= 0, values(val)).

    • ::VecPair: !isempty(val), any(isfinite, getindex.(val, 2)), all(x -> x[2] >= 0, val).

    • ::ArrNum: !isempty(val), any(isfinite, val), all(x -> x >= 0, val).

    • ::Pair: isfinite(val[2]) and val[2] >= 0.

    • ::Number: isfinite(val) and val >= 0.

    • args...: Always passes.

Related

source
PortfolioOptimisers.assert_nonempty_gt0_finite_val Function
julia
assert_nonempty_gt0_finite_val(
    val::Union{<:AbstractDict, <:VecPair, <:ArrNum, Pair, Number},
    val_sym::Union{Symbol,<:AbstractString} = :val
)
assert_nonempty_gt0_finite_val(args...)

Validate that the input value is non-empty, greater than zero, and finite.

Arguments

  • val: Input value to validate.

  • val_sym: Symbolic name used in the error messages.

Returns

  • nothing.

Details

  • val: Input value to validate.
    • ::AbstractDict: !isempty(val), any(isfinite, values(val)), all(x -> x > 0, values(val)).

    • ::VecPair: !isempty(val), any(isfinite, getindex.(val, 2)), all(x -> x[2] > 0, val).

    • ::ArrNum: !isempty(val), any(isfinite, val), all(x -> x > 0, val).

    • ::Pair: isfinite(val[2]) and val[2] > 0.

    • ::Number: isfinite(val) and val > 0.

    • args...: Always passes.

Related

source
PortfolioOptimisers.assert_nonempty_finite_val Function
julia
assert_nonempty_finite_val(
    val::Union{<:AbstractDict, <:VecPair, <:ArrNum, Pair, Number},
    val_sym::Union{Symbol,<:AbstractString} = :val
)
assert_nonempty_finite_val(args...)

Validate that the input value is non-empty and finite.

Arguments

  • val: Input value to validate.

  • val_sym: Symbolic name used in the error messages.

Returns

  • nothing.

Details

  • val: Input value to validate.
    • ::AbstractDict: !isempty(val), any(isfinite, values(val)).

    • ::VecPair: !isempty(val), any(isfinite, getindex.(val, 2)).

    • ::ArrNum: !isempty(val), any(isfinite, val).

    • ::Pair: isfinite(val[2]).

    • ::Number: isfinite(val).

    • args...: Always passes.

Related

source
PortfolioOptimisers.assert_matrix_issquare Function
julia
assert_matrix_issquare(X::MatNum, X_sym::Symbol = :X)

Assert that the input matrix is square.

Arguments

  • X: Input matrix to validate.

  • X_sym: Symbolic name used in error messages.

Returns

  • nothing.

Validation

  • size(X, 1) == size(X, 2).

Details

  • Throws DimensionMismatch if the check fails.

Related

source

Base type aliases

PortfolioOptimisers.jl heavily relies on Julia's dispatch and type system to ensure data validity. Many custom types and functions/methods can accept different data types. These can be represented as type unions, many of which are used throughout the library. The following type aliases centralise these union definitions, as well as improving correctness and maintainability.

PortfolioOptimisers.Option Type
julia
const Option{T} = Union{Nothing, T}

Alias for an optional value of type T, which may be nothing.

Related

source
PortfolioOptimisers.VecNum Type
julia
abstract type AbstractArray{var"#s21"<:(Union{var"#s20", var"#s19"} where {var"#s20"<:Number, var"#s19"<:AbstractJuMPScalar}), 1}

Alias for an abstract vector of numeric types or JuMP scalar types.

Related

source
PortfolioOptimisers.VecInt Type
julia
abstract type AbstractArray{var"#s21"<:Integer, 1}

Alias for an abstract vector of integer types.

Related

source
PortfolioOptimisers.MatNum Type
julia
abstract type AbstractArray{var"#s21"<:(Union{var"#s20", var"#s19"} where {var"#s20"<:Number, var"#s19"<:AbstractJuMPScalar}), 2}

Alias for an abstract matrix of numeric types or JuMP scalar types.

Related

source
PortfolioOptimisers.ArrNum Type
julia
abstract type AbstractArray{var"#s21"<:(Union{var"#s20", var"#s19"} where {var"#s20"<:Number, var"#s19"<:AbstractJuMPScalar}), N}

Alias for an abstract array of numeric types or JuMP scalar types.

Related

source
PortfolioOptimisers.VecNum_MatNum Type
julia
const VecNum_MatNum = Union{<:VecNum, <:MatNum}

Alias for a union of a numeric type or an abstract matrix of numeric types.

Related

source
PortfolioOptimisers.Num_VecNum Type
julia
const Num_VecNum = Union{<:Number, <:VecNum}

Alias for a union of a numeric type or an abstract vector of numeric types.

Related

source
PortfolioOptimisers.Func_Num_VecNum Type
julia
const Func_Num_VecNum = Union{<:Function, <:Num_VecNum}

Alias for a union of a function type or a numeric type or an abstract vector of numeric types.

Related

source
PortfolioOptimisers.Num_ArrNum Type
julia
const Num_ArrNum = Union{<:Number, <:ArrNum}

Alias for a union of a numeric type or an abstract array of numeric types.

Related

source
PortfolioOptimisers.PairStrNum Type
julia
struct Pair{var"#s21"<:AbstractString, var"#s20"<:Number}

Alias for a pair consisting of an abstract string and a numeric type.

Related

source
PortfolioOptimisers.DictStrNum Type
julia
abstract type AbstractDict{var"#s21"<:AbstractString, var"#s20"<:Number}

Alias for an abstract dictionary with string keys and numeric values.

Related

source
PortfolioOptimisers.MultiEstValType Type
julia
const MultiEstValType = Union{<:DictStrNum, <:AbstractVector{<:PairStrNum}}

Alias for a union of a dictionary with string keys and numeric values, or a vector of string-number pairs.

Related

source
PortfolioOptimisers.EstValType Type
julia
const EstValType = Union{<:Num_VecNum, <:MatNum, <:PairStrNum, <:MultiEstValType,
                         <:AbstractEstimatorValueAlgorithm}

Alias for a union of numeric, vector of numeric, matrix of numeric, string-number pair, or multi-estimator value types.

Related

source
PortfolioOptimisers.PairGSCV Type
julia
struct Pair{var"#s21"<:(Union{Expr, Symbol, var"#s21", var"#s20", var"#s19", var"#s18"} where {var"#s21"<:AbstractString, var"#s20"<:ComposedFunction, var"#s19"<:Accessors.PropertyLens, var"#s18"<:Accessors.IndexLens}), var"#s20"<:(AbstractVector)}

Alias for a pair consisting of an abstract string and an abstract vector.

Related

source
PortfolioOptimisers.DictGSCV Type
julia
abstract type AbstractDict{var"#s21"<:(Union{Expr, Symbol, var"#s21", var"#s20", var"#s19", var"#s18"} where {var"#s21"<:AbstractString, var"#s20"<:ComposedFunction, var"#s19"<:Accessors.PropertyLens, var"#s18"<:Accessors.IndexLens}), var"#s20"<:(AbstractVector)}

Alias for an abstract dictionary with string keys and abstract vector values.

Related

source
PortfolioOptimisers.GSCVKey Type

Alias for a key type used in grid search cross-validation, which can be an abstract string, an expression, a symbol, a composed function, or an accessor lens.

Related

source
PortfolioOptimisers.RSCVVal Type

Alias for a value type used in randomised search cross-validation, which can be an abstract vector or a distribution.

Related

source
PortfolioOptimisers.MultiGSCVValType Type
julia
const MultiGSCVValType = Union{<:DictGSCV, <:AbstractVector{<:PairGSCV}}

Alias for a union of an abstract dictionary with string keys and abstract vector values, or a vector of string-vector pairs.

Related

source
PortfolioOptimisers.VecMultiGSCVValType Type
julia
abstract type AbstractArray{var"#s21"<:(Union{var"#s21", var"#s20"} where {var"#s21"<:(AbstractDict{<:Union{Expr, Symbol, var"#s21", var"#s20", var"#s19", var"#s18"} where {var"#s21"<:AbstractString, var"#s20"<:ComposedFunction, var"#s19"<:Accessors.PropertyLens, var"#s18"<:Accessors.IndexLens}, <:AbstractVector}), var"#s20"<:(AbstractVector{<:Pair{<:Union{Expr, Symbol, var"#s21", var"#s20", var"#s19", var"#s18"} where {var"#s21"<:AbstractString, var"#s20"<:ComposedFunction, var"#s19"<:Accessors.PropertyLens, var"#s18"<:Accessors.IndexLens}, <:AbstractVector}})}), 1}

Alias for an abstract vector of MultiGSCVValType elements.

Related

source
PortfolioOptimisers.MultiGSCVValType_VecMultiGSCVValType Type
julia
const MultiGSCVValType_VecMultiGSCVValType = Union{<:MultiGSCVValType,
                                                   <:VecMultiGSCVValType}

Alias for a union of MultiGSCVValType and VecMultiGSCVValType elements.

Related

source
PortfolioOptimisers.Str_Expr Type
julia
const Str_Expr = Union{<:AbstractString, Expr}

Alias for a union of abstract string or Julia expression.

Related

source
PortfolioOptimisers.VecStr_Expr Type
julia
abstract type AbstractArray{var"#s21"<:(Union{Expr, var"#s21"} where var"#s21"<:AbstractString), 1}

Alias for an abstract vector of strings or Julia expressions.

Related

source
PortfolioOptimisers.EqnType Type
julia
const EqnType = Union{<:AbstractString, Expr, <:VecStr_Expr}

Alias for a union of string, Julia expression, or vector of strings/expressions.

Related

source
PortfolioOptimisers.VecVecNum Type
julia
abstract type AbstractArray{var"#s21"<:(AbstractVector{<:Union{var"#s20", var"#s19"} where {var"#s20"<:Number, var"#s19"<:AbstractJuMPScalar}}), 1}

Alias for an abstract vector of numeric vectors.

Related

source
PortfolioOptimisers.VecVecInt Type
julia
abstract type AbstractArray{var"#s21"<:(AbstractVector{<:Integer}), 1}

Alias for an abstract vector of integer vectors.

Related

source
PortfolioOptimisers.VecInt_VecVecInt Type
julia
const VecInt_VecVecInt = Union{<:VecInt, <:VecVecInt}

Alias for a union of an abstract vector of integers or an abstract vector of integer vectors.

Related

source
PortfolioOptimisers.VecVecVecInt Type
julia
abstract type AbstractArray{var"#s21"<:(AbstractVector{<:AbstractVector{<:Integer}}), 1}

Alias for an abstract vector of abstract vector of integer vectors.

Related

source
PortfolioOptimisers.VecMatNum Type
julia
abstract type AbstractArray{var"#s21"<:(AbstractMatrix{<:Union{var"#s20", var"#s19"} where {var"#s20"<:Number, var"#s19"<:AbstractJuMPScalar}}), 1}

Alias for an abstract vector of numeric matrices.

Related

source
PortfolioOptimisers.VecStr Type
julia
abstract type AbstractArray{var"#s21"<:AbstractString, 1}

Alias for an abstract vector of strings.

Related

source
PortfolioOptimisers.VecPair Type
julia
abstract type AbstractArray{var"#s21"<:Pair, 1}

Alias for an abstract vector of pairs.

Related

source
PortfolioOptimisers.VecJuMPScalar Type
julia
abstract type AbstractArray{var"#s20"<:AbstractJuMPScalar, 1}

Alias for an abstract vector of JuMP scalar types.

Related

source
PortfolioOptimisers.MatNum_VecMatNum Type
julia
const MatNum_VecMatNum = Union{<:MatNum, <:VecMatNum}

Alias for a union of a numeric matrix or a vector of numeric matrices.

Related

source
PortfolioOptimisers.Int_VecInt Type
julia
const Int_VecInt = Union{<:Integer, <:VecInt}

Alias for a union of an integer or a vector of integers.

Related

source
PortfolioOptimisers.VecNum_VecVecNum Type
julia
const VecNum_VecVecNum = Union{<:VecNum, <:VecVecNum}

Alias for a union of a numeric vector or a vector of numeric vectors.

Related

source
PortfolioOptimisers.VecDate Type
julia
abstract type AbstractArray{var"#s21"<:Dates.AbstractTime, 1}

Alias for an abstract vector of date or time types.

Related

source
PortfolioOptimisers.Dict_Vec Type
julia
const Dict_Vec = Union{<:AbstractDict, <:AbstractVector}

Alias for a union of an abstract dictionary or an abstract vector.

Related

source
PortfolioOptimisers.Sym_Str Type
julia
const Sym_Str = Union{Symbol, <:AbstractString}

Alias for a union of a symbol or an abstract string.

Related

source
PortfolioOptimisers.Str_Vec Type
julia
const Str_Vec = Union{<:AbstractString, <:AbstractVector}

Alias for a union of an abstract string or an abstract vector.

Related

source
PortfolioOptimisers.ObsWeights Type
julia
const ObsWeights = Union{<:DynamicAbstractWeights, <:StatsBase.AbstractWeights}

Union type for observation weights accepted by estimators.

Accepts either a DynamicAbstractWeights subtype (weights computed from data at fit time) or a StatsBase.AbstractWeights instance (pre-computed numeric weights).

Related

source
PortfolioOptimisers.Num_VecNum_VecScalar Type
julia
const Num_VecNum_VecScalar = Union{<:Num_VecNum, <:VecScalar}

Alias for a union of a numeric type, a vector of numeric types, or a VecScalar result.

Related

source
PortfolioOptimisers.Num_ArrNum_VecScalar_DynWeights Type
julia
const Num_ArrNum_VecScalar_DynWeights = Union{<:Num_ArrNum, <:VecScalar, <:DynamicAbstractWeights}

Alias for a union of a numeric type, an array of numeric types, or a VecScalar result.

Related

source

Glossaries

In order to standardise the documentation we use a arg_dict of terms.

PortfolioOptimisers.arg_dict Constant
julia
arg_dict = Dict(
             # Weight vectors.
             :pw => "`w`: Portfolio weights vector.",
             :ow => "`w`: Observation weights vector.",
             :oow => "`w`: Optional observation weights vector.",
             # Matrix processing.
             :pdm => "`pdm`: Positive definite matrix estimator.",
             :dn => "`dn`: Matrix denoising estimator.",
             :dt => "`dt`: Matrix detoning estimator.",
             :mp => "`mp`: Matrix processing estimator.",
             # Moments.
             :me => "`me`: Expected returns estimator.",
             :ce => "`ce`: Covariance estimator.",
             :ve => "`ve`: Variance estimator.",
             :ske => "`ske`: Coskewness estimator.",
             :kte => "`kte`: Cokurtosis estimator.",
             :de => "`de`: Distance matrix estimator.",
             # Priors.
             :pe => "`pe`: Prior estimator.",
             :pr => "`pr`: Prior result.",
             :per => "`pe`: Prior estimator or result.",
             # Phylogeny.
             :cle => "`cle`: Clusters estimator.",
             :clr => "`clr`: Clusters result.",
             :cler => "`cle`: Clusters estimator or result.",
             :ple => "`pl`: Phylogeny estimator.",
             :plr => "`pl`: Phylogeny result.",
             :pler => "`pl`: Phylogeny estimator or result.",
             :nte => "`pl`: Network estimator.",
             :ntr => "`pl`: Network result.",
             :nter => "`pl`: Network estimator or result.",
             :cte => "`cte`: Centrality estimator.",
             :cta => "`ct`: Centrality algorithm.",
             :ctr => "`ct`: Centrality result.",
             :cter => "`ct`: Centrality estimator or result.",
             # Turnover.
             :tne => "`tn`: Turnover estimator.",
             :tnr => "`tn`: Turnover result.",
             :tner => "`tn`: Turnover estimator or result.",
             :tnes => "`tn`: Turnover estimator(s).",
             :tnrs => "`tn`: Turnover result(s).",
             :tners => "`tn`: Turnover estimator(s) or result(s).",
             # Tracking.
             :tre => "`tr`: Tracking error estimator.",
             :trr => "`tr`: Tracking error result.",
             :trer => "`tr`: Tracking error estimator or result.",
             :tres => "`tr`: Tracking error estimator(s).",
             :trrs => "`tr`: Tracking error result(s).",
             :trers => "`tr`: Tracking error estimator(s) or result(s).",
             # Weight bounds.
             :wbe => "`wb`: Weight bounds estimator.",
             :wbr => "`wb`: Weight bounds result.",
             :wber => "`wb`: Weight bounds estimator or result.",
             :wb => "`wb`: Weight bounds.",
             # Fees.
             :feese => "`fees`: Fees estimator.",
             :feesr => "`fees`: Fees result.",
             :feeser => "`fees`: Fees estimator or result.",
             :fees => "`fees`: Fees estimator or result.",
             # Optimiser config.
             :opt => "`opt`: `JuMP` optimiser configuration.",
             :kwargs => "`kwargs`: Additional keyword arguments.",
             # Index.
             :idx => "`idx`: Index vector.",
             # Risk measure.
             :r => "`r`: Risk measure or vector of risk measures.",
             # Returns estimator.
             :ret => "`ret`: Returns estimator for `JuMP` models.",
             # Turnover constraint.
             :tn => "`tn`: Turnover constraint estimator.",
             # Tracking constraint.
             :tr => "`tr`: Tracking error constraint estimator.",
             # Near optimal centering result fields.
             :w_opt => "`w_opt`: Optimal portfolio weights.",
             :w_max => "`w_max`: Maximum-risk portfolio weights.",
             :w_min => "`w_min`: Minimum-risk portfolio weights.",
             :w_opt_ini => "`w_opt_ini`: Initial weights for the optimal sub-problem.",
             :w_max_ini => "`w_max_ini`: Initial weights for the maximum-risk sub-problem.",
             :w_min_ini => "`w_min_ini`: Initial weights for the minimum-risk sub-problem.",
             :w_opt_retcode => "`w_opt_retcode`: Return code for the optimal-objective sub-problem.",
             :w_max_retcode => "`w_max_retcode`: Return code for the maximum-risk sub-problem.",
             :w_min_retcode => "`w_min_retcode`: Return code for the minimum-risk sub-problem.",
             :rt_opt => "`rt_opt`: Optimal return target.",
             :rt_max => "`rt_max`: Maximum return target.",
             :rt_min => "`rt_min`: Minimum return target.",
             :rk_opt => "`rk_opt`: Optimal risk target.",
             :noc_retcode => "`noc_retcode`: Return code for the near-optimal centering sub-problem.",
             # Discrete allocation result fields.
             :l_model => "`l_model`: `JuMP` model for the long allocation.",
             :s_model => "`s_model`: `JuMP` model for the short allocation.",
             :l_retcode => "`l_retcode`: Return code for the long allocation sub-problem.",
             :s_retcode => "`s_retcode`: Return code for the short allocation sub-problem.",
             # Risk budgeting.
             :prb => "`prb`: Processed risk budgeting configuration.",
             :sq => "`sq`: Whether to use variance instead of volatility in the inverse weighting.",
             :wfalg => "`alg`: Weight finaliser error formulation algorithm.",
             :res_retcode => "`res`: Optional result or message from the solver.",
             :N_msc => "`N`: Number of bisection steps for the monotonic Schur complement.",
             :alpha_dirichlet => "`alpha`: Dirichlet concentration parameter.",
             :opt_hier => "`opt`: Base hierarchical optimiser configuration.",
             :strict_opt => "`strict`: Whether to strictly enforce weight bounds.",
             :strict_conv => "`strict`: Whether to raise an error if convergence is not achieved.",
             :schalg => "`alg`: Schur complement algorithm variant.")

This dictionary contains the arg_dict terms and their corresponding descriptions used in the documentation of PortfolioOptimisers.jl.

source
PortfolioOptimisers.val_dict Constant
julia
val_dict = Dict(:oow => "If `w` is not `nothing`, `!isempty(w)`.")

Validation rules for certain arg_dict terms used in the documentation of PortfolioOptimisers.jl.

source
PortfolioOptimisers.ret_dict Constant

Dictionary containing return value descriptions for common parameters used in PortfolioOptimisers.jl.

source
PortfolioOptimisers.field_dict Constant
julia
field_dict

Derived dictionary mapping argument keys to field description strings, used for $(FIELDS)-style docstring interpolation.

Each entry is derived from arg_dict by stripping the leading parameter name prefix (everything up to and including the first :).

source
PortfolioOptimisers.math_dict Constant
julia
math_dict

Dictionary of mathematical notation descriptions used for docstring interpolation throughout PortfolioOptimisers.jl.

Keys are symbols that identify mathematical variables or subscripts; values are LaTeX-formatted strings suitable for embedding in docstrings.

source

Iteration and indexing

Estimators, algorithms, and results behave as length-1 iterables and containers to simplify dispatch and slicing in hierarchical workflows.

Base.iterate Method
julia
iterate(
    obj::Union{AbstractAlgorithm, AbstractEstimator, AbstractResult}
) -> Tuple{Any, Int64}
iterate(
    obj::Union{AbstractAlgorithm, AbstractEstimator, AbstractResult},
    state
) -> Union{Nothing, Tuple{Union{AbstractAlgorithm, AbstractEstimator, AbstractResult}, Any}}

Make estimators, algorithms, and results behave as length-1 iterables, returning the object itself on the first iteration and nothing thereafter.

source
Base.getindex Method
julia
getindex(
    obj::Union{AbstractAlgorithm, AbstractEstimator, AbstractResult},
    i::Int64
) -> Union{AbstractAlgorithm, AbstractEstimator, AbstractResult}

Index into estimators, algorithms, and results as length-1 containers. Only index 1 is valid; any other index throws BoundsError.

source