Skip to content
18

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
julia
traverse_concrete_subtypes(t, ctarr::Option{<:AbstractVector} = nothing) -> AbstractVector

Recursively 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.

Returns

  • types::Vector{Any}: An array containing all concrete struct types that are subtypes (direct or indirect) of types.

Examples

julia
julia> abstract type MyAbstract end

julia> struct MyConcrete1 <: MyAbstract end

julia> struct MyConcrete2 <: MyAbstract end

julia> PortfolioOptimisers.traverse_concrete_subtypes(MyAbstract)
2-element Vector{Any}:
 MyConcrete1
 MyConcrete2

Related

source
PortfolioOptimisers.concrete_typed_array Function
julia
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::Vector{Union{...}}: A new array with the same shape as A, but with a concrete element type inferred from the elements of A.

Examples

julia
julia> A = Any[1, 2.0, 3];

julia> PortfolioOptimisers.concrete_typed_array(A)
3-element Vector{Union{Float64, Int64}}:
 1
 2.0
 3

Related

source
PortfolioOptimisers.factory Method
julia
factory(a::Union{Nothing, <:AbstractEstimator, <:AbstractAlgorithm,
                 <:AbstractResult}, args...; kwargs...) -> a

No-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.

factory and port_opt_view are the two propagation mechanisms in this library. They are duals: factory threads runtime values (prior moments, observation weights, previous portfolio weights) down through a composed struct tree; port_opt_view threads an index selection (a subset of assets or observations) down through the same tree.

Arguments

  • a: Indicates no object should be constructed.

  • args...: Arbitrary positional arguments (ignored).

  • kwargs...: Arbitrary keyword arguments (ignored).

Returns

  • a: The input unchanged.

Examples

julia
julia> factory(nothing, 1, 2; x = 3)

julia> factory(MeanValue())
MeanValue
  w ┴ nothing

Related

source
PortfolioOptimisers.get_window Function
julia
get_window(window::Option{<:Colon}, args...) -> Option{<:Colon}
get_window(window::Integer, X::MatNum, dims::Int = 1) -> VecInt
get_window(window::Integer, X::VecNum, args...) -> VecInt
get_window(window::VecInt, args...) -> VecInt

Get the observation window index range for a data array.

Arguments

  • window: Observation window.

    • ::Option{<:Colon}: Returns Colon().

    • ::Integer: Returns the last window observations. This operation is safe, so it doesn't error if window is larger than the number of observations.

    • ::VecInt: Returns the window argument.

  • X: Data matrix or vector.

  • dims: Dimension along which to perform the computation.

Returns

  • window::Option{Union{Colon, <:VecInt}}: The window index range.

Related

source
PortfolioOptimisers.@propagatable Macro
julia
@propagatable expr

Define a struct and automatically generate its propagation methods from five orthogonal, stackable field tags:

  • @fprop (factory propagation): tagged fields receive factory_child calls when factory is invoked, recursing runtime values (observation weights, prior results, solvers, …) down the composition tree. A factory(x, args...) method is always generated (it is the identity when no field is tagged @fprop/@wprop).

  • @wprop (weights replacement): tagged observation-weights fields are replaced by an incoming ObsWeights argument via _wprop (and left unchanged when none is threaded). Use @wprop for the weights slot and @fprop for sub-estimators — a weights field that defaults to nothing must become the incoming weights, which conflicts with @fprop's nothing-passthrough.

  • @vprop (view propagation): tagged fields receive port_opt_view calls when a view (an index selection) is propagated, recursing into composed children and slicing data arrays. A port_opt_view method is generated only when at least one field is tagged @vprop.

  • @pprop (prior selection): tagged fields are selected from the same-named field on a prior result via sel(getfield(x, :f), getproperty(pr, :f)).

  • @cprop (context selection): tagged fields are selected against a threaded optimiser value (a solver) found by type via sel(getfield(x, :f), _ctx(args...)).

When at least one field is tagged @pprop or @cprop, a second method factory(x, pr::AbstractPriorResult, args...) is generated. It selects @pprop/@cprop fields as above and threads @fprop-only fields with pr (factory_child(getfield(x, :f), pr, args...)); a field tagged both @pprop and @fprop is prior-selected in this method (@pprop wins). Because this method is more specific than the general factory(x, args...), it is chosen whenever a prior is passed.

Untagged fields pass through unchanged in every method, regardless of type — tagging is explicit and opt-in. The tags are independent and the relevant field sets genuinely diverge. @pprop and @cprop are mutually exclusive on one field (a value comes from exactly one source); legal stacks are @pprop @fprop (sub-estimator) and @pprop @wprop (weights slot). See ADR 0010 and 0012.

Composes with @concrete (put @propagatable outermost):

