Tools
PorfolioOptimisers.jl is a complex codebase which uses a variety of general purpose tools including functions, constants and types.
Utility functions
We strive to be as type-stable, inferrable, and immutable as possible in order to improve robustness, performance, and correctness. These functions help us achieve these goals.
PortfolioOptimisers.traverse_concrete_subtypes Function
traverse_concrete_subtypes(t, ctarr::Option{<:AbstractVector} = nothing) -> AbstractVectorRecursively traverse all subtypes of the given abstract type t and collect all concrete struct types into ctarr.
Arguments
t: An abstract type whose subtypes will be traversed.ctarr: Optional An array to collect the concrete types. If not provided, a new empty array is created.
Examples
julia> abstract type MyAbstract end
julia> struct MyConcrete1 <: MyAbstract end
julia> struct MyConcrete2 <: MyAbstract end
julia> traverse_concrete_subtypes(MyAbstract)
2-element Vector{Any}:
MyConcrete1
MyConcrete2PortfolioOptimisers.concrete_typed_array Function
concrete_typed_array(A::AbstractArray) -> Array{Union{...}}Convert an AbstractArray A to a concrete typed array, where each element is of the same type as the elements of A.
This is useful for converting arrays with abstract element types to arrays with concrete element types, which can improve performance in some cases.
Arguments
A: The input array.
Returns
A_new::Array{Union{...}}: A new array with the same shape asA, but with a concrete element type inferred from the elements ofA.
Examples
julia> A = Any[1, 2.0, 3];
julia> PortfolioOptimisers.concrete_typed_array(A)
3-element Vector{Union{Float64, Int64}}:
1
2.0
3PortfolioOptimisers.factory Method
factory(a::Union{Nothing, <:AbstractEstimator, <:AbstractAlgorithm,
<:AbstractResult}, args...; kwargs...) -> aNo-op factory function for constructing objects with a uniform interface.
Defining methods which dispatch on the first argument allows for a consistent factory interface across different types.
Arguments
a: Indicates no object should be constructed.args...: Arbitrary positional arguments (ignored).kwargs...: Arbitrary keyword arguments (ignored).
Related
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_nonneg_finite_val Function
assert_nonempty_nonneg_finite_val(
val::Union{<:AbstractDict, <:VecPair, <:ArrNum, Pair, Number},
val_sym::Union{Symbol,<:AbstractString} = :val
) -> nothing
assert_nonempty_nonneg_finite_val(args...) -> nothingValidate 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.
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
) -> nothing
assert_nonempty_gt0_finite_val(args...) -> nothingValidate 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.
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
) -> nothing
assert_nonempty_finite_val(args...) -> nothingValidate that the input value is non-empty and finite.
Arguments
val: Input value to validate.val_sym: Symbolic name used in the error messages.
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) -> nothingAssert that the input matrix is square.
Arguments
X: Input matrix to validate.X_sym: Symbolic name used in error messages.
Validation
size(X, 1) == size(X, 2).
Details
- Throws
DimensionMismatchif the check fails.
Mathematical functions
PortfolioOptimisers.jl makes use of various mathematical operators, some of which are generic to support the variety of inputs supported by the library.
PortfolioOptimisers.:⊗ Function
⊗(A::ArrNum, B::ArrNum) -> Matrix{promote_type(eltype(A), eltype(B))}Tensor product of two arrays. Returns a matrix of size (length(A), length(B)) where each element is the product of elements from A and B.
Examples
julia> PortfolioOptimisers.:⊗([1, 2], [3, 4])
2×2 Matrix{Int64}:
3 4
6 8Related
sourcePortfolioOptimisers.:⊙ Function
⊙(A::ArrNum, B::ArrNum) -> Matrix{promote_type(eltype(A), eltype(B))}
⊙(A::ArrNum, B) -> Vector{promote_type(eltype(A), eltype(B))}
⊙(A, B::ArrNum) -> Vector{promote_type(eltype(A), eltype(B))}
⊙(A, B) -> promote_type(eltype(A), eltype(B))Elementwise (Hadamard) multiplication.
Examples
julia> PortfolioOptimisers.:⊙([1, 2], [3, 4])
2-element Vector{Int64}:
3
8
julia> PortfolioOptimisers.:⊙([1, 2], 2)
2-element Vector{Int64}:
2
4
julia> PortfolioOptimisers.:⊙(2, [3, 4])
2-element Vector{Int64}:
6
8
julia> PortfolioOptimisers.:⊙(2, 3)
6PortfolioOptimisers.:⊘ Function
⊘(A::ArrNum, B::ArrNum) -> Matrix{promote_type(eltype(A), eltype(B))}
⊘(A::ArrNum, B) -> Vector{promote_type(eltype(A), eltype(B))}
⊘(A, B::ArrNum) -> Vector{promote_type(eltype(A), eltype(B))}
⊘(A, B) -> promote_type(eltype(A), eltype(B))Elementwise (Hadamard) division.
Examples
julia> PortfolioOptimisers.:⊘([4, 9], [2, 3])
2-element Vector{Float64}:
2.0
3.0
julia> PortfolioOptimisers.:⊘([4, 6], 2)
2-element Vector{Float64}:
2.0
3.0
julia> PortfolioOptimisers.:⊘(8, [2, 4])
2-element Vector{Float64}:
4.0
2.0
julia> PortfolioOptimisers.:⊘(8, 2)
4.0PortfolioOptimisers.:⊕ Function
⊕(A::ArrNum, B::ArrNum) -> Matrix{promote_type(eltype(A), eltype(B))}
⊕(A::ArrNum, B) -> Vector{promote_type(eltype(A), eltype(B))}
⊕(A, B::ArrNum) -> Vector{promote_type(eltype(A), eltype(B))}
⊕(A, B) -> promote_type(eltype(A), eltype(B))Elementwise (Hadamard) addition.
Examples
julia> PortfolioOptimisers.:⊕([1, 2], [3, 4])
2-element Vector{Int64}:
4
6
julia> PortfolioOptimisers.:⊕([1, 2], 2)
2-element Vector{Int64}:
3
4
julia> PortfolioOptimisers.:⊕(2, [3, 4])
2-element Vector{Int64}:
5
6
julia> PortfolioOptimisers.:⊕(2, 3)
5PortfolioOptimisers.:⊖ Function
⊖(A::ArrNum, B::ArrNum) -> Matrix{promote_type(eltype(A), eltype(B))}
⊖(A::ArrNum, B) -> Vector{promote_type(eltype(A), eltype(B))}
⊖(A, B::ArrNum) -> Vector{promote_type(eltype(A), eltype(B))}
⊖(A, B) -> promote_type(eltype(A), eltype(B))Elementwise (Hadamard) subtraction.
Examples
julia> PortfolioOptimisers.:⊖([4, 6], [1, 2])
2-element Vector{Int64}:
3
4
julia> PortfolioOptimisers.:⊖([4, 6], 2)
2-element Vector{Int64}:
2
4
julia> PortfolioOptimisers.:⊖(8, [2, 4])
2-element Vector{Int64}:
6
4
julia> PortfolioOptimisers.:⊖(8, 2)
6PortfolioOptimisers.dot_scalar Function
dot_scalar(a::Union{<:Number, <:JuMP.AbstractJuMPScalar}, b::VecNum) -> Number
dot_scalar(a::VecNum, b::Union{<:Number, <:JuMP.AbstractJuMPScalar}) -> Number
dot_scalar(a::VecNum, b::VecNum) -> NumberEfficient scalar and vector dot product utility.
If one argument is a
Union{<:Number, <:JuMP.AbstractJuMPScalar}and the other anVecNum, returns the scalar times the sum of the vector.If both arguments are
VecNums, returns theirdotproduct.
Examples
julia> PortfolioOptimisers.dot_scalar(2.0, [1.0, 2.0, 3.0])
12.0
julia> PortfolioOptimisers.dot_scalar([1.0, 2.0, 3.0], 2.0)
12.0
julia> PortfolioOptimisers.dot_scalar([1.0, 2.0, 3.0], [4.0, 5.0, 6.0])
32.0Related
sourceView functions
[NestedClustered]-(@ref) optimisations need to index the asset universe in order to produce the inner optimisations. These indexing operations are implemented as views, indexing, and custom index generators.
PortfolioOptimisers.nothing_scalar_array_view Function
nothing_scalar_array_view(
x::Union{Nothing, <:Number, <:Pair, <:VecPair, <:Dict,
AbstractEstimatorValueAlgorithm},
::Any
) -> typeof(x)
nothing_scalar_array_view(x::AbstractVector, i) -> view(x, i)
nothing_scalar_array_view(x::VecScalar, i) -> VecScalar(; v = view(x.v, i), s = x.s)
nothing_scalar_array_view(x::AbstractMatrix, i) -> view(x, i, i)
nothing_scalar_array_view(
x::AbstractVector{<:Union{<:AbstractVector, <:AbstractMatrix, <:VecScalar}},
i
) -> [nothing_scalar_array_view(xi, i) for xi in x]Utility for safely viewing into possibly nothing, scalar, or array values.
Arguments
x: Input value.i: Index or indices to view.
Examples
julia> PortfolioOptimisers.nothing_scalar_array_view(nothing, 1:2)
julia> PortfolioOptimisers.nothing_scalar_array_view(3.0, 1:2)
3.0
julia> PortfolioOptimisers.nothing_scalar_array_view([1.0, 2.0, 3.0], 2:3)
2-element view(::Vector{Float64}, 2:3) with eltype Float64:
2.0
3.0
julia> PortfolioOptimisers.nothing_scalar_array_view([[1, 2], [3, 4]], 1)
2-element Vector{SubArray{Int64, 0, Vector{Int64}, Tuple{Int64}, true}}:
fill(1)
fill(3)PortfolioOptimisers.nothing_scalar_array_view_odd_order Function
nothing_scalar_array_view_odd_order(::Nothing, i, j) -> nothing
nothing_scalar_array_view_odd_order(x::AbstractMatrix, i, j) -> view(x, i, j)Utility for safely viewing or indexing into possibly nothing or array values with two indices.
If
xisnothing, returnsnothing.Otherwise, returns
view(x, i, j).
Arguments
x: Input value.i,j: Indices to view.
Examples
julia> PortfolioOptimisers.nothing_scalar_array_view_odd_order(nothing, 1, 2)
julia> PortfolioOptimisers.nothing_scalar_array_view_odd_order([1 2; 3 4], 1, 2)
0-dimensional view(::Matrix{Int64}, 1, 2) with eltype Int64:
2PortfolioOptimisers.nothing_scalar_array_getindex Function
nothing_scalar_array_getindex(x::Union{Nothing, <:Number, <:Pair, <:VecPair, <:Dict}, ::Any) -> Union{Nothing, <:Number, <:Pair, <:VecPair, <:Dict}
nothing_scalar_array_getindex(x::AbstractVector, i) -> x[i]
nothing_scalar_array_getindex(x::VecScalar, i) -> VecScalar(; v = x.v[i], s = x.s)
nothing_scalar_array_getindex(x::AbstractVector{<:Union{<:AbstractVector, <:VecScalar}}, i) -> [nothing_scalar_array_getindex(xi, i) for xi in x]
nothing_scalar_array_getindex(x::AbstractMatrix, i) -> x[i, i]Utility for safely viewing into possibly nothing, scalar, or array values.
Arguments
x: Input value.i: Index or indices to view.
Returns
x: Input value.::Union{Nothing, <:Number, <:Pair, <:VecPair, <:Dict}: Returnsxunchanged.::AbstractVector: Returnsview(x, i).::VecScalar: ReturnsVecScalar(; v = view(x.v, i), s = x.s).::AbstractVector{<:Union{<:AbstractVector, <:VecScalar}}: Returns a vector of views for each element inx.::AbstractMatrix: Returnsview(x, i, i).
Examples
julia> PortfolioOptimisers.nothing_scalar_array_getindex(nothing, 1:2)
julia> PortfolioOptimisers.nothing_scalar_array_getindex(3.0, 1:2)
3.0
julia> PortfolioOptimisers.nothing_scalar_array_getindex([1.0, 2.0, 3.0], 2:3)
2-element Vector{Float64}:
2.0
3.0
julia> PortfolioOptimisers.nothing_scalar_array_getindex([[1, 2], [3, 4]], 1)
2-element Vector{Int64}:
1
3PortfolioOptimisers.nothing_scalar_array_getindex_odd_order Function
nothing_scalar_array_getindex_odd_order(::Nothing, i, j) -> nothing
nothing_scalar_array_getindex_odd_order(x::AbstractMatrix, i, j) -> x[i, j]Utility for safely viewing or indexing into possibly nothing or array values with two indices.
If
xisnothing, returnsnothing.Otherwise, returns
view(x, i, j).
Arguments
x: Input value.i,j: Indices to view.
Examples
julia> PortfolioOptimisers.nothing_scalar_array_getindex_odd_order(nothing, 1, 2)
julia> PortfolioOptimisers.nothing_scalar_array_getindex_odd_order([1 2; 3 4], 1, 2)
2PortfolioOptimisers.fourth_moment_index_generator Function
fourth_moment_index_generator(
N::Integer,
i
) -> Vector{Int64}Constructs an index vector for extracting the fourth moment submatrix corresponding to indices i from a covariance matrix of size N × N.
Arguments
N: Size of the full covariance matrix.i: Indices of the variables of interest.
Returns
idx::VecInt: Indices for extracting the fourth moment submatrix.
Examples
julia> PortfolioOptimisers.fourth_moment_index_generator(3, [1, 2])
4-element Vector{Int64}:
1
2
4
5Summary statistics
Some estimators and constraints are based on summary statistics of vectors. These types are used to dispatch the appropriate functions and encapsulate auxiliary data such as weights.
PortfolioOptimisers.VectorToScalarMeasure Type
abstract type VectorToScalarMeasure <: AbstractAlgorithmAbstract supertype for algorithms mapping a vector of real values to a single real value.
VectorToScalarMeasure provides a unified interface for algorithms that reduce a vector of real numbers to a scalar, such as minimum, mean, median, or maximum. These are used in constraint generation and centrality-based portfolio constraints to aggregate asset-level metrics.
Related
sourcePortfolioOptimisers.Num_VecToScaM Type
const Num_VecToScaM = Union{<:Number, <:VectorToScalarMeasure, <:Function}Union type representing either a numeric value or a VectorToScalarMeasure.
This type is used to allow functions and fields to accept both plain numbers and objects that implement the VectorToScalarMeasure interface, providing flexibility in handling scalar and vector-to-scalar computations.
Related
sourcePortfolioOptimisers.MinValue Type
struct MinValue <: VectorToScalarMeasureAlgorithm for reducing a vector of real values to its minimum.
Examples
julia> PortfolioOptimisers.vec_to_real_measure(MinValue(), [1.2, 3.4, 0.7])
0.7Related
sourcePortfolioOptimisers.MeanValue Type
struct MeanValue{__T_w} <: VectorToScalarMeasureAlgorithm for reducing a vector of real values to its optionally weighted mean.
Fields
w: Optional observation weights vector.
Constructors
MeanValue(; w::Option{<:StatsBase.AbstractWeights} = nothing)Keyword arguments correspond to the fields above.
Validation
- If
wis notnothing,!isempty(w).
Examples
julia> PortfolioOptimisers.vec_to_real_measure(MeanValue(), [1.2, 3.4, 0.7])
1.7666666666666666Related
sourcePortfolioOptimisers.factory Method
factory(_::MeanValue, w::AbstractWeights) -> MeanValueConstruct a MeanValue instance with observation weights w.
Arguments
mv: Instance to update.w: Observation weights vector.
Examples
julia> factory(MeanValue(), StatsBase.Weights([1.2, 3.4, 0.7]))
MeanValue
w ┴ StatsBase.Weights{Float64, Float64, Vector{Float64}}: [1.2, 3.4, 0.7]Related
sourcePortfolioOptimisers.MedianValue Type
struct MedianValue{__T_w} <: VectorToScalarMeasureAlgorithm for reducing a vector of real values to its optionally weighted median.
Fields
w: Optional observation weights vector.
Constructors
MedianValue(; w::Option{<:StatsBase.AbstractWeights} = nothing)Keyword arguments correspond to the fields above.
Validation
- If
wis notnothing,!isempty(w).
Examples
julia> PortfolioOptimisers.vec_to_real_measure(MedianValue(), [1.2, 3.4, 0.7])
1.2Related
sourcePortfolioOptimisers.factory Method
factory(_::MedianValue, w::AbstractWeights) -> MedianValueConstructs a MedianValue instance with observation weights w.
Arguments
mv: Instance to update.w: Observation weights vector.
Examples
julia> factory(MedianValue(), StatsBase.Weights([1.2, 3.4, 0.7]))
MedianValue
w ┴ StatsBase.Weights{Float64, Float64, Vector{Float64}}: [1.2, 3.4, 0.7]Related
sourcePortfolioOptimisers.MaxValue Type
struct MaxValue <: VectorToScalarMeasureAlgorithm for reducing a vector of real values to its maximum.
Examples
julia> PortfolioOptimisers.vec_to_real_measure(MaxValue(), [1.2, 3.4, 0.7])
3.4Related
sourcePortfolioOptimisers.StdValue Type
struct StdValue{__T_w, __T_corrected} <: VectorToScalarMeasureAlgorithm for reducing a vector of real values to its optionally weighted standard deviation.
Fields
w: Optional observation weights vector.corrected: Indicates whether to use Bessel's correction (truefor sample standard deviation,falsefor population).
Constructors
StdValue(; w::Option{<:StatsBase.AbstractWeights} = nothing, corrected::Bool = true)Keyword arguments correspond to the fields above.
Validation
- If
wis notnothing,!isempty(w).
Examples
julia> PortfolioOptimisers.vec_to_real_measure(StdValue(), [1.2, 3.4, 0.7])
1.4364307617610164Related
sourcePortfolioOptimisers.factory Method
factory(
sv::StdValue,
w::AbstractWeights
) -> StdValue{_A, Bool} where _AConstructs a StdValue instance with observation weights w.
Arguments
sv: Instance to update.w: Observation weights vector.
Examples
julia> factory(StdValue(), StatsBase.Weights([1.2, 3.4, 0.7]))
StdValue
w ┼ StatsBase.Weights{Float64, Float64, Vector{Float64}}: [1.2, 3.4, 0.7]
corrected ┴ Bool: trueRelated
sourcePortfolioOptimisers.VarValue Type
struct VarValue{__T_w, __T_corrected} <: VectorToScalarMeasureAlgorithm for reducing a vector of real values to its optionally weighted variance.
Fields
w: Optional observation weights vector.corrected: Indicates whether to use Bessel's correction (truefor sample standard deviation,falsefor population).
Constructors
VarValue(; w::Option{<:StatsBase.AbstractWeights} = nothing, corrected::Bool = true)Keyword arguments correspond to the fields above.
Validation
- If
wis notnothing,!isempty(w).
Examples
julia> PortfolioOptimisers.vec_to_real_measure(VarValue(), [1.2, 3.4, 0.7])
2.0633333333333335Related
sourcePortfolioOptimisers.factory Method
factory(
vv::VarValue,
w::AbstractWeights
) -> VarValue{_A, Bool} where _AConstructs a VarValue instance with observation weights w.
Arguments
vv: Instance to update.w: Observation weights vector.
Examples
julia> factory(VarValue(), StatsBase.Weights([1.2, 3.4, 0.7]))
VarValue
w ┼ StatsBase.Weights{Float64, Float64, Vector{Float64}}: [1.2, 3.4, 0.7]
corrected ┴ Bool: trueRelated
sourcePortfolioOptimisers.SumValue Type
struct SumValue <: VectorToScalarMeasureAlgorithm for reducing a vector of real values to its sum.
Examples
julia> PortfolioOptimisers.vec_to_real_measure(SumValue(), [1.2, 3.4, 0.7])
5.3Related
sourcePortfolioOptimisers.ProdValue Type
struct ProdValue <: VectorToScalarMeasureAlgorithm for reducing a vector of real values to its product.
Examples
julia> PortfolioOptimisers.vec_to_real_measure(ProdValue(), [1.2, 3.4, 0.7])
2.856Related
sourcePortfolioOptimisers.ModeValue Type
struct ModeValue <: VectorToScalarMeasureAlgorithm for reducing a vector of real values to its mode.
Examples
julia> PortfolioOptimisers.vec_to_real_measure(ModeValue(), [1.2, 3.4, 0.7, 1.2])
1.2Related
sourcePortfolioOptimisers.StandardisedValue Type
struct StandardisedValue{__T_mv, __T_sv} <: VectorToScalarMeasureAlgorithm for reducing a vector of real values to its optionally weighted mean divided by its optionally weighted standard deviation.
Fields
mv: The mean value measure used for the numerator.sv: The standard deviation measure used for the denominator.
Constructors
StandardisedValue(; mv::MeanValue = MeanValue(), sv::StdValue = StdValue())Keyword arguments correspond to the fields above.
Examples
julia> PortfolioOptimisers.vec_to_real_measure(StandardisedValue(), [1.2, 3.4, 0.7])
1.2299003291330186Related
sourcePortfolioOptimisers.factory Method
factory(
msv::StandardisedValue,
w::AbstractWeights
) -> StandardisedValue{MeanValue{__T_w}, StdValue{__T_w1, __T_corrected}} where {__T_w, __T_w1, __T_corrected}Construct a StandardisedValue instance with observation weights w for both mv and sv.
Arguments
msv: Instance to update.w: Observation weights vector.
Examples
julia> factory(StandardisedValue(), StatsBase.Weights([1.2, 3.4, 0.7]))
StandardisedValue
mv ┼ MeanValue
│ w ┴ StatsBase.Weights{Float64, Float64, Vector{Float64}}: [1.2, 3.4, 0.7]
sv ┼ StdValue
│ w ┼ StatsBase.Weights{Float64, Float64, Vector{Float64}}: [1.2, 3.4, 0.7]
│ corrected ┴ Bool: trueRelated
source