Naive optimisation
PortfolioOptimisers.NaiveOptimisationResult — Type
struct NaiveOptimisationResult{__T_pr, __T_wb, __T_retcode, __T_w, __T_imsk, __T_fb} <: NonJuMPOptimisationResultResult type for naive portfolio optimisation estimators.
Fields
pr: Prior result.
wb: Weight bounds.
retcode: Optimisation return code.
w: Portfolio weights vectorassets × 1.
imsk: The Investable Mask the optimisation reduced on:trueat every asset whose prior moments were finite. It isnothingwhen every asset was investable, and that sentinel is what skips both the reduction and the expansion.investable_maskderives it once from the full-universe prior result, and the result carries it, because the reduced prior can no longer yield it.
fb: The fallback chain that answered this result: the(estimator, result)pair of every attemptoptimisemade before this one, in the order they ran, ornothingwhen the estimator it was asked of answered (seeFbChain).
Constructors
NaiveOptimisationResult(; pr::Option{<:Pr_RR}, wb::Option{<:WeightBounds}, retcode::OptimisationReturnCode, w::Option{<:VecNum}, imsk::Option{<:BitVector} = nothing, fb::Option{<:OptE_Opt_FbChain}) -> NaiveOptimisationResultKeywords correspond to the struct's fields. The keyword constructor expands w onto the full asset universe through expand_investable_weights, which is the one door _optimise exits through. The positional constructor never expands.
Examples
julia> NaiveOptimisationResult(; pr = nothing, wb = nothing, retcode = OptimisationSuccess(), w = [0.5, 0.5], fb = nothing)NaiveOptimisationResult pr ┼ nothing wb ┼ nothing retcode ┼ OptimisationSuccess │ res ┴ nothing w ┼ Vector{Float64}: [0.5, 0.5] imsk ┼ nothing fb ┴ nothingRelated
PortfolioOptimisers.InverseVolatility — Type
struct InverseVolatility{__T_pe, __T_wb, __T_sets, __T_wf, __T_fb, __T_sq, __T_brt, __T_strict, __T_cache} <: NaiveOptimisationEstimatorAllocates each asset a weight inversely proportional to its volatility, or to its variance when sq = true.
The volatilities come from the diagonal of the covariance matrix the prior estimator pe returns, so every choice inside pe reaches the result. This is the naive risk parity allocation that HierarchicalRiskParity applies inside a cluster.
Mathematical definition
\[\begin{align} w_i &= \frac{\sigma_i^{-1}}{\sum_{j=1}^N \sigma_j^{-1}} \quad \textrm{when } \texttt{sq = false}\,,\\ w_i &= \frac{\sigma_i^{-2}}{\sum_{j=1}^N \sigma_j^{-2}} \quad \textrm{when } \texttt{sq = true}\,. \end{align}\]
Where:
- $w_i$: Portfolio weight of asset $i$ before the weight bounds are applied.
- $\sigma_i^2$: Variance of asset $i$, the $i$-th diagonal entry of the prior covariance matrix.
- $\sigma_i$: Standard deviation of asset $i$.
- $N$: Number of assets.
The weight finaliser wf then imposes the resolved weight bounds on $\boldsymbol{w}$, so the returned weights equal the expression above only when no bound binds.
Fields
pe: Prior estimator.
wb: Weight bounds.
sets: Sets used to map estimator values to assets.
wf: Weight finaliser.
fb: Fallback result or estimator.
sq: Whether to use variance instead of volatility in the inverse weighting.
brt: Whether to use bootstrap returns.
strict: Whether to strictly enforce weight bounds.
cache: OptionalReturnsBufferState, the fold context of the online step. It isnothinguntilpartial_fit!writes one, andoptimise(opt)with no returns reads it. The returns themselves are carried by the prior, which owns the rows once; this holds every other column of the carrier and the context pinned at the first step.factorycarries it unchanged andport_opt_viewslices it to the selected assets.
Constructors
InverseVolatility(; pe::Onl{<:TD{<:PrE_Pr}} = EmpiricalPrior(), wb::TD_Option{<:WbE_Wb} = WeightBounds(), sets::TD_Option{<:UniverseSets} = nothing, wf::TD{<:WeightFinaliser} = IterativeWeightFinaliser(), fb::TDO_Option{<:OptE_Opt} = nothing, sq::Bool = false, brt::Bool = false, strict::Bool = false, cache::Option{<:ReturnsBufferState} = nothing) -> InverseVolatilityKeywords correspond to the struct's fields. Fields typed TD, TD_Option or TDO_Option may hold a TimeDependent per-fold schedule instead of a static value: the prior estimator, weight bounds, asset sets, weight finaliser and fallback are problem definition, so a cross-validation fold loop resolves them per fold, and a fold-less optimise runs with each at its static default. sq, brt and strict are execution control and stay static.
Validation
- If
wbis aWeightBoundsEstimator:!isnothing(sets). fbschedules:bind !== :nearest.
Propagated parameters
When factory is called on this type, the following @fprop-tagged fields are automatically propagated:
fb: Recursively updated viafactory.
View parameters
When port_opt_view is called on this type, the following @vprop-tagged fields are automatically subset to the selected indices:
pe: Recursively viewed viaport_opt_view.wb: Recursively viewed viaport_opt_view.sets: Sliced to the selected indices viaport_opt_view.
Examples
julia> InverseVolatility()InverseVolatility pe ┼ EmpiricalPrior │ ce ┼ PortfolioOptimisersCovariance │ │ ce ┼ Covariance │ │ │ me ┼ SimpleExpectedReturns │ │ │ │ w ┴ nothing │ │ │ ce ┼ GeneralCovariance │ │ │ │ ce ┼ StatsBase.SimpleCovariance: StatsBase.SimpleCovariance(true) │ │ │ │ w ┴ nothing │ │ │ alg ┼ FullMoment() │ │ │ w ┴ nothing │ │ mp ┼ MatrixProcessing │ │ │ pdm ┼ Posdef │ │ │ │ alg ┼ UnionAll: NearestCorrelationMatrix.Newton │ │ │ │ kwargs ┴ @NamedTuple{}: NamedTuple() │ │ │ dn ┼ nothing │ │ │ dt ┼ nothing │ │ │ alg ┼ nothing │ │ │ order ┴ NTuple{4, Symbol}: (:pdm, :dn, :dt, :alg) │ me ┼ SimpleExpectedReturns │ │ w ┴ nothing │ horizon ┼ nothing │ fill_limit ┴ nothing wb ┼ WeightBounds │ lb ┼ Float64: 0.0 │ ub ┴ Float64: 1.0 sets ┼ nothing wf ┼ IterativeWeightFinaliser │ iter ┴ Int64: 100 fb ┼ nothing sq ┼ Bool: false brt ┼ Bool: false strict ┴ Bool: falseRelated
optimiseNaiveOptimisationResultNaiveOptimisationEstimatorEqualWeightedRandomWeightedfactoryport_opt_view
References
- [5] D. Cajas. Advanced Portfolio Optimization: A Cutting-edge Quantitative Approach (Springer Nature Switzerland, 2025). Section 12.1.3, footnote 5.
PortfolioOptimisers.EqualWeighted — Type
struct EqualWeighted{__T_wb, __T_sets, __T_wf, __T_fb, __T_strict, __T_cache} <: NaiveOptimisationEstimatorAllocates the same weight to every asset in the universe.
The asset count comes from rd.X, so this optimiser reads no prior and no covariance matrix.
$N$ is the size of the Coverage Universe of the window, not of the full asset universe. An asset is in it when its return is finite and the active mask of the AssetPanel is true at every row of the window, so an asset that is not yet listed, is delisted, or carries a stale finite price during an inactive spell, weights nothing and holds a zero. The result carries that universe as its imsk. An all-dead window throws an IsEmptyError.
Mathematical definition
\[\begin{align} w_i &= \frac{1}{N} \quad \forall i\,. \end{align}\]
Where:
- $w_i$: Portfolio weight of asset $i$ before the weight bounds are applied.
- $N$: Number of assets.
The weight finaliser wf then imposes the resolved weight bounds on $\boldsymbol{w}$, so the returned weights equal $1/N$ only when no bound binds.
Fields
wb: Weight bounds.
sets: Sets used to map estimator values to assets.
wf: Weight finaliser.
fb: Fallback result or estimator.
strict: Whether to strictly enforce weight bounds.
cache: OptionalReturnsBufferState, the fold context of the online step. It isnothinguntilpartial_fit!writes one, andoptimise(opt)with no returns reads it. This head holds no prior, so it is the bottom of the chain and its state carries the returns themselves, beside every other column of the carrier and the context pinned at the first step.factorycarries it unchanged andport_opt_viewslices it to the selected assets.
Constructors
EqualWeighted(; wb::TD_Option{<:WbE_Wb} = WeightBounds(), sets::TD_Option{<:UniverseSets} = nothing, wf::TD{<:WeightFinaliser} = IterativeWeightFinaliser(), fb::TDO_Option{<:OptE_Opt} = nothing, strict::Bool = false, cache::Option{<:ReturnsBufferState} = nothing) -> EqualWeightedKeywords correspond to the struct's fields. Fields typed TD, TD_Option or TDO_Option may hold a TimeDependent per-fold schedule instead of a static value: the weight bounds, asset sets, weight finaliser and fallback are problem definition, so a cross-validation fold loop resolves them per fold, and a fold-less optimise runs with each at its static default. strict is execution control and stays static.
Validation
- If
wbis aWeightBoundsEstimator:!isnothing(sets). fbschedules:bind !== :nearest.
Propagated parameters
When factory is called on this type, the following @fprop-tagged fields are automatically propagated:
fb: Recursively updated viafactory.
View parameters
When port_opt_view is called on this type, the following @vprop-tagged fields are automatically subset to the selected indices:
wb: Recursively viewed viaport_opt_view.sets: Sliced to the selected indices viaport_opt_view.
Examples
julia> EqualWeighted()EqualWeighted wb ┼ WeightBounds │ lb ┼ Float64: 0.0 │ ub ┴ Float64: 1.0 sets ┼ nothing wf ┼ IterativeWeightFinaliser │ iter ┴ Int64: 100 fb ┼ nothing strict ┴ Bool: falseRelated
PortfolioOptimisers.RandomWeighted — Type
struct RandomWeighted{__T_alpha, __T_rng, __T_seed, __T_wb, __T_sets, __T_wf, __T_fb, __T_strict, __T_cache} <: NaiveOptimisationEstimatorDraws portfolio weights at random from a Dirichlet distribution with concentration parameter alpha.
Use it for simulation, benchmarking, or stress testing. A scalar alpha draws from the symmetric Dirichlet distribution over $N$ assets; a vector alpha must be one entry per asset.
$N$ is the size of the Coverage Universe of the window, not of the full asset universe. An asset is in it when its return is finite and the active mask of the AssetPanel is true at every row of the window, so an asset that is not yet listed, is delisted, or carries a stale finite price during an inactive spell, weights nothing and holds a zero. A vector alpha is still stated over the full universe, and is sliced to the Coverage Universe. The result carries that universe as its imsk. An all-dead window throws an IsEmptyError.
Mathematical definition
\[\begin{align} \boldsymbol{w} &\sim \mathrm{Dirichlet}(\boldsymbol{\alpha})\,. \end{align}\]
Where:
- $\boldsymbol{w}$: Portfolio weight vector before the weight bounds are applied. A Dirichlet draw is non-negative and sums to one.
- $\boldsymbol{\alpha}$: Concentration parameter, one entry per asset. A larger value concentrates the distribution near equal weights.
The weight finaliser wf then imposes the resolved weight bounds on $\boldsymbol{w}$, which by default are absent for this optimiser.
Fields
alpha: Dirichlet concentration parameter.
rng: Random number generator.
seed: Seed for the random number generator.
wb: Weight bounds.
sets: Sets used to map estimator values to assets.
wf: Weight finaliser.
fb: Fallback result or estimator.
strict: Whether to strictly enforce weight bounds.
cache: OptionalReturnsBufferState, the fold context of the online step. It isnothinguntilpartial_fit!writes one, andoptimise(opt)with no returns reads it. This head holds no prior, so it is the bottom of the chain and its state carries the returns themselves, beside every other column of the carrier and the context pinned at the first step.factorycarries it unchanged andport_opt_viewslices it to the selected assets.
Constructors
RandomWeighted(; alpha::Num_VecNum = 1, rng::Random.AbstractRNG = Random.default_rng(), seed::Option{<:Integer} = nothing, wb::TD_Option{<:WbE_Wb} = nothing, sets::TD_Option{<:UniverseSets} = nothing, wf::TD{<:WeightFinaliser} = IterativeWeightFinaliser(), fb::TDO_Option{<:OptE_Opt} = nothing, strict::Bool = false, cache::Option{<:ReturnsBufferState} = nothing) -> RandomWeightedKeywords correspond to the struct's fields. Fields typed TD, TD_Option or TDO_Option may hold a TimeDependent per-fold schedule instead of a static value: the weight bounds, asset sets, weight finaliser and fallback are problem definition, so a cross-validation fold loop resolves them per fold, and a fold-less optimise runs with each at its static default (nothing for wb, sets and fb). rng, seed and strict are execution control and stay static.
Validation
alpha: non-empty, and every element is positive and finite.- If
wbis aWeightBoundsEstimator:!isnothing(sets). fbschedules:bind !== :nearest.
Propagated parameters
When factory is called on this type, the following @fprop-tagged fields are automatically propagated:
fb: Recursively updated viafactory.
View parameters
When port_opt_view is called on this type, the following @vprop-tagged fields are automatically subset to the selected indices:
alpha: Sliced to the selected indices viaport_opt_view.wb: Recursively viewed viaport_opt_view.sets: Sliced to the selected indices viaport_opt_view.
Examples
julia> RandomWeighted()RandomWeighted alpha ┼ Int64: 1 rng ┼ Random.TaskLocalRNG: Random.TaskLocalRNG() seed ┼ nothing wb ┼ nothing sets ┼ nothing wf ┼ IterativeWeightFinaliser │ iter ┴ Int64: 100 fb ┼ nothing strict ┴ Bool: falseRelated
PortfolioOptimisers.PreviousWeights — Type
struct PreviousWeights{__T_w, __T_fb} <: NaiveOptimisationEstimatorHolds the weights it was handed, and solves nothing.
The hold-only head. Its weights are the previous fold's, threaded into w by the fold loop through factory exactly as they reach a TurnoverEstimator, and it returns them verbatim on the full asset universe: no prior, no Coverage Universe, no weight bounds, so a hold is never rewritten. Its one use is as the fallback fb of an optimiser inside a walk-forward, where a failed solve then holds the book instead of writing NaN weights and losing the fold; a weight on an asset that left the panel is still held, and its returns are zeroed as a Held Gap. It is also a primary: PreviousWeights(; w = w) is a walk-forward that holds w on every fold. It refuses nothing at construction and fails at solve time when w is nothing, which is what fold 1 of a walk-forward, and a fold-less optimise with no w, hand it.
needs_previous_weights is true, so an optimiser that carries it as a fallback runs sequentially, and the loop threads the previous weights into it.
Fields
w: Weights to hold, ornothingbefore the fold loop threads any.
fb: Fallback result or estimator.
Constructors
PreviousWeights(; w::Option{<:VecNum} = nothing, fb::TDO_Option{<:OptE_Opt} = nothing) -> PreviousWeightsKeywords correspond to the struct's fields. fb may hold a TimeDependent per-fold schedule.
Validation
w:all(isfinite, w), else aDomainErroris raised.fbschedules:bind !== :nearest.
Propagated parameters
When factory is called on this type, the following @fprop-tagged fields are automatically propagated:
fb: Recursively updated viafactory.
Examples
julia> PreviousWeights()PreviousWeights w ┼ nothing fb ┴ nothingRelated
optimisefactory(pw::PreviousWeights, w::VecNum)NaiveOptimisationResultNaiveOptimisationEstimatorneeds_previous_weightsTurnoverEstimator: Receives the previous weights through the samefactorypass.fold_loop: Threads the previous fold's weights intow.
PortfolioOptimisers.factory — Method
factory(a::Union{Nothing, <:AbstractEstimator, <:AbstractAlgorithm,
<:AbstractResult}, args...; kwargs...) -> a
factory(a::AbstractVector{<:Union{Nothing, <:AbstractEstimator, <:AbstractAlgorithm,
<:AbstractResult}}, args...; kwargs...) -> VectorNo-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.
The vector method is the one forwarding contract for every vector-valued propagation field: it applies factory to each element and forwards args... and kwargs... unchanged, so a family that admits a vector of estimators, algorithms, or results needs no method of its own. A family that needs more than the forward, such as a concrete element type (concrete_typed_array_if_abstract), defines its own more specific method.
Algorithm
The scalar method:
- Return
aunchanged, and dropargs...andkwargs.... This method is the leaf of the recursion, and it is what makes an untagged type safe to call the verb on.
The vector method:
- For each element
aiofa, callfactoryonai, and forwardargs...andkwargs...unchanged. - Collect the results into a new vector, in the order of
a, and return it.
A @propagatable struct with at least one @fprop- or @wprop-tagged field carries a generated method that dominates the scalar method. That method rebuilds the struct with its keyword constructor, sending each @fprop field through factory_child and each @wprop field through _wprop.
Arguments
a: Indicates no object should be constructed, or a vector whose elements are rebuilt one by one.args...: Arbitrary positional arguments (ignored by the scalar method, forwarded by the vector method).kwargs...: Arbitrary keyword arguments (ignored by the scalar method, forwarded by the vector method).
Returns
a: The input unchanged.v::Vector: The element-wise rebuilds, for the vector method.
Examples
julia> factory(nothing, 1, 2; x = 3)julia> factory(MeanValue())MeanValue w ┴ nothingRelated
factory(res::NonFiniteAllocationOptimisationResult, fb::Option{<:OptE_Opt_FbChain})Rebuild a continuous optimisation result with an updated fallback record fb.
Every optimisation result carries fb as its last field, so the generic rebuild copies all fields unchanged except the trailing fb. Concrete result types may override this method when rebuilding requires more than swapping fb. optimise is the one caller, and it hands in the FbChain it walked.
Related
factory(
opt::Union{NonFiniteAllocationOptimisationEstimator, NonFiniteAllocationOptimisationResult},
_
) -> RandomWeighted{_A, var"#s185", _B, _C, _D, _E, _F, Bool} where {_A, var"#s185"<:AbstractRNG, _B, _C, _D, _E, _F}
Return opt unchanged.
Default pass-through factory for optimisation estimators and results. Overridden for estimators that carry parameters requiring update at each optimisation step.
Related
PortfolioOptimisers.optimise — Method
optimise(iv::InverseVolatility{<:Any, <:Any, <:Any, <:Any, Nothing},
rd::ReturnsResult; dims::Int = 1, kwargs...) -> NaiveOptimisationResultRun the inverse volatility portfolio optimisation.
Arguments
iv: The inverse volatility optimiser to use.rd: The returns result to use. Ifisa(iv.pe, AbstractPriorResult),rdis not necessary.dims: The dimension along which observations advance in time.kwargs: Additional keyword arguments passed to the optimisation function.
Validation
- No field in the tree of
ivholds anOnline. AnArgumentErrornaming the field is thrown otherwise, throughassert_batch_entry: a plainoptimiseis a batch fit, and a wrapper resolves only at the warm-up of the fold loop's online arm.
PortfolioOptimisers.optimise — Method
optimise(ew::EqualWeighted{<:Any, <:Any, <:Any, Nothing},
rd::ReturnsResult; dims::Int = 1, kwargs...) -> NaiveOptimisationResultRun the equal-weighted portfolio optimisation.
Arguments
ew: The equal-weighted optimiser to use.rd: The returns result to use. Its returns matrix and its Asset Panel give the Coverage Universe of the window, which is the universe the weights are spread over.dims: Must be1. AReturnsResultis always observations × assets, sodims == 2throwsConflictingArgumentError; build one in this layout withprices_to_returns.kwargs: Additional keyword arguments passed to the optimisation function.
PortfolioOptimisers.optimise — Method
optimise(rw::RandomWeighted{<:Any, <:Any, <:Any, <:Any, <:Any, <:Any, Nothing},
rd::ReturnsResult; dims::Int = 1, kwargs...) -> NaiveOptimisationResultRun the random-weighted portfolio optimisation.
Arguments
rw: The random-weighted optimiser to use.rd: The returns result to use. Its returns matrix and its Asset Panel give the Coverage Universe of the window, which is the universe the draw is taken over.dims: Must be1. AReturnsResultis always observations × assets, sodims == 2throwsConflictingArgumentError; build one in this layout withprices_to_returns.kwargs: Additional keyword arguments passed to the optimisation function.
PortfolioOptimisers.factory — Method
factory(pw::PreviousWeights, w::VecNum) -> PreviousWeightsThread the previous fold's weights into the hold-only head, and on into its fallback.
Arguments
pw: The head.w: The weights the fold loop threads.
Returns
PreviousWeights: The head holdingw, withfbpropagated throughfactory.
Examples
julia> PortfolioOptimisers.factory(PreviousWeights(), [0.25, 0.75])PreviousWeights w ┼ Vector{Float64}: [0.25, 0.75] fb ┴ nothingRelated
PortfolioOptimisers.optimise — Function
optimise(pw::PreviousWeights{<:Any, Nothing}, rd::ReturnsResult = ReturnsResult();
kwargs...) -> NaiveOptimisationResultHold the weights the head carries.
Arguments
pw: The hold-only head.rd: The returns result to use. Read for nothing, and recorded on the result aspr.kwargs: Additional keyword arguments, ignored.
PortfolioOptimisers._optimise — Method
_optimise(
iv::InverseVolatility;
...
) -> NaiveOptimisationResult{__T_pr, __T_wb, __T_retcode, __T_w, __T_imsk, Nothing} where {__T_pr, __T_wb, __T_retcode, __T_w, __T_imsk}
_optimise(
iv::InverseVolatility,
rd::ReturnsResult;
dims,
kwargs...
) -> NaiveOptimisationResult{__T_pr, __T_wb, __T_retcode, __T_w, __T_imsk, Nothing} where {__T_pr, __T_wb, __T_retcode, __T_w, __T_imsk}
Run the inverse volatility portfolio optimisation.
Internal dispatch called by optimise. Computes covariance via the prior estimator, reduces the prior, the optimiser and the returns data to the Investable Mask with investable_reduction, assigns weights inversely proportional to volatility (or variance when iv.sq = true), then applies weight bounds. NaiveOptimisationResult expands the weights back onto the full asset universe.
Related
PortfolioOptimisers._optimise — Method
_optimise(
ew::EqualWeighted,
rd::ReturnsResult;
dims,
kwargs...
) -> NaiveOptimisationResult{__T_pr, __T_wb, __T_retcode, __T_w, __T_imsk, Nothing} where {__T_pr, __T_wb, __T_retcode, __T_w, __T_imsk}
Run the equal-weighted portfolio optimisation.
Internal dispatch called by optimise. Reduces the optimiser and the returns data to the Coverage Universe of the window with coverage_reduction, assigns equal weights to the assets it keeps, then applies weight bounds. NaiveOptimisationResult expands the weights back onto the full asset universe.
This head fits no prior, so no Prior Result yields an Investable Mask for it. The Coverage Universe is the mask it derives instead: an asset is kept when its return is finite and the active mask of the AssetPanel is true at every row of the window. A stale finite price during an inactive spell weights nothing, and an asset outside the mask holds a zero. The result carries the mask as imsk, so a reader of a walk-forward has the same idiom here as in every other family. An all-dead window throws an IsEmptyError.
Related
PortfolioOptimisers._optimise — Method
_optimise(
rw::RandomWeighted,
rd::ReturnsResult;
dims,
kwargs...
) -> NaiveOptimisationResult{__T_pr, __T_wb, __T_retcode, __T_w, __T_imsk, Nothing} where {__T_pr, __T_wb, __T_retcode, __T_w, __T_imsk}
Run the random-weighted portfolio optimisation.
Internal dispatch called by optimise. Reduces the optimiser and the returns data to the Coverage Universe of the window with coverage_reduction, draws weights over the assets it keeps from a Dirichlet distribution parameterised by rw.alpha, then applies weight bounds. NaiveOptimisationResult expands the weights back onto the full asset universe.
This head fits no prior, so no Prior Result yields an Investable Mask for it. The Coverage Universe is the mask it derives instead: an asset is kept when its return is finite and the active mask of the AssetPanel is true at every row of the window. A stale finite price during an inactive spell weights nothing, and an asset outside the mask holds a zero. The result carries the mask as imsk, so a reader of a walk-forward has the same idiom here as in every other family. An all-dead window throws an IsEmptyError.
A vector alpha is one concentration per asset of the full universe, because that is the universe the caller states it over. Its length is therefore checked against the full width, before the reduction, and port_opt_view then slices it to the Coverage Universe with the rest of the estimator.
Related
PortfolioOptimisers._optimise — Function
_optimise(
pw::PreviousWeights;
...
) -> NaiveOptimisationResult{ReturnsResult{Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing}, Nothing, __T_retcode, __T_w, Nothing, Nothing} where {__T_retcode, __T_w}
_optimise(
pw::PreviousWeights,
rd::ReturnsResult;
kwargs...
) -> NaiveOptimisationResult{__T_pr, Nothing, __T_retcode, __T_w, Nothing, Nothing} where {__T_pr, __T_retcode, __T_w}
Return the held weights as a result, or a failure when there are none.
Internal dispatch called by optimise. The head reads nothing off rd but its width: the weights are returned verbatim, on the universe they were threaded on, with imsk = nothing and no weight bounds. A head whose w is nothing answers an OptimisationFailure naming the missing weights, so a fallback chain that reaches it walks on, and its weights are a NaN vector of the carrier's width — what every failed solve carries, so a fold reads the failure as it reads any other — or nothing when the carrier has no returns to take a width from.
Algorithm
- With
wset, give aNaiveOptimisationResultcarryingwand anOptimisationSuccess. - With
wunset, give one carrying anOptimisationFailureandNaNweights, one per column ofrd.X, ornothingwhenrd.Xisnothing.
Related
PortfolioOptimisers.needs_previous_weights — Method
needs_previous_weights(
opt::NaiveOptimisationEstimator
) -> Bool
Return whether the naive optimiser's fallback estimator requires previous portfolio weights.
Related
References
- [5]
- D. Cajas. Advanced Portfolio Optimization: A Cutting-edge Quantitative Approach (Springer Nature Switzerland, 2025).