julia
@propagatable @concrete struct MyMeasure <: RiskMeasure
    @pprop @wprop w       # prior factory selects pr.w; ObsWeights factory fills w
    @pprop sigma          # prior-selected from pr.sigma
    @fprop alg            # threaded (recursed) with pr / args
    config                # passed through unchanged
    function MyMeasure(w, sigma, alg, config)
        return new{typeof(w), typeof(sigma), typeof(alg), typeof(config)}(w, sigma, alg,
                                                                          config)
    end
end

The generated factory/port_opt_view methods are added to the PortfolioOptimisers functions, so @propagatable works correctly for types defined in external packages.

Docstrings on the enclosing definition are forwarded correctly via Base.@__doc__.

source
PortfolioOptimisers.factory_child Function
julia
factory_child(v, args...; kwargs...) -> Any

Per-field recursion helper called by @propagatable-generated factory methods.

Dispatches on the field value type: estimators, algorithms, and results recurse via factory; observation-weight fields (::Nothing or ::StatsBase.AbstractWeights) are replaced by the incoming ObsWeights argument; everything else passes through unchanged.

Related

source
PortfolioOptimisers.@fprop Macro
julia
@fprop field

Field tag for use inside a @propagatable struct body. Marks the field as participating in factory propagation — factory_child will be called on it when factory is invoked on the enclosing struct.

Raises an error if used outside a @propagatable struct body.

source
PortfolioOptimisers.@vprop Macro
julia
@vprop field

Field tag for use inside a @propagatable struct body. Marks the field as participating in port_opt_view propagation — port_opt_view will be called on it when a view (index selection) is propagated through the enclosing struct.

Orthogonal to @fprop; the two may be stacked on one field (@fprop @vprop field) when it participates in both factory and view propagation.

Raises an error if used outside a @propagatable struct body.

source
PortfolioOptimisers.@pprop Macro
julia
@pprop field

Field tag for use inside a @propagatable struct body. Marks the field as prior-selected: when factory(x, pr::AbstractPriorResult, …) is invoked, the field is set to sel(getfield(x, :field), getproperty(pr, :field)) — the risk-measure value if present, else the same-named moment from the prior result.

Orthogonal to, and stackable with, @wprop (@pprop @wprop w gives a weights field both a prior factory and an ObsWeights factory) or @fprop; @pprop wins in the prior method. Mutually exclusive with @cprop on a single field. See ADR 0012.

Raises an error if used outside a @propagatable struct body.

source
PortfolioOptimisers.@wprop Macro
julia
@wprop field

Field tag for use inside a @propagatable struct body. Marks the field as an observation-weights slot: when factory(x, w::ObsWeights, …) is invoked, the field is replaced by the incoming weights via _wprop; when no ObsWeights is threaded, it is left unchanged.

Distinct from @fprop, which recurses into a sub-estimator value and leaves a nothing value untouched. A weights field defaults to nothing (meaning "uniform") and must become the incoming weights — so it cannot share @fprop's nothing-handling without the two semantics colliding. Use @wprop for the w/weights field and @fprop for sub-estimators.

Raises an error if used outside a @propagatable struct body.

source
PortfolioOptimisers.@cprop Macro
julia
@cprop field

Field tag for use inside a @propagatable struct body. Marks the field as context-selected: when factory(x, pr::AbstractPriorResult, …) is invoked, the field is set to sel(getfield(x, :field), _ctx(args...)) — the risk-measure value if present, else the threaded optimiser value (a solver) located by type in the variadic tail. Used for slv fields, whose source is a threaded argument rather than the prior. Mutually exclusive with @pprop on a single field. See ADR 0012.

Raises an error if used outside a @propagatable struct body.

source
PortfolioOptimisers.is_prop_tag_call Function
julia
is_prop_tag_call(x) -> Union{Missing, Bool}

Return true if x is a macro call to any of @fprop, @vprop, @pprop or @cprop.

Used by propagatable_parse_body to detect tagged fields in a struct body.

Related

source
PortfolioOptimisers.is_fprop_macro Function
julia
is_fprop_macro(x) -> Union{Missing, Bool}

Return true if x is a reference to the @fprop macro (bare Symbol or GlobalRef).

Used by propagatable_parse_body to detect @fprop-tagged fields in a struct body.

Related

source
PortfolioOptimisers.is_vprop_macro Function
julia
is_vprop_macro(x) -> Union{Missing, Bool}

Return true if x is a reference to the @vprop macro (bare Symbol or GlobalRef).

Used by propagatable_parse_body to detect @vprop-tagged fields in a struct body.

Related

source
PortfolioOptimisers.is_pprop_macro Function
julia
is_pprop_macro(x) -> Union{Missing, Bool}

Return true if x is a reference to the @pprop macro (bare Symbol or GlobalRef).

Used by propagatable_parse_body to detect @pprop-tagged fields in a struct body.

Related

source
PortfolioOptimisers.is_wprop_macro Function
julia
is_wprop_macro(x) -> Union{Missing, Bool}

Return true if x is a reference to the @wprop macro (bare Symbol or GlobalRef).

