Base
01_Base.jl implements the most basal symbols used in PortfolioOptimisers.jl.
PortfolioOptimisers Module
PortfolioOptimisers.jl
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> 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
devbranch.
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.
StatsPlotsandGraphRecipesis needed to load the plotting extension.ClarabelandHiGHSare the optimisers we will use.CSV,TimeSeriesandDataFramesfor loading and preprocessing price data.PrettyTablesfor displaying the results.
We use the S&P 500 sample dataset shipped in examples/SP500.csv.gz: daily adjusted close prices for 20 large-cap stocks. To keep things quick, we only use the most recent year.
# Import module and plotting extension.
using PortfolioOptimisers, StatsPlots, GraphRecipes
# Import optimisers.
using Clarabel, HiGHS
# Load and preprocess data.
using CSV, TimeSeries, DataFrames
# Pretty printing.
using PrettyTables
# 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
# Load the shipped S&P 500 price data as a TimeArray (run from the repo root).
prices = TimeArray(CSV.File(joinpath("examples", "SP500.csv.gz")); timestamp = :Date)[(end - 252):end]
#=
Any price history with a `Date` column and one column per asset works. To pull live
data instead, download it with YFinance and assemble a TimeArray:
using YFinance, TimeSeries
function stock_price_to_time_array(x)
coln = collect(keys(x))[3:end]
m = hcat([x[k] for k in coln]...)
return TimeArray(x["timestamp"], m, Symbol.(coln), x["ticker"])
end
assets = sort!(["AAPL", "AMD", "BAC", "BBY", "CVX", "GE", "HD", "JNJ", "JPM", "KO",
"LLY", "MRK", "MSFT", "PEP", "PFE", "PG", "RRC", "UNH", "WMT", "XOM"])
prices = get_prices.(assets; startdt = "2024-01-01", enddt = "2025-01-01")
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, FiniteAllocationInput(; w = res.w, prices = vec(values(prices[end])), cash = 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)# 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, erc = false)
# 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).# We can also plot the returns' histogram and probability density.
plot_histogram(mip_res.w, rd.X; slv = slv)# Plot compounded or uncompounded drawdowns.
plot_drawdowns(mip_res.w, rd.X; slv = slv, ts = rd.ts, compound = true)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
abstract type AbstractEstimatorAbstract 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
sourcePortfolioOptimisers.AbstractAlgorithm Type
abstract type AbstractAlgorithmAbstract 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
sourcePortfolioOptimisers.AbstractResult Type
abstract type AbstractResultAbstract 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
sourcePortfolioOptimisers.DynamicAbstractWeights Type
abstract type DynamicAbstractWeights <: AbstractEstimatorAbstract 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 vectorX.get_observation_weights(w::DynamicAbstractWeights, X::MatNum; dims::Int = 1, kwargs...) -> StatsBase.AbstractWeights: Returns observation weights for a 2D matrixX, withdimsspecifying the dimension along which to compute weights.
Arguments
w: Subtype ofDynamicAbstractWeightswith all necessary parameters.X: Data matrix or vector.dims: Dimension along which to compute weights for a 2D matrixX.kwargs...: Additional keyword arguments passed to the weight computation function.
Returns
w::StatsBase.AbstractWeights: Observation weights for the input dataX.
Examples
We can create a dummy dynamic observation weight estimator as follows:
julia> struct MyWeights{T} <: PortfolioOptimisers.DynamicAbstractWeights
half_life::T
function MyWeights(half_life::Integer)
if half_life < one(half_life)
throw(DomainError(half_life, "half_life must be an integer greater than zero"))
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.0Related
sourceConfiguration
Package-level configuration values (pretty-printing collapse, fuzzy-suggestion distance, equation-parser resource caps) are held in thread-safe ScopedConfig holders: a set_*! setter swaps the global default atomically, a with_* helper overrides it for the dynamic extent of a call (task-scoped, automatically restored), and per-project defaults can be seeded at load time via Preferences.jl.
PortfolioOptimisers.ScopedConfig Type
mutable struct ScopedConfig{T}Thread-safe holder for a package-level configuration value, combining a persistent global default with a task-scoped override.
Reads go through cfg[], which returns the innermost active scoped override when inside a with_* block, otherwise the global default. The default is an @atomic field swapped as a whole — a set_*! call is a single atomic store, so concurrent readers (e.g. the FLoops.@floop loops inside meta-optimisers) can never observe a torn or partially-updated configuration. The scoped override is a Base.ScopedValues.ScopedValue: it is inherited by tasks spawned inside the scope, restored automatically when the scope exits, and invisible to unrelated concurrent tasks.
Configs held this way store immutable structs (or bits values); changing any knob builds a new value and swaps it in, never mutates in place.
Used by COMPACT_SHOW, STRING_DISTANCE, and EQUATION_LIMITS; their global defaults are set via the set_*! setters, scoped overrides via the with_* helpers, and load-time per-project defaults via Preferences.jl (see apply_preferences!).
Related
Base.getindex Method
getindex(cfg::ScopedConfig)Read the active value of a ScopedConfig: the innermost task-scoped override when inside a with_* block, otherwise the global default (read atomically).
PortfolioOptimisers.set_default! Function
set_default!(cfg::ScopedConfig{T}, x) -> AnyAtomically replace the global default of a ScopedConfig with x and return it. Does not affect any active scoped override.
Related
sourcePortfolioOptimisers.with_config Function
with_config(f, cfg::ScopedConfig{T}, x) -> AnyRun f() with the ScopedConfig cfg overridden to x for the dynamic extent of the call, restoring the previous value on exit. Thread-safe: the override is task-scoped (inherited by tasks spawned inside f, invisible to concurrent tasks outside it).
Related
sourcePortfolioOptimisers.apply_preferences! Function
apply_preferences!(prefs::AbstractDict{<:AbstractString})Apply load-time preference values to the global config defaults (EQUATION_LIMITS, STRING_DISTANCE, COMPACT_SHOW). Called by the package __init__ with the PREFERENCE_KEYS values read via Preferences.load_preference; nothing values (unset preferences) are skipped and keep the shipped default.
Fails closed: an invalid value throws a typed ArgumentError naming the key and value, so the package refuses to load rather than silently running with a weaker cap than the one the project requested. Values are applied through the set_*! setters, so they receive the same validation as runtime calls.
To persist a configuration, put the keys in the active project's LocalPreferences.toml, e.g.:
[PortfolioOptimisers]
equation_max_length = 512
equation_max_depth = 64
suggestion_min_score = 0.8
suggestion_distance = "damerau_levenshtein"
compact_show = 4Related
sourcePortfolioOptimisers.__init__ Function
__init__()Package load hook: reads the PREFERENCE_KEYS preferences of the active project via Preferences.load_preference and applies them to the global config defaults through apply_preferences!. An invalid preference value fails closed — the package refuses to load — rather than silently running with a weaker cap than the one the project requested.
PortfolioOptimisers.PREFERENCE_KEYS Constant
PREFERENCE_KEYSThe Preferences.jl keys read at package load to seed the global config defaults (see apply_preferences!):
"equation_max_length"/"equation_max_depth": positive integers forEQUATION_LIMITS."suggestion_min_score": real number for theSTRING_DISTANCEthreshold."suggestion_distance": aPREFERENCE_DISTANCESname for theSTRING_DISTANCEmetric."compact_show": boolean or integer forCOMPACT_SHOW.
Preferences.jl offers no way to enumerate the keys a project has set, so a misspelled key cannot be detected and is silently ignored (the shipped default applies) — misspelled or invalid values under these keys fail closed at load.
Related
sourcePortfolioOptimisers.PREFERENCE_DISTANCES Constant
PREFERENCE_DISTANCESEnumerated allowlist mapping the names accepted by the "suggestion_distance" preference to their StringDistances.StringDistance objects. Membership and dispatch are one Dict — the same single-source-of-truth discipline as the equation parser's function allowlist (docs/adr/0025-enumerated-parser-allowlist.md): an unknown name fails closed at load with a typed error carrying a did_you_mean suggestion.
Supported names: "levenshtein", "damerau_levenshtein", "jaro", "jaro_winkler", "ratcliff_obershelp".
Related
sourcePretty 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
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 bycompact_show_budget.Collapses an oversized nested struct field to
Name ⋯when its rendered height exceedscompact_show_budget; seeset_compact_show!.Skips fields that are not present or are
nothing.
Related
sourcePortfolioOptimisers.has_pretty_show_method Function
has_pretty_show_method(_) -> BoolDefault 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:falseby default, indicating no custom pretty-printing method.
Related
sourcePortfolioOptimisers.set_compact_show! Function
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 budgetn.
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).
Sets the global default (atomically; see ScopedConfig). For a temporary, task-scoped override use with_compact_show.
Related
sourcePortfolioOptimisers.with_compact_show Function
with_compact_show(f, x::Bool)
with_compact_show(f, n::Integer)Run f() with the COMPACT_SHOW collapsing setting overridden to x/n for the dynamic extent of the call, restoring the previous setting on exit. Task-scoped and thread-safe (see ScopedConfig); the global default is untouched.
Related
sourcePortfolioOptimisers.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 ofn.
Held in a ScopedConfig: set the global default via set_compact_show!, override per scope via with_compact_show, and read (together with the per-call :po_compact IO property) by compact_show_budget. The default may be seeded per project at load time via the "compact_show" preference (see apply_preferences!).
PortfolioOptimisers.compact_show_budget Function
compact_show_budget(io::IO) -> AnyResolve 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
nothingwhen collapsing is disabled.budget::Int(the maximum number of rendered lines a nested struct may occupy before collapsing) otherwise.
Related
sourcePortfolioOptimisers.pretty_show_vector_summary Function
pretty_show_vector_summary(val::AbstractVector) -> StringBuild 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
sourcePortfolioOptimisers.pretty_show_vector_element Function
pretty_show_vector_element(v) -> StringRender 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
sourcePortfolioOptimisers.pretty_show_vector_body Function
pretty_show_vector_body(
io::IO,
lines::AbstractVector{<:AbstractString}
) -> AnyApply 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
io: Output stream; drives the budget viacompact_show_budget.lines: Per-element display strings frompretty_show_vector_element.
Returns
body::Vector{String}: Lines to print, possibly truncated with a"⋮"separator.
Related
sourceUtilities
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
struct VecScalar{__T_v, __T_s} <: AbstractResultRepresents 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
VecScalar(;
v::VecNum,
s::Number
) -> VecScalarKeywords correspond to the struct's fields.
Validation
v:!isempty(v)andall(isfinite, v).s:isfinite(s).
Examples
julia> VecScalar([1.0, 2.0, 3.0], 4.2)
VecScalar
v ┼ Vector{Float64}: [1.0, 2.0, 3.0]
s ┴ Float64: 4.2Related
sourcePortfolioOptimisers.AbstractEstimatorValueAlgorithm Type
abstract type AbstractEstimatorValueAlgorithm <: AbstractAlgorithmAbstract 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 ifvalisnothing.nx = sets.dict[ifelse(isnothing(key), sets.key, key)]: Gets the universe to use for mapping values to features.
Arguments
alg: Concrete subtype ofAbstractEstimatorValueAlgorithm.sets: Sets used to map estimator values to features.val: Default value to use for the estimator. Ifnothing, the estimator provides the default value.key: Key to specify the asset universe insets.dict. Ifnothing, the key is taken fromsets.key.datatype: Data type to use for the result in casevalisnothing.strict: Whether to throw an error ifsetsdoes not contain the desired value insets.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> 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.0Related
sourcePortfolioOptimisers.get_observation_weights Function
get_observation_weights(
w::Option{<:ObsWeights},
args...;
kwargs...
) -> Option{<:VecNum}Get the observation weights for statistical estimation.
Arguments
w: Optional observation weights vectorobservations × 1, or a concrete subtype ofDynamicAbstractWeights. Ifnothing, the computation is unweighted.args: Additional positional arguments (ignored).kwargs: Additional keyword arguments (ignored).
Returns
w::Option{<:VecNum}: The observation weights, ornothingfor whenwisDynamicAbstractWeightsornothing.
Related
sourcePortfolioOptimisers.NormError Type
abstract type NormError <: AbstractEstimatorAbstract supertype for all norm-based error algorithms in PortfolioOptimisers.jl.
All concrete and/or abstract types representing norm-based error algorithms (such as second-order cone or norm-one error) should be subtypes of NormError.
Related
sourcePortfolioOptimisers.L2Norm Type
struct L2Norm{__T_ddof} <: NormErrorSecond-order cone (SOC) norm-based error formulation.
L2Norm implements a norm-based error formulation using the Euclidean (L2) norm, scaled by the square root of the number of assets minus the degrees of freedom (ddof). This is commonly used for error constraints and objectives in portfolio optimisation.
Mathematical definition
Where:
: L2-norm error. : Portfolio weight or return vector . : Benchmark vector . : Number of observations. : Degrees of freedom, ddof. Whenis not provided the denominator is 1.
Fields
ddof: Degrees-of-freedom correction.
Constructors
L2Norm(;
ddof::Integer = 1
) -> L2NormValidation
0 <= ddof.
Examples
julia> L2Norm()
L2Norm
ddof ┴ Int64: 1Related
sourcePortfolioOptimisers.SquaredL2Norm Type
struct SquaredL2Norm{__T_ddof} <: NormErrorSecond-order cone (SOC) squared norm-based error formulation.
SquaredL2Norm implements a norm-based error formulation using the squared Euclidean (L2) norm, scaled by the number of assets minus the degrees of freedom (ddof). This is commonly used for norm error constraints and objectives in portfolio optimisation where squared error is preferred.
Mathematical definition
Where:
: Squared L2-norm error. : Portfolio weight or return vector . : Benchmark vector . : Number of observations. : Degrees of freedom, ddof. Whenis not provided the denominator is 1.
Fields
ddof: Degrees-of-freedom correction.
Constructors
SquaredL2Norm(;
ddof::Integer = 1,
) -> SquaredL2NormValidation
0 <= ddof.
Examples
julia> SquaredL2Norm()
SquaredL2Norm
ddof ┴ Int64: 1Related
sourcePortfolioOptimisers.L1Norm Type
struct L1Norm <: NormErrorNorm-one (NOC) error formulation.
L1Norm implements a norm-based error formulation using the L1 (norm-one) distance between portfolio and benchmark weights. This is commonly used for error constraints and objectives in portfolio optimisation where sparsity or absolute deviations are preferred.
Mathematical definition
Where:
: L1-norm error. : Portfolio weight or return vector . : Benchmark vector . : Number of observations. When is not provided the denominator is 1.
Constructors
L1Norm() -> L1NormExamples
julia> L1Norm()
L1Norm()Related
sourcePortfolioOptimisers.LpNorm Type
struct LpNorm{__T_p, __T_ddof} <: NormErrorL-p norm error estimator.
Computes the Lp-norm of the difference between portfolio and benchmark returns:
Mathematical definition
Where:
: Lp-norm error. : Portfolio weight or return vector . : Benchmark vector . : Number of observations. : Degrees of freedom, ddof. Whenis not provided the denominator is 1. : Norm order.
Fields
p: Power or order parameter.ddof: Degrees-of-freedom correction.
Constructors
LpNorm(; p::Number = 3, ddof::Integer = 0) -> LpNormKeywords correspond to the struct's fields.
Validation
0 <= ddof.
Examples
julia> LpNorm()
LpNorm
p ┼ Int64: 3
ddof ┴ Int64: 0Related
sourcePortfolioOptimisers.LInfNorm Type
struct LInfNorm{__T_ddof, __T_pos} <: NormErrorL-infinity norm (maximum absolute deviation) error estimator.
Computes the L∞-norm (maximum absolute deviation) of the difference between portfolio and benchmark returns.
Mathematical definition
Where:
: L∞-norm error. pos = trueuses, pos = falseuses. : Portfolio weight or return vector . : Benchmark vector . : Number of observations. : Degrees of freedom, ddof. Whenis not provided the denominator is 1.
Fields
ddof: Degrees-of-freedom correction.pos: Whether to consider only positive deviations.
Constructors
LInfNorm(; ddof::Integer = 0, pos::Bool = true) -> LInfNormKeywords correspond to the struct's fields.
Validation
0 <= ddof.
Examples
julia> LInfNorm()
LInfNorm
ddof ┼ Int64: 0
pos ┴ Bool: trueRelated
sourcePortfolioOptimisers.norm_error Function
norm_error(f::L2Norm, a, b, T::Option{<:Number} = nothing)
norm_error(f::SquaredL2Norm, a, b, T::Option{<:Number} = nothing)
norm_error(::L1Norm, a, b, T::Option{<:Number} = nothing)
norm_error(f::LpNorm, a, b, T::Option{<:Number} = nothing)
norm_error(f::LInfNorm, a, b, T::Option{<:Number} = nothing)Compute the norm-based tracking error between portfolio and benchmark weights.
norm_error computes the tracking error using either the Euclidean (L2) norm for L2Norm, squared Euclidean (L2) norm for SquaredL2Norm, or the L1 (norm-one) distance for L1Norm. The error is optionally scaled by the number of assets and degrees of freedom for SOC, or by the number of assets for NOC.
Mathematical definition
Where:
: Portfolio weight or return vector . : Benchmark vector . : Number of observations. : Degrees of freedom, ddof.: Norm order.
Arguments
f: Tracking formulation algorithm.a: Portfolio weights.b: Benchmark weights.T: Optional number of observations.
Returns
err::Number: Norm-based tracking error.
Details
For
L2Norm, computesLinearAlgebra.norm(a - b, 2) / sqrt(T - f.ddof)ifTis notnothing, else unscaled.For
SquaredL2Norm, computesLinearAlgebra.norm(a - b, 2)^2 / (T - f.ddof)ifTis notnothing, else unscaled.For
L1Norm, computesLinearAlgebra.norm(a - b, 1) / TifTis notnothing, else unscaled.
Examples
julia> PortfolioOptimisers.norm_error(L2Norm(), [0.5, 0.5], [0.6, 0.4], 2)
0.14142135623730948
julia> PortfolioOptimisers.norm_error(L1Norm(), [0.5, 0.5], [0.6, 0.4], 2)
0.09999999999999998Related
sourceLogging
Functionality for logging messages.
PortfolioOptimisers.StringDistanceConfig Type
struct StringDistanceConfigGlobal configuration for the fuzzy "did you mean?" suggestions appended to "variable not in asset universe" messages by did_you_mean.
Fields
dist: theStringDistances.StringDistanceused to score candidate names against the offending one (defaultStringDistances.Levenshtein()).min_score: the minimum normalised similarity in[0, 1]a candidate must reach before it is suggested (default0.7). Raising it toward1keeps only near-exact matches; setting it above1disables suggestions entirely — useful in meta-optimiser inner loops, where an asset name legitimately absent from a cluster/subset is not a typo and should draw no suggestion.
Immutable; held in the STRING_DISTANCE ScopedConfig. Set the global default via set_string_distance!, override per scope via with_string_distance. Read by did_you_mean.
Related
sourcePortfolioOptimisers.STRING_DISTANCE Constant
STRING_DISTANCE = ScopedConfig(StringDistanceConfig(StringDistances.Levenshtein(), 0.7))Default string distance configuration for fuzzy "did you mean?" suggestions appended to "variable not in asset universe" messages by did_you_mean. Read as STRING_DISTANCE[]; the defaults may be seeded per project at load time via the "suggestion_distance" / "suggestion_min_score" preferences (see apply_preferences!).
Related
sourcePortfolioOptimisers.set_string_distance! Function
set_string_distance!(; dist::StringDistances.StringDistance, min_score::Real)Configure the global default fuzzy-suggestion settings read by did_you_mean. The store is atomic (see ScopedConfig); unspecified keywords keep their current default. For a temporary, task-scoped override use with_string_distance.
dist: distance used to rank candidate names (e.g.StringDistances.Levenshtein(),StringDistances.DamerauLevenshtein(),StringDistances.JaroWinkler()).min_score: minimum normalised similarity in[0, 1]to emit a suggestion; set above1to disable suggestions.
Returns the new default StringDistanceConfig.
Related
sourcePortfolioOptimisers.with_string_distance Function
with_string_distance(f; dist::StringDistances.StringDistance = STRING_DISTANCE[].dist,
min_score::Real = STRING_DISTANCE[].min_score)Run f() with the fuzzy-suggestion settings read by did_you_mean overridden for the dynamic extent of the call, restoring the previous settings on exit. Task-scoped and thread-safe (see ScopedConfig); the global default is untouched. Unspecified keywords inherit from the currently active value, so nested overrides compose.
Useful around a meta-optimiser run to silence suggestions (min_score above 1) in its inner loops without affecting other concurrent work.
Related
sourcePortfolioOptimisers.did_you_mean Function
did_you_mean(name::AbstractString, candidates) -> StringReturn a " (did you meanX?)"suffix naming the closest match tonameamongcandidates, or "" when no candidate reaches the global STRING_DISTANCE min_scorethreshold (orcandidates is empty).
Used to enrich "variable not in asset universe" messages (see unknown_variable_msg) with a typo suggestion. The distance and threshold are read from the active STRING_DISTANCE config — global default via set_string_distance!, task-scoped override via with_string_distance; the threshold gating means a name legitimately absent from a meta-optimiser cluster/subset (no close neighbour) draws no suggestion.
Related
sourcePortfolioOptimisers.unknown_variable_msg Function
unknown_variable_msg(v, nx, key; candidates = nx) -> StringBuild the warning/error text for a constraint or view variable v that is absent from the asset universe nx (stored under key). Names the variable and the universe size only — never the full universe — and appends a did_you_mean suggestion when a close match exists.
candidates is the pool searched for the typo suggestion (default: the asset universe nx). Callers whose valid namespace is broader than the raw asset universe — e.g. group_to_val!, where a key may name a group rather than an asset — pass a wider pool (asset names plus group/set keys) so the suggestion can name a mistyped group. The reported universe size is always length(nx) regardless of candidates.
Shared by get_linear_constraints, Black-Litterman view generation, entropy-pooling view generation, and group_to_val! so the message (and its info-leak-safe shape) lives in exactly one place.
Related
sourcePortfolioOptimisers.missing_group_assets_msg Function
missing_group_assets_msg(group, missing_assets, nx, key) -> StringBuild the warning/error text for a group that resolves in the asset sets but whose members missing_assets are absent from the asset universe nx (stored under key). Names the group, the offending member names (which are caller input, not internal state), and the universe size only — never the full universe or the input value dictionary — and appends a did_you_mean suggestion for the first missing member.
Shared by group_to_val! so the info-leak-safe message shape lives in exactly one place, alongside unknown_variable_msg and empty_row_msg.
Related
sourcePortfolioOptimisers.empty_row_msg Function
empty_row_msg(eqn, nx, key; noun::AbstractString = "constraint") -> StringBuild the warning/error text for a parsed equation eqn whose every term missed the asset universe nx (stored under key), leaving an all-zero row that is dropped. Names the equation and the universe size only — never the full universe or the parsed struct. noun is "constraint" for linear constraints or "view" for Black-Litterman views.
Shared by get_linear_constraints and Black-Litterman view generation.
Related
sourcePortfolioOptimisers.failed_solve_msg Function
failed_solve_msg(trials::AbstractDict; max_line_length::Integer = 200) -> StringBuild the warning text for a JuMP model that no configured solver could solve satisfactorily (see JuMPResult). One line per failed stage of each solver trial: the solver name, the stage that failed (set_optimizer, optimize!, or assert_is_solved_and_feasible), and the first line of the error truncated to max_line_length characters — so a JuMP termination status stays visible.
Never interpolates the whole trials dictionary, the solver settings, or full exception payloads into the log; the raw data remains available on the returned JuMPResult.trials. This is the same info-leak-safe message discipline as unknown_variable_msg and its siblings. Solver names and stages are sorted so the message is deterministic.
Related
sourcePortfolioOptimisers.first_error_line Function
first_error_line(err, max_line_length::Integer) -> StringRender the first line of an error for a log message, truncated to max_line_length characters (a trailing … marks the cut). Exceptions render via showerror, so the line carries the exception type and message; anything else renders via repr.
Related
sourcePortfolioOptimisers.EquationLimits Type
Global resource caps for equation parsing, guarding the string→AST trust boundary against a stack-exhaustion denial of service.
Constraint, Black-Litterman view and entropy-pooling view strings are untrusted input (config files, spreadsheets, UI). They funnel through parse_equation, which calls Meta.parse and then walks the resulting expression tree recursively (eval_numeric_functions, collect_terms!, has_invalid_plus). Without a bound, a deeply nested string (e.g. tens of thousands of parentheses) produces an AST deep enough to exhaust the stack and take down the host process. These caps fail closed with a typed Meta.ParseError well before that point.
Fields
max_length: maximum number of characters in an equation string handed toMeta.parse(default4096). A legitimate linear constraint is short; the bound sits far above any real constraint and far below the nesting depth that threatens the stack. Because achieving nesting depthdfrom a string needs at leastdcharacters, the length cap also bounds the AST depth of the string form.max_depth: maximum expression-tree depth accepted by theExprform ofparse_equation(default256), which receives a pre-built AST that no length cap covers.
The values are conservative static defaults (portable across build and deployment machines, unlike a value auto-detected during precompilation). Immutable; held in the EQUATION_LIMITS ScopedConfig. Set the global default via set_equation_limits!, override per scope via with_equation_limits. Both fields must be positive (enforced by the constructor). See docs/adr/0027-cap-equation-parser-recursion.md.
PortfolioOptimisers.EQUATION_LIMITS Constant
EQUATION_LIMITS = ScopedConfig(EquationLimits(4096, 256))Default global resource caps for equation parsing, guarding the string→AST trust boundary against a stack-exhaustion denial of service. Read as EQUATION_LIMITS[]; the defaults may be seeded per project at load time via the "equation_max_length" / "equation_max_depth" preferences (see apply_preferences!).
Related
sourcePortfolioOptimisers.set_equation_limits! Function
set_equation_limits!(; max_length::Integer, max_depth::Integer)Configure the global default equation-parser resource caps read at the string→AST trust boundary (see EQUATION_LIMITS).
max_length: maximum equation-string length passed toMeta.parse.max_depth: maximum expression-tree depth accepted by theExprform ofparse_equation.
Raise them for a genuinely large machine-generated constraint set, or lower them to tighten the boundary. Both must be positive; unspecified keywords keep their current default. The store is atomic (see ScopedConfig); for a temporary, task-scoped override use with_equation_limits.
Returns the new default EquationLimits.
Related
sourcePortfolioOptimisers.with_equation_limits Function
with_equation_limits(f; max_length::Integer = EQUATION_LIMITS[].max_length,
max_depth::Integer = EQUATION_LIMITS[].max_depth)Run f() with the equation-parser resource caps (see EQUATION_LIMITS) overridden for the dynamic extent of the call, restoring the previous caps on exit. Task-scoped and thread-safe (see ScopedConfig); the global default is untouched. Unspecified keywords inherit from the currently active value, so nested overrides compose.
Useful to tighten the boundary around one batch of untrusted constraint strings, or to raise it for a single machine-generated constraint set, without affecting other concurrent work.
Related
sourceError 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
abstract type PortfolioOptimisersError <: ExceptionAbstract supertype for all custom exception types in PortfolioOptimisers.jl.
All error types specific to PortfolioOptimisers.jl should be subtypes of PortfolioOptimisersError.
Related
sourceBase.showerror Method
showerror(io::IO, err::PortfolioOptimisersError) -> AnyPrint human-readable representation of PortfolioOptimisersError subtypes to io, stripping parametric type suffixes.
PortfolioOptimisers.IsNothingError Type
struct IsNothingError{__T_msg} <: PortfolioOptimisersErrorException type thrown when an argument or value is unexpectedly nothing.
Fields
msg: Error message describing the condition that triggered the exception.
Constructors
IsNothingError(msg)Arguments correspond to the fields above.
Examples
julia> throw(IsNothingError("Input data must not be nothing"))
ERROR: IsNothingError: Input data must not be nothing
Stacktrace:
[1] top-level scope
@ none:1Related
sourcePortfolioOptimisers.IsEmptyError Type
struct IsEmptyError{__T_msg} <: PortfolioOptimisersErrorException type thrown when an argument or value is unexpectedly empty.
Fields
msg: Error message describing the condition that triggered the exception.
Constructors
IsEmptyError(msg)Arguments correspond to the fields above.
Examples
julia> throw(IsEmptyError("Input array must not be empty"))
ERROR: IsEmptyError: Input array must not be empty
Stacktrace:
[1] top-level scope
@ none:1Related
sourcePortfolioOptimisers.IsNonFiniteError Type
struct IsNonFiniteError{__T_msg} <: PortfolioOptimisersErrorException 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
IsNonFiniteError(msg)Arguments correspond to the fields above.
Examples
julia> throw(IsNonFiniteError("Input array contains non-finite values"))
ERROR: IsNonFiniteError: Input array contains non-finite values
Stacktrace:
[1] top-level scope
@ none:1Related
sourcePortfolioOptimisers.PropertyPathError Type
struct PropertyPathError{__T_msg} <: PortfolioOptimisersErrorException type thrown when a @forward_properties nested path cannot be descended because an intermediate node is nothing.
Fields
msg: Error message describing the condition that triggered the exception.
Constructors
PropertyPathError(msg)Arguments correspond to the fields above.
Examples
julia> throw(PropertyPathError("cannot descend path `sol.w` on `JuMPOptimisationResult`: intermediate `sol` is `nothing`"))
ERROR: PropertyPathError: cannot descend path `sol.w` on `JuMPOptimisationResult`: intermediate `sol` is `nothing`
Stacktrace:
[1] top-level scope
@ none:1Related
sourceAssertions
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 Function
assert_nonempty(
val::Union{AbstractDict, AbstractArray{<:Union{var"#s29", var"#s28"} where {var"#s29"<:Number, var"#s28"<:AbstractJuMPScalar}}, AbstractVector{<:Pair}}
)
assert_nonempty(
val::Union{AbstractDict, AbstractArray{<:Union{var"#s29", var"#s28"} where {var"#s29"<:Number, var"#s28"<:AbstractJuMPScalar}}, AbstractVector{<:Pair}},
sym::Union{AbstractString, Symbol}
)Assert that val is non-empty.
No-op for Pair and Number inputs; emptiness does not apply to scalars.
Arguments
val: Container to check; one ofAbstractDict,VecPair, orArrNum.sym: Symbolic name used in the error message.
Returns
nothing.
Related
assert_nonempty(::Union{Number, Pair})
assert_nonempty(
::Union{Number, Pair},
::Union{AbstractString, Symbol}
)No-op overload of assert_nonempty for scalar inputs.
Emptiness does not apply to Pair or Number values.
Returns
nothing.
Related
sourcePortfolioOptimisers.assert_finite Function
assert_finite(val::AbstractDict)
assert_finite(
val::AbstractDict,
sym::Union{AbstractString, Symbol}
)Assert that val contains at least one finite element.
Dispatches on the input type:
AbstractDict:any(isfinite, values(val)).VecPair:any(isfinite, getindex.(val, 2)).ArrNum:any(isfinite, val).Pair:isfinite(val[2]).Number:isfinite(val).
Arguments
val: Value to check.sym: Symbolic name used in the error message.
Returns
nothing.
Related
PortfolioOptimisers.assert_nonneg Function
assert_nonneg(val::AbstractDict)
assert_nonneg(
val::AbstractDict,
sym::Union{AbstractString, Symbol}
)Assert that all elements of val are non-negative (>= 0).
Dispatches on the input type:
AbstractDict:all(x -> 0 <= x, values(val)).VecPair:all(x -> 0 <= x[2], val).ArrNum:all(x -> 0 <= x, val).Pair:0 <= val[2].Number:0 <= val.
Arguments
val: Value to check.sym: Symbolic name used in the error message.
Returns
nothing.
Related
sourcePortfolioOptimisers.assert_gt0 Function
assert_gt0(val::AbstractDict)
assert_gt0(
val::AbstractDict,
sym::Union{AbstractString, Symbol}
)Assert that all elements of val are strictly positive (> 0).
Dispatches on the input type:
AbstractDict:all(x -> 0 < x, values(val)).VecPair:all(x -> 0 < x[2], val).ArrNum:all(x -> 0 < x, val).Pair:0 < val[2].Number:0 < val.
Arguments
val: Value to check.sym: Symbolic name used in the error message.
Returns
nothing.
Related
sourcePortfolioOptimisers.assert_nonempty_nonneg_finite_val Function
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])andval[2] >= 0.::Number:isfinite(val)andval >= 0.args...: Always passes.
Related
sourcePortfolioOptimisers.assert_nonempty_gt0_finite_val Function
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])andval[2] > 0.::Number:isfinite(val)andval > 0.args...: Always passes.
Related
sourcePortfolioOptimisers.assert_nonempty_finite_val Function
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
sourcePortfolioOptimisers.assert_matrix_issquare Function
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
DimensionMismatchif the check fails.
Related
sourcePortfolioOptimisers.assert_unit_interval Function
assert_unit_interval(val::Number)
assert_unit_interval(
val::Number,
sym::Union{AbstractString, Symbol}
)Assert that val lies strictly inside the open unit interval (0 < val < 1).
Arguments
val: Value to check.sym: Symbolic name used in the error message.
Returns
nothing.
Related
sourceBase 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
const Option{T} = Union{Nothing, T}Alias for an optional value of type T, which may be nothing.
Related
sourcePortfolioOptimisers.VecNum Type
abstract type AbstractArray{var"#s30"<:(Union{var"#s29", var"#s28"} where {var"#s29"<:Number, var"#s28"<:AbstractJuMPScalar}), 1}Alias for an abstract vector of numeric types or JuMP scalar types.
Related
sourcePortfolioOptimisers.VecInt Type
abstract type AbstractArray{var"#s30"<:Integer, 1}Alias for an abstract vector of integer types.
Related
sourcePortfolioOptimisers.MatNum Type
abstract type AbstractArray{var"#s30"<:(Union{var"#s29", var"#s28"} where {var"#s29"<:Number, var"#s28"<:AbstractJuMPScalar}), 2}Alias for an abstract matrix of numeric types or JuMP scalar types.
Related
sourcePortfolioOptimisers.ArrNum Type
abstract type AbstractArray{var"#s30"<:(Union{var"#s29", var"#s28"} where {var"#s29"<:Number, var"#s28"<:AbstractJuMPScalar}), N}Alias for an abstract array of numeric types or JuMP scalar types.
Related
sourcePortfolioOptimisers.VecNum_MatNum Type
const VecNum_MatNum = Union{<:VecNum, <:MatNum}Alias for a union of a numeric type or an abstract matrix of numeric types.
Related
sourcePortfolioOptimisers.Num_VecNum Type
const Num_VecNum = Union{<:Number, <:VecNum}Alias for a union of a numeric type or an abstract vector of numeric types.
Related
sourcePortfolioOptimisers.Func_Num_VecNum Type
const Func_Num_VecNum = Union{<:Number, <:Func_VecNum}Alias for a union of a function type or a numeric type or an abstract vector of numeric types.
Related
sourcePortfolioOptimisers.Num_ArrNum Type
const Num_ArrNum = Union{<:Number, <:ArrNum}Alias for a union of a numeric type or an abstract array of numeric types.
Related
sourcePortfolioOptimisers.PairStrNum Type
struct Pair{var"#s30"<:AbstractString, var"#s29"<:Number}Alias for a pair consisting of an abstract string and a numeric type.
Related
sourcePortfolioOptimisers.DictStrNum Type
abstract type AbstractDict{var"#s30"<:AbstractString, var"#s29"<:Number}Alias for an abstract dictionary with string keys and numeric values.
Related
sourcePortfolioOptimisers.MultiEstValType Type
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
sourcePortfolioOptimisers.EstValType Type
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
sourcePortfolioOptimisers.PairGSCV Type
struct Pair{var"#s30"<:(Union{Expr, Symbol, var"#s30", var"#s29", var"#s28", var"#s27", var"#s26"} where {var"#s30"<:AbstractString, var"#s29"<:ComposedFunction, var"#s28"<:Accessors.PropertyLens, var"#s27"<:Accessors.IndexLens, var"#s26"<:Integer}), var"#s29"<:(AbstractVector)}Alias for a pair consisting of an abstract string and an abstract vector.
Related
sourcePortfolioOptimisers.DictGSCV Type
abstract type AbstractDict{var"#s30"<:(Union{Expr, Symbol, var"#s30", var"#s29", var"#s28", var"#s27", var"#s26"} where {var"#s30"<:AbstractString, var"#s29"<:ComposedFunction, var"#s28"<:Accessors.PropertyLens, var"#s27"<:Accessors.IndexLens, var"#s26"<:Integer}), var"#s29"<:(AbstractVector)}Alias for an abstract dictionary with string keys and abstract vector values.
Related
sourcePortfolioOptimisers.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, an accessor lens, or an integer (a step position when tuning a Pipeline).
Related
sourcePortfolioOptimisers.RSCVVal Type
Alias for a value type used in randomised search cross-validation, which can be an abstract vector or a distribution.
Related
sourcePortfolioOptimisers.MultiGSCVValType Type
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
sourcePortfolioOptimisers.VecMultiGSCVValType Type
abstract type AbstractArray{var"#s30"<:(Union{var"#s30", var"#s29"} where {var"#s30"<:(AbstractDict{<:Union{Expr, Symbol, var"#s30", var"#s29", var"#s28", var"#s27", var"#s26"} where {var"#s30"<:AbstractString, var"#s29"<:ComposedFunction, var"#s28"<:Accessors.PropertyLens, var"#s27"<:Accessors.IndexLens, var"#s26"<:Integer}, <:AbstractVector}), var"#s29"<:(AbstractVector{<:Pair{<:Union{Expr, Symbol, var"#s30", var"#s29", var"#s28", var"#s27", var"#s26"} where {var"#s30"<:AbstractString, var"#s29"<:ComposedFunction, var"#s28"<:Accessors.PropertyLens, var"#s27"<:Accessors.IndexLens, var"#s26"<:Integer}, <:AbstractVector}})}), 1}Alias for an abstract vector of MultiGSCVValType elements.
Related
sourcePortfolioOptimisers.MultiGSCVValType_VecMultiGSCVValType Type
const MultiGSCVValType_VecMultiGSCVValType = Union{<:MultiGSCVValType,
<:VecMultiGSCVValType}Alias for a union of MultiGSCVValType and VecMultiGSCVValType elements.
Related
sourcePortfolioOptimisers.Str_Expr Type
const Str_Expr = Union{<:AbstractString, Expr}Alias for a union of abstract string or Julia expression.
Related
sourcePortfolioOptimisers.VecStr_Expr Type
abstract type AbstractArray{var"#s30"<:(Union{Expr, var"#s30"} where var"#s30"<:AbstractString), 1}Alias for an abstract vector of strings or Julia expressions.
Related
sourcePortfolioOptimisers.EqnType Type
const EqnType = Union{<:AbstractString, Expr, <:VecStr_Expr,
<:AbstractEstimatorValueAlgorithm}Alias for a union of string, Julia expression, or vector of strings/expressions.
Related
sourcePortfolioOptimisers.VecVecNum Type
abstract type AbstractArray{var"#s30"<:(AbstractVector{<:Union{var"#s29", var"#s28"} where {var"#s29"<:Number, var"#s28"<:AbstractJuMPScalar}}), 1}Alias for an abstract vector of numeric vectors.
Related
sourcePortfolioOptimisers.VecVecInt Type
abstract type AbstractArray{var"#s30"<:(AbstractVector{<:Integer}), 1}Alias for an abstract vector of integer vectors.
Related
sourcePortfolioOptimisers.VecInt_VecVecInt Type
const VecInt_VecVecInt = Union{<:VecInt, <:VecVecInt}Alias for a union of an abstract vector of integers or an abstract vector of integer vectors.
Related
sourcePortfolioOptimisers.VecVecVecInt Type
abstract type AbstractArray{var"#s30"<:(AbstractVector{<:AbstractVector{<:Integer}}), 1}Alias for an abstract vector of abstract vector of integer vectors.
Related
sourcePortfolioOptimisers.VecMatNum Type
abstract type AbstractArray{var"#s30"<:(AbstractMatrix{<:Union{var"#s29", var"#s28"} where {var"#s29"<:Number, var"#s28"<:AbstractJuMPScalar}}), 1}Alias for an abstract vector of numeric matrices.
Related
sourcePortfolioOptimisers.VecStr Type
abstract type AbstractArray{var"#s30"<:AbstractString, 1}Alias for an abstract vector of strings.
Related
sourcePortfolioOptimisers.VecPair Type
abstract type AbstractArray{var"#s30"<:Pair, 1}Alias for an abstract vector of pairs.
Related
sourcePortfolioOptimisers.VecJuMPScalar Type
abstract type AbstractArray{var"#s29"<:AbstractJuMPScalar, 1}Alias for an abstract vector of JuMP scalar types.
Related
sourcePortfolioOptimisers.MatNum_VecMatNum Type
const MatNum_VecMatNum = Union{<:MatNum, <:VecMatNum}Alias for a union of a numeric matrix or a vector of numeric matrices.
Related
sourcePortfolioOptimisers.Int_VecInt Type
const Int_VecInt = Union{<:Integer, <:VecInt}Alias for a union of an integer or a vector of integers.
Related
sourcePortfolioOptimisers.VecNum_VecVecNum Type
const VecNum_VecVecNum = Union{<:VecNum, <:VecVecNum}Alias for a union of a numeric vector or a vector of numeric vectors.
Related
sourcePortfolioOptimisers.VecDate Type
abstract type AbstractArray{var"#s30"<:Dates.AbstractTime, 1}Alias for an abstract vector of date or time types.
Related
sourcePortfolioOptimisers.Dict_Vec Type
const Dict_Vec = Union{<:AbstractDict, <:AbstractVector}Alias for a union of an abstract dictionary or an abstract vector.
Related
sourcePortfolioOptimisers.Sym_Str Type
const Sym_Str = Union{Symbol, <:AbstractString}Alias for a union of a symbol or an abstract string.
Related
sourcePortfolioOptimisers.Str_Vec Type
const Str_Vec = Union{<:AbstractString, <:AbstractVector}Alias for a union of an abstract string or an abstract vector.
Related
sourcePortfolioOptimisers.ObsWeights Type
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
sourcePortfolioOptimisers.Num_VecNum_VecScalar Type
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
sourcePortfolioOptimisers.Num_ArrNum_VecScalar_DynWeights Type
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
sourcePortfolioOptimisers.Func_VecNum Type
const Func_VecNum = Union{<:Function, <:VecNum}Alias for a union of a function and a vector of numeric types.
Related
sourceGlossaries
In order to standardise the documentation we use a arg_dict of terms.
PortfolioOptimisers.arg_dict Constant
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.
PortfolioOptimisers.val_dict Constant
const 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.
PortfolioOptimisers.ret_dict Constant
Dictionary containing return value descriptions for common parameters used in PortfolioOptimisers.jl.
PortfolioOptimisers.field_dict Constant
field_dictDerived 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 :).
PortfolioOptimisers.math_dict Constant
math_dictDictionary 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.
sourcePortfolioOptimisers.err_name_dict Constant
err_name_dictMaps high-order-moment argument keys to the domain noun used in error messages, so a message names what the caller supplied (e.g. cokurtosis) rather than the bare field symbol. The symbol itself is appended at the call site, giving messages like
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
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.
Base.getindex Method
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.