Used by propagatable_parse_body to detect @wprop-tagged fields in a struct body.

Related

source
PortfolioOptimisers.is_cprop_macro Function
julia
is_cprop_macro(x) -> Union{Missing, Bool}

Return true if x is a reference to the @cprop macro (bare Symbol or GlobalRef).

Used by propagatable_parse_body to detect @cprop-tagged fields in a struct body.

Related

source
PortfolioOptimisers.is_doc_macro Function
julia
is_doc_macro(x) -> Union{Missing, Bool}

Return true if x is a reference to Julia's @doc macro (bare Symbol or GlobalRef).

Used by propagatable_parse_body to recognise docstring-prefixed fields in a struct body.

Related

source
PortfolioOptimisers._ctx Function
julia
_ctx(args...)

Locate the lone threaded optimiser context value (a solver, Slv_VecSlv) in the variadic tail of a prior factory call, returning nothing if none is present. Emitted by the @cprop tag as the source argument to sel. The tuple scan is unrolled by the compiler, so it is type-stable and allocation-free. See ADR 0012.

Related

source
PortfolioOptimisers._wprop Function
julia
_wprop(
    field,
    args...;
    kwargs...
) -> Union{DynamicAbstractWeights, AbstractWeights}

Resolve the new value of a @wprop-tagged observation-weights field during factory propagation.

When an ObsWeights argument is threaded through factory, the field is replaced by those weights; otherwise the existing field value is kept. This is distinct from factory_child (used by @fprop), which recurses into sub-estimators and leaves nothing/non-estimator values unchanged — a weights slot must not be confused with an optional sub-estimator that happens to be nothing.

Related

source
PortfolioOptimisers.sel Function
julia
sel(risk_variable, source_variable)

Unified risk-measure selector emitted by the @pprop/@cprop tags. Prefers the risk-measure value risk_variable when present, otherwise falls back to source_variable (a prior moment for @pprop, or a threaded optimiser value for @cprop). Dispatches on operand types to the appropriate leaf selector and inlines to zero cost:

Note: the solver_selector both-nothing "cannot solve" error is not reachable through sel (both-nothing routes to the moment selector and returns nothing); the JuMPOptimiser solver-required invariant makes that case unreachable in the pipeline. See ADR 0012.

Related

source
PortfolioOptimisers.extract_field_name Function
julia
extract_field_name(expr) -> Any

Extract the field name Symbol from a bare field or field::Type expression.

Errors with a descriptive message when expr is neither a bare Symbol nor a field::Type annotation, since only those forms are valid after @fprop.

Arguments

  • expr: A Symbol, an Expr with head :(::), or any other expression (triggers an error).

Returns

  • name::Symbol: The field name.

Related

source
PortfolioOptimisers.propagatable_find_struct Function
julia
propagatable_find_struct(
    expr
) -> Union{Tuple{Expr, typeof(identity)}, Tuple{Expr, Union{PortfolioOptimisers.var"#propagatable_find_struct##0#propagatable_find_struct##1"{Vector{Any}, typeof(identity)}, PortfolioOptimisers.var"#propagatable_find_struct##0#propagatable_find_struct##1"{Vector{Any}, PortfolioOptimisers.var"#propagatable_find_struct##0#propagatable_find_struct##1"{Vector{Any}, rebuild}} where rebuild}}}

Recursively unwrap macro call chains to locate the innermost :struct node.

Returns (struct_node, rebuild_fn) where rebuild_fn(new_struct) reconstructs the original macro chain with new_struct in place of the original struct. This allows @propagatable to inject modified struct definitions back into arbitrary macro wrappers such as @concrete.

Arguments

  • expr: A :struct expression or a :macrocall expression wrapping one.

Returns

  • struct_node::Expr: The innermost :struct expression.

  • rebuild_fn::Function: A function that, given a replacement :struct, returns the full macro chain with the replacement in place of the original.

Related

source
PortfolioOptimisers.propagatable_bare_name Function
julia
propagatable_bare_name(n) -> Symbol

Extract the plain struct name Symbol from a potentially parameterised or supertype-constrained name expression.

Handles the forms Name, Name{T, ...}, and Name{T, ...} <: SuperType by recursively peeling :curly and :<: wrappers until a bare Symbol is reached.

Arguments

  • n: A Symbol, or an Expr with head :curly or :<:.

Returns

  • name::Symbol: The plain struct name.

Related

source
PortfolioOptimisers.try_field_name Function
julia
try_field_name(expr) -> Any

Return the field name Symbol for a plain field declaration, or nothing for non-field nodes.

Recognises bare Symbol fields and field::Type annotations. Returns nothing for LineNumberNodes, inner constructors, and any other expression that does not declare a single named field.

Arguments

  • expr: Any expression appearing in a struct body.

Returns

  • name::Symbol: The field name, if expr is a plain field declaration.

  • nothing: If expr is not a plain field declaration.

Related

source
PortfolioOptimisers.peel_prop_tags Function
julia
peel_prop_tags(
    expr
) -> Tuple{Bool, Bool, Bool, Bool, Bool, Any}

Peel any stack of @fprop/@vprop/@pprop/@cprop tag macrocalls off a field expression, recording which tags were present.

Tags may be stacked in either order (@pprop @fprop field), which parses as nested :macrocall nodes; this unwraps them all and returns the bare field expression.

Returns

  • is_f::Bool: whether an @fprop tag was present.

  • is_v::Bool: whether a @vprop tag was present.

  • is_p::Bool: whether a @pprop tag was present.

  • is_c::Bool: whether a @cprop tag was present.

  • is_w::Bool: whether a @wprop tag was present.

  • stripped: the field expression with all tags removed.

Related

source
PortfolioOptimisers.propagatable_parse_body Function
julia
propagatable_parse_body(
    body
) -> Tuple{Vector{Symbol}, Vector{Symbol}, Vector{Symbol}, Vector{Symbol}, Vector{Symbol}, Vector{Symbol}, Expr}

Walk a struct body, collecting @fprop-, @vprop-, @pprop- and @cprop-tagged field names (and all field names) and stripping the tags from the body.

Handles bare tagged fields (@fprop field, …), stacked tags (@pprop @fprop field, in any order), and docstring-prefixed forms ("doc" \n @fprop field). Non-field nodes (line numbers, inner constructors) are carried through unchanged.

Arguments

  • body::Expr: The :block expression forming the struct body.

Returns

  • fprop_fields::Vector{Symbol}: Names of @fprop-tagged fields.

  • vprop_fields::Vector{Symbol}: Names of @vprop-tagged fields.

  • pprop_fields::Vector{Symbol}: Names of @pprop-tagged fields.

  • cprop_fields::Vector{Symbol}: Names of @cprop-tagged fields.

  • wprop_fields::Vector{Symbol}: Names of @wprop-tagged fields.

  • all_fields::Vector{Symbol}: Names of every declared field (tagged or not).

  • new_body::Expr: The struct body with all tags stripped.

Related

source
PortfolioOptimisers.@forward_properties Macro
julia
@forward_properties T begin
    forward(loc)
    forward(loc, names...)
    alias(exposed, loc)
    compute(exposed, loc; broadcast)
    compute(exposed, fn)
    swap(field, loc)
    swap(field, fn)
end

Generate the Base.getproperty / Base.propertynames pair for type T from a block of declarative forwarding rules, so the property-forwarding decision lives in one declared surface instead of a hand-written getproperty body (ADR 0013). T may be a bare type name or a parametric/UnionAll signature (Foo{<:Any, Nothing, <:Any}), so a swap can be specialised per type parameter.

All names are written as bare identifiers. Every rule names its source via a locator — a bare name a (the field a of the receiver) or a dotted path a.b.c (the receiver-rooted path obj.a.b.c, any depth). Nesting is simply more dots; a depth-≥2 path guards each intermediate and throws a PropertyPathError naming the path when a node is nothing.

forward/alias/compute only add new virtual names and so resolve after the receiver's own fields; swap replaces the value of an existing field and so resolves before the field check.

Rules

  • forward(loc): forward all properties of the value at loc (sym in propertynames(value) ? getproperty(value, sym)).

  • forward(loc, names...): forward only the named subset from the value at loc.

  • alias(exposed, loc): expose exposed as the value at loc (renaming).

  • compute(exposed, loc; broadcast): expose exposed via a dotted locator (depth ≥ 2); broadcast maps the final hop over a vector penultimate value.

  • compute(exposed, fn): expose exposed as fn(obj); fn must be an anonymous function (a lambda), which would otherwise be ambiguous with a dotted path.

  • swap(field, loc) / swap(field, fn): override an existing field's value with the value at loc (bare name, e.g. swap(L, M), or dotted path) or with fn(obj). Unlike the others it takes precedence over the own-field check, and is the only rule that may name a real field. Typically specialised on a parametric T (swap(L, M) on Regression{<:Any, Nothing, <:Any}). The locator form reads through getfield and is recursion-safe; in the function form the body must read the swapped field via getfield(obj, :field), never obj.field, since dot-access on the swapped field re-enters getproperty and recurses (StackOverflowError). Other fields may use dot-access freely.

Details

The generated getproperty applies any swap rules first (in declaration order), then checks the receiver's own fieldnames (via getfield, so it never recurses), then each remaining rule in declaration order with first-match-wins, then falls through to getfield(x, sym) (the standard "no field" error on T). The generated propertynames unions the own field names with every forwarded, subset, aliased, computed and swapped name, deduplicated.

Related

source
PortfolioOptimisers.forward_nonnothing Function
julia
forward_nonnothing(v, _::Type{T}, pathstr, nodestr) -> Any

Guard one intermediate node of a @forward_properties nested path.

Return v unchanged when it is not nothing; otherwise throw a PropertyPathError naming the receiver type T, the full declared path pathstr, and the nodestr node that resolved to nothing. Called once per intermediate hop in the descent generated for a depth-≥2 locator.

Related

source
PortfolioOptimisers.forward_flatten_path Function
julia
forward_flatten_path(expr) -> Vector{Symbol}

Flatten a @forward_properties locator into its path of field symbols.

A bare identifier a becomes [:a]; a dotted expression a.b.c becomes [:a, :b, :c]. Any other expression raises an error.

Related

source
PortfolioOptimisers.forward_walk_expr Function
julia
forward_walk_expr(
    path,
    struct_name,
    broadcast::Bool
) -> Expr

Build the expression that descends a @forward_properties path (a vector of field symbols) on the receiver x, returning the value at the path.

A depth-1 path is a single getfield. A depth-≥2 path descends hop by hop, guarding every intermediate with forward_nonnothing (keyed on the receiver type struct_name) so a nothing node throws a path-naming PropertyPathError. When broadcast is true, the final hop maps over the penultimate value if it is an AbstractVector (the scalar-or-vector solution case), otherwise it is a plain access.

Related

source

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
julia
(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.

Arguments

  • A::ArrNum: First array.

  • B::ArrNum: Second array.

Examples

julia
julia> PortfolioOptimisers.:([1, 2], [3, 4])
2×2 Matrix{Int64}:
 3  4
 6  8

Related

source
PortfolioOptimisers.:⊙ Function
julia
(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.

Arguments

  • A: First operand (array or scalar).

  • B: Second operand (array or scalar).

Examples

julia
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)
6

Related

source
PortfolioOptimisers.:⊘ Function
julia
(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.

Arguments

  • A: Dividend (array or scalar).

  • B: Divisor (array or scalar).

Examples

julia
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.0

Related

source
PortfolioOptimisers.:⊕ Function
julia
(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.

Arguments

  • A: First summand (array or scalar).

  • B: Second summand (array or scalar).

Examples

julia
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)
5

Related

source
PortfolioOptimisers.:⊖ Function
julia
(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.

Arguments

  • A: Minuend (array or scalar).

  • B: Subtrahend (array or scalar).

Examples

julia
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)
6

Related

source
PortfolioOptimisers.dot_scalar Function
julia
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) -> Number

Efficient scalar and vector dot product utility.

  • If one argument is a Union{<:Number, <:JuMP.AbstractJuMPScalar} and the other an VecNum, returns the scalar times the sum of the vector.

  • If both arguments are VecNums, returns their dot product.

Returns

  • res::Number: The resulting scalar.

Examples

julia
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.0

Related

source

View functions

NestedClustered 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.port_opt_view Method
julia
port_opt_view(x, i, args...; kwargs...) -> nothing_scalar_array_view(x, i)

Sub-select an estimator, result, or algorithm to the asset/observation index i.

port_opt_view is the index-selection counterpart of factory: where factory threads runtime values down a composed struct tree, port_opt_view threads an index selection — restricting every data-bearing field and composed child to the subset i. It is the mechanism that makes meta-optimisers (NestedClustered, SubsetResampling) and cross-validation variants operate on subproblems with identical struct shapes.

Callers do not normally call port_opt_view directly; it is driven by meta-optimisers and cross-validation internals. It is public (not exported) because extension authors who implement a new composed estimator may need to define a method. Use @vprop on data-bearing fields to have the method generated automatically.

This universal fallback handles leaf values: arrays are sliced via nothing_scalar_array_view; scalars, nothing, estimators without data fields, and algorithms pass through unchanged. Composed structs that recurse into children define their own (more specific) method — emitted by @vprop or hand-written.

The threaded tail args... (typically the returns matrix X for the JuMP families) and any kwargs are accepted and dropped here, so a macro-threaded port_opt_view(child, i, X) never MethodErrors on a leaf field.

Related

source
PortfolioOptimisers.port_opt_view Method
julia
port_opt_view(x::VecScalar, i, args...) -> nothing_scalar_array_view(x, i)

First-class port_opt_view method for VecScalar: slices the vector component and preserves the scalar component, delegating to nothing_scalar_array_view.

source
PortfolioOptimisers.nothing_scalar_array_view Function
julia
nothing_scalar_array_view(
    x::Union{Nothing, <:Number, <:Pair, <:VecPair, <:Dict,
             <:AbstractEstimatorValueAlgorithm,
             <:DynamicAbstractWeights, <:AbstractEstimator, <:AbstractAlgorithm},
    ::Any
) -> 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.

Returns

  • x: Input value.
    • ::Union{Nothing, <:Number, <:Pair, <:VecPair, <:Dict, <:AbstractEstimatorValueAlgorithm, <:DynamicAbstractWeights, <:AbstractEstimator, <:AbstractAlgorithm}: Returns x unchanged.

    • ::AbstractVector: Returns view(x, i).

    • ::VecScalar: Returns VecScalar(; v = view(x.v, i), s = x.s).

    • ::AbstractMatrix: Returns view(x, i, i).

    • ::AbstractVector{<:Union{<:AbstractVector, <:AbstractMatrix, <:VecScalar}}: Returns a vector of views for each element in x.

Examples

julia
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)

Related

source
julia
nothing_scalar_array_view(
    x::MedianCenteringFunction,
    _
) -> MedianCenteringFunction

Return the MedianCenteringFunction x unchanged.

Identity pass-through: centering functions are not sliced by asset index.

Related

source
julia
nothing_scalar_array_view(
    td::TimeDependent,
    i
) -> TimeDependent

Slice a TimeDependent schedule of scalar-or-array field values (warm starts, initial weights) to asset indices i.

Vector schedules slice each per-fold entry, and the default when one is set; callable schedules pass through — they see the sliced universe via their fold context's rd.

Related

source
PortfolioOptimisers.nothing_scalar_array_view_odd_order Function
julia
nothing_scalar_array_view_odd_order(::Nothing, i, j)
nothing_scalar_array_view_odd_order(x::AbstractMatrix, i, j) -> view(x, i, j)

Utility for safely viewing into possibly nothing or array values with two indices.

  • If x is nothing, returns nothing.

  • Otherwise, returns view(x, i, j).

Arguments

  • x: Input value.

  • i, j: Indices to view.

Returns

  • The corresponding view or nothing.

Examples

julia
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:
2

Related

source
PortfolioOptimisers.nothing_scalar_array_getindex Function
julia
nothing_scalar_array_getindex(
    x::Union{Nothing, <:Number, <:Pair, <:VecPair, <:Dict,
             <:AbstractEstimatorValueAlgorithm,
             <:DynamicAbstractWeights},
    ::Any
) -> x
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::AbstractMatrix, i) -> x[i, i]
nothing_scalar_array_getindex(
    x::AbstractVector{<:Union{<:AbstractVector, <:AbstractMatrix, <:VecScalar}},
    i
) -> [nothing_scalar_array_getindex(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.

Returns

  • x: Input value.
    • ::Union{Nothing, <:Number, <:Pair, <:VecPair, <:Dict, <:AbstractEstimatorValueAlgorithm, <:DynamicAbstractWeights}: Returns x unchanged.

    • ::AbstractVector: Returns x[i].

    • ::VecScalar: Returns VecScalar(; v = x.v[i], s = x.s).

    • ::AbstractVector{<:Union{<:AbstractVector, <:AbstractMatrix, <:VecScalar}}: Returns a vector of elements indexed by i.

    • ::AbstractMatrix: Returns x[i, i].

Examples

julia
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
 3

Related

source
PortfolioOptimisers.nothing_scalar_array_getindex_odd_order Function
julia
nothing_scalar_array_getindex_odd_order(::Nothing, i, j)
nothing_scalar_array_getindex_odd_order(x::AbstractMatrix, i, j) -> x[i, j]

Utility for safely indexing into possibly nothing or array values with two indices.

  • If x is nothing, returns nothing.

  • Otherwise, returns x[i, j].

Arguments

  • x: Input value.

  • i, j: Indices to access.

Returns

  • The corresponding matrix element or nothing.

Examples

julia
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)
2

Related

source
PortfolioOptimisers.fourth_moment_index_generator Function
julia
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
julia> PortfolioOptimisers.fourth_moment_index_generator(3, [1, 2])
4-element Vector{Int64}:
 1
 2
 4
 5
source

Summary 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
julia
abstract type VectorToScalarMeasure <: AbstractAlgorithm

Abstract 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.

Interfaces

In order to implement a new vector-to-scalar measure that works seamlessly with the library, subtype VectorToScalarMeasure and implement the following method:

Reduction method

  • vec_to_real_measure(measure::VectorToScalarMeasure, val::VecNum) -> Number: Reduces val to a single scalar.

Arguments

  • measure: Concrete subtype instance.

  • val: Vector of real values to reduce.

Returns

  • score::Number: Computed scalar.

Related

source
PortfolioOptimisers.Num_VecToScaM Type
julia
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

source
PortfolioOptimisers.MinValue Type
julia
struct MinValue <: VectorToScalarMeasure

Algorithm for reducing a vector of real values to its minimum.

Examples

julia
julia> PortfolioOptimisers.vec_to_real_measure(MinValue(), [1.2, 3.4, 0.7])
0.7

Related

source
PortfolioOptimisers.MeanValue Type
julia
struct MeanValue{__T_w} <: VectorToScalarMeasure

Algorithm for reducing a vector of real values to its optionally weighted mean.

Fields

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

Constructors

julia
MeanValue(;
    w::Option{<:ObsWeights} = nothing,
) -> MeanValue

Keywords correspond to the struct's fields.

Validation

  • If w is not nothing, !isempty(w).

Curried parameters

When factory is called on this type, the following @fprop-tagged fields are automatically propagated:

Examples

julia
julia> PortfolioOptimisers.vec_to_real_measure(MeanValue(), [1.2, 3.4, 0.7])
1.7666666666666666

Related

source
PortfolioOptimisers.factory Method
julia
factory(a::Union{Nothing, <:AbstractEstimator, <:AbstractAlgorithm,
                 <:AbstractResult}, args...; kwargs...) -> a

No-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.

factory and port_opt_view are the two propagation mechanisms in this library. They are duals: factory threads runtime values (prior moments, observation weights, previous portfolio weights) down through a composed struct tree; port_opt_view threads an index selection (a subset of assets or observations) down through the same tree.

Arguments

  • a: Indicates no object should be constructed.

  • args...: Arbitrary positional arguments (ignored).

  • kwargs...: Arbitrary keyword arguments (ignored).

Returns

  • a: The input unchanged.

Examples

julia
julia> factory(nothing, 1, 2; x = 3)

julia> factory(MeanValue())
MeanValue
  w ┴ nothing

Related

source
PortfolioOptimisers.MedianValue Type
julia
struct MedianValue{__T_w} <: VectorToScalarMeasure

Algorithm for reducing a vector of real values to its optionally weighted median.

Fields

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

Constructors

julia
MedianValue(;
    w::Option{<:ObsWeights} = nothing,
) -> MedianValue

Keywords correspond to the struct's fields.

Validation

  • If w is not nothing, !isempty(w).

Curried parameters

When factory is called on this type, the following @fprop-tagged fields are automatically propagated:

Examples

julia
julia> PortfolioOptimisers.vec_to_real_measure(MedianValue(), [1.2, 3.4, 0.7])
1.2

Related

source
PortfolioOptimisers.factory Method
julia
factory(a::Union{Nothing, <:AbstractEstimator, <:AbstractAlgorithm,
                 <:AbstractResult}, args...; kwargs...) -> a

No-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.

factory and port_opt_view are the two propagation mechanisms in this library. They are duals: factory threads runtime values (prior moments, observation weights, previous portfolio weights) down through a composed struct tree; port_opt_view threads an index selection (a subset of assets or observations) down through the same tree.

Arguments

  • a: Indicates no object should be constructed.

  • args...: Arbitrary positional arguments (ignored).

  • kwargs...: Arbitrary keyword arguments (ignored).

Returns

  • a: The input unchanged.

Examples

julia
julia> factory(nothing, 1, 2; x = 3)

julia> factory(MeanValue())
MeanValue
  w ┴ nothing

Related

source
PortfolioOptimisers.MaxValue Type
julia
struct MaxValue <: VectorToScalarMeasure

Algorithm for reducing a vector of real values to its maximum.

Examples

julia
julia> PortfolioOptimisers.vec_to_real_measure(MaxValue(), [1.2, 3.4, 0.7])
3.4

Related

source
PortfolioOptimisers.StdValue Type
julia
struct StdValue{__T_w, __T_corrected} <: VectorToScalarMeasure

Algorithm for reducing a vector of real values to its optionally weighted standard deviation.

Fields

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

  • corrected: Whether to apply Bessel's correction.

Constructors

julia
StdValue(;
    w::Option{<:ObsWeights} = nothing,
    corrected::Bool = true,
) -> StdValue

Keywords correspond to the struct's fields.

Validation

  • If w is not nothing, !isempty(w).

Curried parameters

When factory is called on this type, the following @fprop-tagged fields are automatically propagated:

Examples

julia
julia> PortfolioOptimisers.vec_to_real_measure(StdValue(), [1.2, 3.4, 0.7])
1.4364307617610164

Related

source
PortfolioOptimisers.factory Method
julia
factory(a::Union{Nothing, <:AbstractEstimator, <:AbstractAlgorithm,
                 <:AbstractResult}, args...; kwargs...) -> a

No-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.

factory and port_opt_view are the two propagation mechanisms in this library. They are duals: factory threads runtime values (prior moments, observation weights, previous portfolio weights) down through a composed struct tree; port_opt_view threads an index selection (a subset of assets or observations) down through the same tree.

Arguments

  • a: Indicates no object should be constructed.

  • args...: Arbitrary positional arguments (ignored).

  • kwargs...: Arbitrary keyword arguments (ignored).

Returns

  • a: The input unchanged.

Examples

julia
julia> factory(nothing, 1, 2; x = 3)

julia> factory(MeanValue())
MeanValue
  w ┴ nothing

Related

source
PortfolioOptimisers.VarValue Type
julia
struct VarValue{__T_w, __T_corrected} <: VectorToScalarMeasure

Algorithm for reducing a vector of real values to its optionally weighted variance.

Fields

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

  • corrected: Whether to apply Bessel's correction.

Constructors

julia
VarValue(;
    w::Option{<:ObsWeights} = nothing,
    corrected::Bool = true,
) -> VarValue

Keywords correspond to the struct's fields.

Validation

  • If w is not nothing, !isempty(w).

Curried parameters

When factory is called on this type, the following @fprop-tagged fields are automatically propagated:

Examples

julia
julia> PortfolioOptimisers.vec_to_real_measure(VarValue(), [1.2, 3.4, 0.7])
2.0633333333333335

Related

source
PortfolioOptimisers.factory Method
julia
factory(a::Union{Nothing, <:AbstractEstimator, <:AbstractAlgorithm,
                 <:AbstractResult}, args...; kwargs...) -> a

No-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.

factory and port_opt_view are the two propagation mechanisms in this library. They are duals: factory threads runtime values (prior moments, observation weights, previous portfolio weights) down through a composed struct tree; port_opt_view threads an index selection (a subset of assets or observations) down through the same tree.

Arguments

  • a: Indicates no object should be constructed.

  • args...: Arbitrary positional arguments (ignored).

  • kwargs...: Arbitrary keyword arguments (ignored).

Returns

  • a: The input unchanged.

Examples

julia
julia> factory(nothing, 1, 2; x = 3)

julia> factory(MeanValue())
MeanValue
  w ┴ nothing

Related

source
PortfolioOptimisers.SumValue Type
julia
struct SumValue <: VectorToScalarMeasure

Algorithm for reducing a vector of real values to its sum.

Examples

julia
julia> PortfolioOptimisers.vec_to_real_measure(SumValue(), [1.2, 3.4, 0.7])
5.3

Related

source
PortfolioOptimisers.ProdValue Type
julia
struct ProdValue <: VectorToScalarMeasure

Algorithm for reducing a vector of real values to its product.

Examples

julia
julia> PortfolioOptimisers.vec_to_real_measure(ProdValue(), [1.2, 3.4, 0.7])
2.856

Related

source
PortfolioOptimisers.ModeValue Type
julia
struct ModeValue <: VectorToScalarMeasure

Algorithm for reducing a vector of real values to its mode.

Examples

julia
julia> PortfolioOptimisers.vec_to_real_measure(ModeValue(), [1.2, 3.4, 0.7, 1.2])
1.2

Related

source
PortfolioOptimisers.StandardisedValue Type
julia
struct StandardisedValue{__T_mv, __T_sv} <: VectorToScalarMeasure

Algorithm 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

julia
StandardisedValue(;
    mv::MeanValue = MeanValue(),
    sv::StdValue = StdValue(),
) -> StandardisedValue

Keywords correspond to the struct's fields.

Curried parameters

When factory is called on this type, the following @fprop-tagged fields are automatically propagated:

  • mv: Recursively updated via factory.

  • sv: Recursively updated via factory.

Examples

julia
julia> PortfolioOptimisers.vec_to_real_measure(StandardisedValue(), [1.2, 3.4, 0.7])
1.2299003291330186

Related

source
PortfolioOptimisers.factory Method
julia
factory(a::Union{Nothing, <:AbstractEstimator, <:AbstractAlgorithm,
                 <:AbstractResult}, args...; kwargs...) -> a

No-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.

factory and port_opt_view are the two propagation mechanisms in this library. They are duals: factory threads runtime values (prior moments, observation weights, previous portfolio weights) down through a composed struct tree; port_opt_view threads an index selection (a subset of assets or observations) down through the same tree.

Arguments

  • a: Indicates no object should be constructed.

  • args...: Arbitrary positional arguments (ignored).

  • kwargs...: Arbitrary keyword arguments (ignored).

Returns

  • a: The input unchanged.

Examples

julia
julia> factory(nothing, 1, 2; x = 3)

julia> factory(MeanValue())
MeanValue
  w ┴ nothing

Related

source
PortfolioOptimisers.vec_to_real_measure Function
julia
vec_to_real_measure(measure::Num_VecToScaM, val::VecNum) -> Number

Reduce a vector of real values to a single real value using a specified measure.

vec_to_real_measure applies a reduction algorithm (such as minimum, mean, median, or maximum) to a vector of real numbers, as specified by the concrete subtype of VectorToScalarMeasure. This is used in constraint generation and centrality-based portfolio constraints to aggregate asset-level metrics.

Arguments

  • measure: An instance of a concrete subtype of VectorToScalarMeasure, or the predefined value to return.

  • val: A vector of real values to be reduced (ignored if measure is a Number).

Returns

  • score::Number: Computed value according to measure.

Examples

julia
julia> PortfolioOptimisers.vec_to_real_measure(MaxValue(), [1.2, 3.4, 0.7])
3.4

julia> PortfolioOptimisers.vec_to_real_measure(0.9, [1.2, 3.4, 0.7])
0.9

Related

source