Entropy Pooling: private API
PortfolioOptimisers.StagedEP — Type
const StagedEP = Union{<:H1_EntropyPooling, <:H2_EntropyPooling}Alias for a union of staged entropy pooling algorithm types.
Related
PortfolioOptimisers.NonCVaREP — Type
const NonCVaREP = Union{<:OptimEntropyPooling, <:JuMPEntropyPooling}Alias for a union of non-CVaR entropy pooling algorithm types.
Related
PortfolioOptimisers.AbstractEntropyPoolingOptimiser — Type
abstract type AbstractEntropyPoolingOptimiser <: AbstractEstimatorAbstract supertype for the optimisers that solve an entropy pooling problem.
A subtype names the numerical route to the posterior probabilities: which package drives the solve, and whether it solves the dual or the primal.
Related
PortfolioOptimisers.AbstractEntropyPoolingAlgorithm — Type
abstract type AbstractEntropyPoolingAlgorithm <: AbstractAlgorithmAbstract supertype for the algorithms that decide how the views of an entropy pooling problem reach the optimiser.
A subtype states whether every view is enforced in one optimisation or in stages, from the lower moments to the higher ones, and which probabilities each stage starts from.
Related
H0_EntropyPoolingH1_EntropyPoolingH2_EntropyPoolingStagedEPEntropyPoolingPriorMeucciEntropyPoolingPrior
References
PortfolioOptimisers.AbstractEntropyPoolingOptAlgorithm — Type
abstract type AbstractEntropyPoolingOptAlgorithm <: AbstractAlgorithmAbstract supertype for the algorithms that decide how an entropy pooling optimiser evaluates its objective.
Every subtype minimises the same Kullback-Leibler divergence of the posterior probabilities from the prior ones. They differ only in the arithmetic that evaluates it, so they answer the same problem with the same posterior.
Related
AbstractEntropyPoolingAlgorithmLogEntropyPoolingExpEntropyPoolingOptimEntropyPoolingJuMPEntropyPooling
References
- [78] A. Meucci. Fully flexible views: theory and practice. Risk 21, 97–102 (2008).
PortfolioOptimisers.AbstractEntropyPoolingViewEstimator — Type
abstract type AbstractEntropyPoolingViewEstimator <: AbstractEstimatorAbstract supertype for the estimators that carry a group of entropy pooling views together with the settings those views are read under.
A significance level is a property of a view, not of the estimator that holds it: the value at risk at 1% and at 10% are different statistics of the same series. An estimator of this family pairs a group of view equations with the settings they are read under, so one entropy pooling estimator can hold views stated at several levels.
Related
PortfolioOptimisers.VV_VecVV — Type
const VV_VecVV = Union{<:ValueatRiskView, <:AbstractVector{<:ValueatRiskView}}Alias for the shapes a var_views field accepts: one ValueatRiskView, or a vector of them read under their own significance levels.
Related
PortfolioOptimisers.AbstractEntropyPoolingViewFormulation — Type
abstract type AbstractEntropyPoolingViewFormulation <: AbstractAlgorithmAbstract supertype for the formulations that express a tail view inside an entropy pooling problem.
A tail view constrains a quantile-based risk measure of the posterior distribution. Unlike a mean, variance or correlation view, it is not a linear function of the posterior probabilities, so each measure admits more than one way of writing it as a solvable program. The concrete subtypes name those ways.
Related
AbstractConditionalValueatRiskViewFormulationAbstractEntropicValueatRiskViewFormulationEntropyPoolingPrior
References
- [1] D. Cajas. Entropy Pooling with CVaR and EVaR Views. Available at SSRN 7120258 (2026).
PortfolioOptimisers.AbstractConditionalValueatRiskViewFormulation — Type
abstract type AbstractConditionalValueatRiskViewFormulation <: AbstractEntropyPoolingViewFormulationAbstract supertype for the formulations of a conditional value-at-risk view.
Related
AbstractEntropyPoolingViewFormulationLinearConditionalValueatRiskViewIntegerConditionalValueatRiskViewSequentialConditionalValueatRiskView
References
- [1] D. Cajas. Entropy Pooling with CVaR and EVaR Views. Available at SSRN 7120258 (2026).
PortfolioOptimisers.AbstractEntropicValueatRiskViewFormulation — Type
abstract type AbstractEntropicValueatRiskViewFormulation <: AbstractEntropyPoolingViewFormulationAbstract supertype for the formulations of an entropic value-at-risk view.
Related
AbstractEntropyPoolingViewFormulationConicEntropicValueatRiskViewGridEntropicValueatRiskViewSequentialEntropicValueatRiskView
References
- [1] D. Cajas. Entropy Pooling with CVaR and EVaR Views. Available at SSRN 7120258 (2026).
PortfolioOptimisers.AbstractRelativisticValueatRiskViewFormulation — Type
abstract type AbstractRelativisticValueatRiskViewFormulation <: AbstractEntropyPoolingViewFormulationAbstract supertype for the formulations of a relativistic value-at-risk view.
Related
AbstractEntropyPoolingViewFormulationConicRelativisticValueatRiskViewGridRelativisticValueatRiskViewSequentialRelativisticValueatRiskView
References
- [2] D. Cajas. Entropy Pooling with Relativistic Value at Risk Views. Available at SSRN 7329718 (2026).
PortfolioOptimisers.CVaRVF_VecCVaRVF — Type
const CVaRVF_VecCVaRVF = Union{<:AbstractConditionalValueatRiskViewFormulation,
<:AbstractVector{<:AbstractConditionalValueatRiskViewFormulation}}Alias for a union of a single conditional value-at-risk view formulation or a vector of them.
Related
PortfolioOptimisers.EVaRVF_VecEVaRVF — Type
const EVaRVF_VecEVaRVF = Union{<:AbstractEntropicValueatRiskViewFormulation,
<:AbstractVector{<:AbstractEntropicValueatRiskViewFormulation}}Alias for a union of a single entropic value-at-risk view formulation or a vector of them.
Related
PortfolioOptimisers.RLVaRVF_VecRLVaRVF — Type
const RLVaRVF_VecRLVaRVF = Union{<:AbstractRelativisticValueatRiskViewFormulation,
<:AbstractVector{<:AbstractRelativisticValueatRiskViewFormulation}}Alias for a union of a single relativistic value-at-risk view formulation or a vector of them.
Related
PortfolioOptimisers.AbstractEntropyPoolingTailViewEstimator — Type
abstract type AbstractEntropyPoolingTailViewEstimator <: AbstractEntropyPoolingViewEstimatorAbstract supertype for the estimators that carry a group of tail views together with the settings those views are read under.
A significance level is a property of a view, not of the estimator that holds it: the conditional value at risk at 1% and at 10% are different statistics of the same series. An estimator of this family pairs a group of view equations with the level and the formulation they take, so one EntropyPoolingPrior can hold views stated at several levels.
Related
AbstractEntropyPoolingViewEstimatorConditionalValueatRiskViewEntropicValueatRiskViewEntropyPoolingPrior
References
- [1] D. Cajas. Entropy Pooling with CVaR and EVaR Views. Available at SSRN 7120258 (2026).
PortfolioOptimisers.CVV_VecCVV — Type
const CVV_VecCVV = Union{<:ConditionalValueatRiskView,
<:AbstractVector{<:ConditionalValueatRiskView}}Alias for the shapes a cvar_views field accepts: one ConditionalValueatRiskView, or a vector of them read under their own significance levels and formulations.
Related
PortfolioOptimisers.EVV_VecEVV — Type
const EVV_VecEVV = Union{<:EntropicValueatRiskView,
<:AbstractVector{<:EntropicValueatRiskView}}Alias for the shapes an evar_views field accepts: one EntropicValueatRiskView, or a vector of them read under their own significance levels and formulations.
Related
PortfolioOptimisers.RVV_VecRVV — Type
const RVV_VecRVV = Union{<:RelativisticValueatRiskView,
<:AbstractVector{<:RelativisticValueatRiskView}}Alias for the shapes an rlvar_views field accepts: one RelativisticValueatRiskView, or a vector of them read under their own significance levels, deformation parameters and formulations.
Related
PortfolioOptimisers.AbstractEntropyPoolingTailView — Type
abstract type AbstractEntropyPoolingTailView <: AbstractResultAbstract supertype for the tail view constraints of an entropy pooling problem.
A tail view constraint is the parsed, resolved form of a conditional or entropic value-at-risk view. It carries the loss series, the level, the operator and the target, in the shape the formulation that produced it needs. Unlike the linear views, which reduce to rows of a matrix that multiplies the posterior probabilities, a tail view constraint needs auxiliary variables, so it is handed to the optimiser as a struct and built into the model there.
Related
References
- [1] D. Cajas. Entropy Pooling with CVaR and EVaR Views. Available at SSRN 7120258 (2026).
PortfolioOptimisers.VecEPTV — Type
const VecEPTV = AbstractVector{<:AbstractEntropyPoolingTailView}Alias for an abstract vector of AbstractEntropyPoolingTailView elements.
Related
PortfolioOptimisers.add_ep_constraint! — Function
add_ep_constraint!(epc::AbstractDict, lhs::MatNum, rhs::VecNum, key::Symbol)Add an entropy pooling view constraint to the constraint dictionary.
add_ep_constraint! normalises and adds a constraint to the entropy pooling constraint dictionary epc. If a constraint with the same key already exists, it concatenates the new constraint to the existing one. This function is used internally to build the set of linear constraints for entropy pooling optimisation.
Every view that is linear in the posterior probabilities reaches epc as a block $(\mathbf{A},\, \boldsymbol{B})$ of the system $\mathbf{A} \boldsymbol{p} = \boldsymbol{B}$ or $\mathbf{A} \boldsymbol{p} \leq \boldsymbol{B}$. The key names the sense of the block, and the optimiser reads the block back by that key.
Mathematical definition
The block is divided by the Frobenius norm of its left-hand side, which leaves the row it states unchanged:
\[\begin{align} \tilde{\mathbf{A}} &= \dfrac{\mathbf{A}}{\lVert \mathbf{A} \rVert_{F}}\,, \\ \tilde{\boldsymbol{B}} &= \dfrac{\boldsymbol{B}}{\lVert \mathbf{A} \rVert_{F}}\,. \end{align}\]
Where:
- $\mathbf{A}$: Constraint coefficient matrix.
- $\boldsymbol{B}$: Constraint response vector.
- $\boldsymbol{p}$: $T \times 1$ posterior probabilities of the observations, summing to one. They are the unknown of the entropy pooling problem.
- $\lVert \mathbf{A} \rVert_{F}$: Frobenius norm of the left-hand side block.
Algorithm
- Read the Frobenius norm of
lhsintosc. - Divide
lhsandrhsbysc, giving the normalised block. - Store the pair under
keywhenepcholds no such key. - Otherwise stack the normalised
lhsunder the block already held, and appendrhsto the block's right-hand side.
Arguments
epc: Dictionary of entropy pooling constraints, mapping keys to(lhs, rhs)pairs.lhs: Left-hand side constraint matrix.rhs: Right-hand side constraint vector.key: Constraint type key (:eq,:ineq,:feq,:cvar_eq).
Returns
nothing: The function mutatesepcin-place.
Related
PortfolioOptimisers.announce_ep_departures — Function
announce_ep_departures(ni::VecStr, ledger::VecStr, viewless::Bool) -> NothingReport, once per entropy pooling fit, who left the investable universe and what their leaving cost the view set.
This is the family's call of announce_non_investable, written once so the four ep_prior methods each spend one line on it and none of them can word it differently. It names the process an entropy pooling fit, because the message is otherwise the optimisation door's and would tell a standalone prior(pe, X) call that it is inside an optimisation it is not.
It is said at the end of the fit, not at the reduction. A staged algorithm interleaves its view builders with its solves, so the ledger is only complete when the last stage has stated its views; reporting earlier would report a third of the truth and reporting per stage would be three messages for one departure.
viewless raises the message to a warning: a departure that took the last surviving view leaves the fit with nothing to condition on, so the posterior is the prior probabilities and the answer is not the one the caller asked for. Every other drop trims the view set and is @info.
Arguments
ni: The names the Investable Mask left out, frominvestable_views.ledger: What the departures cost, as the view builders recorded it.viewless: Whether the fit ended up with no view at all because of the departures.
Returns
nothing.
Related
PortfolioOptimisers.replace_prior_views — Function
replace_prior_views(res::ParsingResult, pr::AbstractPriorResult, sets::UniverseSets,
key::Symbol, alpha::Option{<:Number} = nothing, params...;
strict::Bool = false)Replace prior references in view parsing results with their corresponding prior values.
replace_prior_views scans a parsed view constraint ParsingResult for references to prior values (e.g., prior(A)), and replaces them with the actual prior value from the provided prior result object. This ensures that prior-based terms in view constraints are treated as constants and not as variables in the optimisation.
Mathematical definition
A parsed view is the row $\sum_{k} c_{k} v_{k} \lessgtr b$, and a term whose variable is prior(a) carries the constant $\pi_{a}$ rather than an unknown. Moving every such term to the right-hand side gives an equivalent row over the remaining terms:
\[\sum_{k \notin \mathcal{P}} c_{k} v_{k} \lessgtr b - \sum_{k \in \mathcal{P}} c_{k} \pi_{a_{k}}\,.\]
Where:
- $c_{k}$, $v_{k}$: Coefficient and variable of the $k$-th term of the view.
- $b$: Right-hand side of the view.
- $\mathcal{P}$: Terms whose variable is a
prior(...)reference. - $\pi_{a}$: Prior value of the statistic
keyfor asset $a$, read byget_pr_valueat the levelalphaand the further parametersparams....
Algorithm
- Match the pattern
prior(<asset>)against the variable of each term in turn. - When a term does not match, record that the view keeps a variable of its own, and take the next term.
- Find the named asset in the universe. When it is absent, report it through
strict_diagnostic, record the term for removal, and take the next term. - Subtract
get_pr_valuetimes the term's coefficient fromrhs, and record the term for removal. - Return
resunchanged when step 3 and step 4 recorded no term. - Drop the recorded terms from
varsandcoef, rebuild the equation string, and return aParsingResultthat carries the adjustedrhs.
Arguments
res: Parsed view constraint containing variables and coefficients.pr: Prior result object containing prior values.sets: Asset set mapping asset names to indices.key: Moment type key (:mu,:var,:cvar, etc.).alpha: Optional confidence level for VaR/CVaR views.params...: Further parameters of the statistic, forwarded toget_pr_value. A tail risk view passes the observation weights the reference is read under here, and a relativistic value-at-risk view its deformation parameter.strict: Iftrue, throws error for missing assets; otherwise, issue warnings.
Validation
- An asset a
prior(...)reference names that the universe does not hold raises anArgumentErrorwhenstrictistrue, and warns otherwise. The term is dropped either way. - At least one term of the view must keep a variable of its own. A view whose every term is a
prior(...)reference is a statement about constants alone, and raises anArgumentError.
Returns
res::ParsingResult: Updated parsing result with prior references replaced by their values.
Related
ParsingResultget_pr_value: reads the prior value each reference is replaced by.LowOrderPriorUniverseSetsprior
replace_prior_views(res::VecPR, args...; kwargs...)Replace the prior references of every view constraint of a group.
replace_prior_views applies replace_prior_views to each element of a vector of parsed view constraints, replacing prior references with their corresponding prior values. parse_equation answers a group of view equations with a vector of results, so this is the shape every caller in this file meets.
The loop is a comprehension rather than a broadcast. Every parameter after res is one value for the whole group, and a broadcast reads a Tuple or a vector of observation weights as a container to walk beside res instead. That raises a DimensionMismatch whenever a group holds more than one equation, which is the shape this method exists for.
Algorithm
- Call the single-view method once per element of
res, forwardingargs...andkwargs...to each call. - Return the vector of the results, one per element of
res, in the order ofres.
Arguments
res:: Vector of parsed view constraints.args...: Additional positional arguments forwarded toreplace_prior_views.kwargs...: Additional keyword arguments forwarded toreplace_prior_views.
Returns
res::Vector{<:ParsingResult}: Vector of updated parsing results with prior references replaced by their values.
Related
PortfolioOptimisers.replace_coprior_views — Function
replace_coprior_views(res::ParsingResult, pr::AbstractPriorResult, sets::UniverseSets, key::Symbol;
strict::Bool = false)Replace correlation prior references in view parsing results with their corresponding prior values.
replace_coprior_views scans a parsed correlation view constraint (ParsingResult) for references to prior values (e.g., prior(A, B)), and replaces them with the actual prior correlation value from the provided prior result object. This ensures that prior-based terms in correlation view constraints are treated as constants and not as variables in the optimisation.
It is the pair counterpart of replace_prior_views, and it answers a RhoParsingResult rather than a ParsingResult: a pair view carries the index pair of every term, which the verb that places the view in the covariance matrix reads back.
Mathematical definition
A parsed pair view is the row $\sum_{k} c_{k} v_{k} \lessgtr b$, whose variables name asset pairs. A term whose variable is prior(a, b) carries a constant, so moving every such term to the right-hand side gives an equivalent row:
\[\sum_{k \notin \mathcal{P}} c_{k} v_{k} \lessgtr b - \sum_{k \in \mathcal{P}} c_{k} \pi_{a_{k},\, b_{k}}\,.\]
A prior(gA, gB) reference over a pair of groups carries one constant per spanned asset pair, so the subtraction broadcasts and $b$ widens to a vector of that length, one right-hand side per row the view emits.
Where:
- $c_{k}$, $v_{k}$: Coefficient and variable of the $k$-th term of the view.
- $b$: Right-hand side of the view.
- $\mathcal{P}$: Terms whose variable is a
prior(...)reference. - $\pi_{a,\,b}$: Prior value of the statistic
keyfor the asset pair $(a, b)$, read byget_pr_value.
Algorithm
- Match the pattern
prior(<asset1>, <asset2>)against the variable of each term in turn. - When a term does not match, read its own pair
(a, b)instead. Raise when the term is not of the form(a, b). - Find both names in the universe, reading a bracketed name as a group and every other as one asset. When either is absent, report it through
strict_diagnostic, record the term for removal, and take the next term. - Record the index pair in
jk_idx, and take the next term. - For a term that does match, find both names the same way, subtract
get_pr_valuetimes the term's coefficient fromrhswith the broadcasting operators, and record the term for removal. - Return a
RhoParsingResultover the untouched terms when step 3 and step 5 recorded no term. - Drop the recorded terms from
varsandcoef, rebuild the equation string, and return aRhoParsingResultthat carries the adjustedrhsandjk_idx.
Arguments
res: Parsed correlation view constraint containing variables and coefficients.pr: Prior result object containing prior correlation values.sets: Asset set mapping asset names to indices.key: Symbol representing whether it's a correlation or covariance view.strict: Iftrue, throws error for missing assets; otherwise, issue warnings.
Validation
- Every term that is not a
prior(...)reference must be of the form(a, b). Any other form raises anArgumentError. - Every
prior(...)reference must be of the formprior(a, b). Any other form raises anArgumentError. - An asset a reference names that the universe does not hold raises an
ArgumentErrorwhenstrictistrue, and warns otherwise. The term is dropped either way. - At least one term of the view must keep a variable of its own. A view whose every term is a
prior(...)reference raises anArgumentError.
Returns
res::RhoParsingResult: Updated parsing result with prior references replaced by their values and correlation indices.
Related
ParsingResultRhoParsingResultreplace_prior_views: the single-asset counterpart.get_pr_value: reads the prior value each reference is replaced by.LowOrderPriorUniverseSetsprior
replace_coprior_views(res::VecPR, args...; kwargs...)Broadcast prior reference replacement across multiple view constraints.
replace_coprior_views applies replace_coprior_views to each element of a vector of parsed view constraints, replacing prior references with their corresponding prior values. parse_equation answers a group of view equations with a vector of results, so this is the shape every caller in this file meets.
Algorithm
- Broadcast the single-view method over
res, forwardingargs...andkwargs...to each call. - Return the vector of the results, one
RhoParsingResultper element ofres, in the order ofres.
Arguments
res:: Vector of parsed view constraints.args...: Additional positional arguments forwarded toreplace_coprior_views.kwargs...: Additional keyword arguments forwarded toreplace_coprior_views.
Returns
res::Vector{<:ParsingResult}: Vector of updated parsing results with prior references replaced by their values.
Related
PortfolioOptimisers.get_pr_value — Function
get_pr_value(pr::AbstractPriorResult, i::Integer, ::Val{:mu}, args...)Read the prior mean of asset i.
get_pr_value is the dispatch table that resolves a prior(...) reference inside a view. This method reads the statistic the tag Val(:mu) names, the i-th entry of pr.mu. It is used internally by replace_prior_views and by the ep_*_views! verbs.
Arguments
pr: Prior result containing asset return information.i: Index of the asset.::Val{:mu}: Dispatch tag for mean extraction.args...: Additional arguments (ignored).
Returns
mu::Number: Mean (expected return) for asseti.
Related
get_pr_value(pr::AbstractPriorResult, i::Integer, ::Val{:var}, alpha::Number,
w::Option{<:ObsWeights} = nothing)Read the prior value at risk of asset i at the level alpha.
get_pr_value is the dispatch table that resolves a prior(...) reference inside a view. This method reads the statistic the tag Val(:var) names, by applying ValueatRisk to the i-th column of pr.X. That is the $\alpha$-quantile of the loss series under w, the observation weights the initial prior result was read at. A caller who states a non-uniform w reads the reference off the distribution that caller's own prior carries.
Arguments
pr: Prior result containing asset return information.i: Index of the asset.::Val{:var}: Dispatch tag for VaR extraction.alpha: Confidence level (e.g.,0.05for 5% VaR).w: Optional observation weights vectorobservations × 1, or a concrete subtype ofDynamicAbstractWeights. Ifnothing, the computation is unweighted.
Returns
var::Number: Value-at-Risk for assetiat levelalpha.
Related
get_pr_value(pr::AbstractPriorResult, i::Integer, ::Val{:cvar}, alpha::Number,
w::Option{<:ObsWeights} = nothing)Read the prior conditional value at risk of asset i at the level alpha.
get_pr_value is the dispatch table that resolves a prior(...) reference inside a view. This method reads the statistic the tag Val(:cvar) names, by applying ConditionalValueatRisk to the i-th column of pr.X. That is the conditional value at risk of the loss series under w, the observation weights the initial prior result was read at, and it rests on no distributional assumption. It reads w on the reasoning get_pr_value gives for the value at risk.
Arguments
pr: Prior result containing asset return information.i: Index of the asset.::Val{:cvar}: Dispatch tag for CVaR computation.alpha: Confidence level.w: Optional observation weights vectorobservations × 1, or a concrete subtype ofDynamicAbstractWeights. Ifnothing, the computation is unweighted.
Returns
cvar::Number: Conditional Value-at-Risk for assetiat levelalpha.
Related
get_pr_value(pr::AbstractPriorResult, i::Integer, ::Val{:sigma}, args...)Read the prior variance of asset i.
get_pr_value is the dispatch table that resolves a prior(...) reference inside a view. This method reads the statistic the tag Val(:sigma) names, the i-th diagonal entry of pr.sigma. The tag is :sigma and the statistic is the variance, not the standard deviation and not the value at risk, which the tag :var names.
Arguments
pr: Prior result containing asset return information.i: Index of the asset.::Val{:sigma}: Dispatch tag for variance extraction.args...: Additional arguments (ignored).
Returns
sigma::Number: Variance for asseti.
Related
get_pr_value(pr::AbstractPriorResult, i::Integer, j::Integer, ::Val{:rho}, args...)
get_pr_value(pr::AbstractPriorResult, i::Integer, j::Integer, ::Val{:cov}, args...)Read the prior correlation or covariance of the asset pair (i, j).
get_pr_value is the dispatch table that resolves a prior(...) reference inside a view. Val(:cov) names the entry pr.sigma[i, j], and Val(:rho) names the same entry of StatsBase.cov2cor(pr.sigma). These methods are used internally by replace_coprior_views to resolve a prior(a, b) reference.
Arguments
pr: Prior result containing asset return information.i: Index of the first asset.j: Index of the second asset.::Val{:rho}: Dispatch tag for correlation extraction.::Val{:cov}: Dispatch tag for covariance extraction.args...: Additional arguments (ignored).
Returns
val::Number: Correlation coefficient or covariance between assetsiandj.
Related
get_pr_value(pr::AbstractPriorResult, i::VecInt, j::VecInt, ::Val{:rho}, args...)
get_pr_value(pr::AbstractPriorResult, i::VecInt, j::VecInt, ::Val{:cov}, args...)Read the prior correlations or covariances of the asset pairs that two groups span.
get_pr_value is the dispatch table that resolves a prior(...) reference inside a view. These methods read the same statistics their scalar siblings do, once per spanned pair, in the order of zip(i, j). A view over a pair of groups emits one constraint row per spanned pair, so a prior(gA, gB) reference inside such a view must give each row that pair's own prior value.
Arguments
pr: Prior result containing asset return information.i: Vector of indices for the first asset group.j: Vector of indices for the second asset group.::Val{:rho}: Dispatch tag for correlation extraction.::Val{:cov}: Dispatch tag for covariance extraction.args...: Additional arguments (ignored).
Returns
val::Vector{<:Number}: Correlation or covariance of each spanned pair, one entry per element ofzip(i, j).
Related
get_pr_value(pr::AbstractPriorResult, i::Integer, ::Val{:skew}, args...)Read the prior skewness of asset i.
get_pr_value is the dispatch table that resolves a prior(...) reference inside a view. This method reads the statistic the tag Val(:skew) names, by applying Skewness to the i-th column of pr.X. That is the standardised third central moment of the sample, and it ignores pr.w.
Arguments
pr: Prior result containing asset return information.i: Index of the asset.::Val{:skew}: Dispatch tag for skewness extraction.args...: Additional arguments (ignored).
Returns
skew::Number: Skewness for asseti.
Related
get_pr_value(pr::AbstractPriorResult, i::Integer, ::Val{:kurtosis}, args...)Read the prior kurtosis of asset i.
get_pr_value is the dispatch table that resolves a prior(...) reference inside a view. This method reads the statistic the tag Val(:kurtosis) names, by applying HighOrderMoment with a StandardisedHighOrderMoment of FourthMoment to the i-th column of pr.X. That is the standardised fourth central moment of the sample, and it ignores pr.w.
Arguments
pr: Prior result containing asset return information.i: Index of the asset.::Val{:kurtosis}: Dispatch tag for kurtosis extraction.args...: Additional arguments (ignored).
Returns
kurtosis::Number: Kurtosis for asseti.
Related
get_pr_value(pr::AbstractPriorResult, i::Integer, ::Val{:evar}, alpha::Number,
w::Option{<:ObsWeights} = nothing, args::Tuple = (),
kwargs::NamedTuple = (;), zlo_frac::Option{<:Number} = nothing)Extract the Entropic Value-at-Risk (EVaR) for asset i from a prior result.
get_pr_value computes the EVaR at confidence level alpha for the asset indexed by i from the prior result object pr, by minimising the scalar objective of the sample EVaR formula with ep_evar. The observations carry w, the weights the initial prior result was read at. A w of nothing leaves them uniform.
Arguments
pr: Prior result containing asset return information. Only its returns matrix is read, under the weightswnames.i: Index of the asset.::Val{:evar}: Dispatch tag for EVaR extraction.alpha: Confidence level (e.g.0.05for 5% EVaR).w: Optional observation weights vectorobservations × 1, or a concrete subtype ofDynamicAbstractWeights. Ifnothing, the computation is unweighted.args: Additional positional arguments passed to the optimisation function.kwargs: Additional keyword arguments passed to the optimisation function.zlo_frac: Lower end of the bracket of the dual variable, as a fraction of the upper end, forwarded toep_evar.
Returns
evar::Number: Entropic Value-at-Risk for assetiat levelalpha.
Related
get_pr_value(pr::AbstractPriorResult, i::Integer, ::Val{:rlvar}, alpha::Number,
kappa::Number, w::Option{<:ObsWeights} = nothing, args::Tuple = (),
kwargs::NamedTuple = (;),
bracket::Option{<:RelativisticValueatRiskViewBracket} = nothing)Extract the Relativistic Value-at-Risk (RLVaR) for asset i from a prior result.
get_pr_value computes the RLVaR at confidence level alpha and deformation parameter kappa for the asset indexed by i from the prior result object pr, by minimising the primal objective of the sample RLVaR with ep_rlvar. The observations carry w, the weights the initial prior result was read at, on the reasoning the entropic value at risk method above gives.
Arguments
pr: Prior result containing asset return information. Only its returns matrix is read, under the weightswnames.i: Index of the asset.::Val{:rlvar}: Dispatch tag for RLVaR extraction.alpha: Confidence level (e.g.0.05for 5% RLVaR).kappa: Deformation parameter, in(0, 1).w: Optional observation weights vectorobservations × 1, or a concrete subtype ofDynamicAbstractWeights. Ifnothing, the computation is unweighted.args: Additional positional arguments passed to the optimisation function.kwargs: Additional keyword arguments passed to the optimisation function.bracket: Spans of the searches, forwarded toep_rlvarandep_rlvar_shift.
Returns
rlvar::Number: Relativistic Value-at-Risk for assetiat levelalphaand deformationkappa.
Related
PortfolioOptimisers.ep_mu_views! — Function
ep_mu_views!(mu_views::Nothing, args...; kwargs...)Do nothing when a problem states no mean view.
ep_mu_views! is the verb that turns a group of mean views into rows of the entropy pooling constraint dictionary. This method is the absent-view branch: it registers no row, so a higher-level routine can call the verb without special-casing mu_views = nothing.
Arguments
mu_views::Nothing: Indicates that no mean view constraints are specified.args...: Additional positional arguments (ignored).kwargs...: Additional keyword arguments (ignored).
Returns
nothing.
Related
ep_mu_views!(mu_views::LinearConstraintEstimator, epc::AbstractDict,
pr::AbstractPriorResult, sets::UniverseSets; strict::Bool = false)Add the mean views of a group to the entropy pooling constraint dictionary.
ep_mu_views! parses mean view equations from a LinearConstraintEstimator, replaces any prior references with their actual values, and constructs the corresponding linear constraints for entropy pooling. The constraints are then added to the entropy pooling constraint dictionary epc. The statistic is the mean of the posterior distribution, which is linear in the posterior probabilities, so the view needs no auxiliary variable and no moment is fixed on its account.
Mathematical definition
The posterior mean of an asset is the probability weighted average of its returns, and a view states a linear combination of such means:
\[\begin{align} \mathrm{E}_{\boldsymbol{p}}[x_{i}] &= \sum_{t=1}^{T} p_{t} x_{t,\,i}\,, \\ \sum_{i=1}^{N} a_{k,\,i} \mathrm{E}_{\boldsymbol{p}}[x_{i}] &\lessgtr B_{k}\,, \quad \forall\, k = 1,\ldots,K\,. \end{align}\]
The left-hand side is linear in $\boldsymbol{p}$, so the $K$ views are the block $\left(\mathbf{A} \mathbf{X}^{\intercal},\, \boldsymbol{B}\right)$.
Where:
- $\boldsymbol{p}$: $T \times 1$ posterior probabilities of the observations, summing to one. They are the unknown of the entropy pooling problem.
- $x_{t,\,i}$: Return of asset $i$ at observation $t$.
- $T$: Number of observations.
- $N$: Number of assets.
- $\mathbf{A}$: Constraint coefficient matrix.
- $\boldsymbol{B}$: Constraint response vector.
- $a_{k,\,i}$: Coefficient asset $i$ takes in view $k$, the $(k, i)$ entry of $\mathbf{A}$.
- $K$: Number of views the group states.
- $\mathbf{X}$: $T \times N$ returns matrix of the prior.
Algorithm
- Parse the view equations of
mu_views.val, giving oneParsingResultper view. - Replace every group name by the assets it spans.
- Replace every
prior(...)reference by the prior mean, throughreplace_prior_views. - Turn the parsed views into the linear constraint blocks
lcs, one for:ineqand one for:eq. Understrict = falseevery row of the group can drop, andlcsis thennothing: the group states no view, and the call returns without adding a row. - For each block present, add
A * transpose(X)againstBunder that key withadd_ep_constraint!.
Arguments
mu_views: Mean view constraints.epc: Dictionary of entropy pooling constraints, mapping keys to(lhs, rhs)pairs.pr: Prior result containing asset return information.sets: Asset set mapping asset names to indices.strict: Iftrue, throws error for missing assets; otherwise, issue warnings.
Returns
nothing: The function mutatesepcin-place.
Related
add_ep_constraint!replace_prior_viewsget_pr_value: reads the prior mean aprior(...)reference resolves to.fix_mu!: holds a mean at the prior when a higher moment view would move it.MeucciEntropyPoolingPrior
PortfolioOptimisers.fix_mu! — Function
fix_mu!(epc::AbstractDict, fixed::AbstractVector, to_fix::BitVector,
pr::AbstractPriorResult)Hold the mean of the named assets at the prior value.
fix_mu! identifies assets in to_fix that are not yet fixed (i.e., not present in fixed), and adds constraints to the entropy pooling constraint dictionary epc to fix their mean to the prior value. This ensures that higher moment views (e.g., variance, skewness, kurtosis, correlation) do not inadvertently alter the mean of these assets. The function updates fixed in-place to reflect the newly fixed assets.
The rows go in under the :feq key, which the optimiser relaxes with a penalised slack rather than enforcing exactly. A fixing row is a wish, not a view: it competes with the views that were asked for, and it yields where the two cannot both hold.
Mathematical definition
The posterior mean of every named asset is held at the prior mean:
\[\sum_{t=1}^{T} p_{t} x_{t,\,i} = \mu_{i}\,, \quad \forall\, i \in \mathcal{F}\,.\]
Where:
- $\boldsymbol{p}$: $T \times 1$ posterior probabilities of the observations, summing to one. They are the unknown of the entropy pooling problem.
- $x_{t,\,i}$: Return of asset $i$ at observation $t$.
- $\mu_{i}$: Prior mean of asset $i$. It is a constant of the view, and a lower moment view or a fixing row holds the posterior mean at it.
- $T$: Number of observations.
- $\mathcal{F}$: Assets named by
to_fixthatfixeddoes not already hold.
Algorithm
- Read the assets that
to_fixnames andfixeddoes not already hold intofix. - Return when
fixnames no asset. - Add one
:feqrow per named asset,transpose(view(pr.X, :, fix))againstpr.mu[fix], withadd_ep_constraint!. - Mark the named assets in
fixed, so a later call adds no second row for them.
Arguments
epc: Dictionary of entropy pooling constraints, mapping keys to(lhs, rhs)pairs.fixed: Boolean vector indicating which assets have their mean fixed.to_fix: Boolean vector indicating which assets should have their mean fixed.pr: Prior result containing asset return information.
Returns
nothing: The function mutatesepcandfixedin-place.
Related
add_ep_constraint!ep_mu_views!fix_sigma!: the same rule, one moment higher.MeucciEntropyPoolingPrior
PortfolioOptimisers.ep_var_views! — Function
ep_var_views!(var_views::Nothing, args...; kwargs...)Do nothing when a problem states no value at risk view.
ep_var_views! is the verb that turns a group of value at risk views into rows of the entropy pooling constraint dictionary. This method is the absent-view branch: it registers no row, so a higher-level routine can call the verb without special-casing var_views = nothing.
Arguments
var_views::Nothing: Indicates that no value at risk (VaR) view constraints are specified.args...: Additional positional arguments (ignored).kwargs...: Additional keyword arguments (ignored).
Returns
nothing.
Related
ep_var_views!(var_views::ValueatRiskView, epc::AbstractDict,
pr::AbstractPriorResult, sets::UniverseSets,
w::Option{<:ObsWeights} = nothing; strict::Bool = false)
ep_var_views!(var_views::LinearConstraintEstimator, epc::AbstractDict,
pr::AbstractPriorResult, sets::UniverseSets, alpha::Number,
w::Option{<:ObsWeights} = nothing; strict::Bool = false)Add the value at risk views of a group to the entropy pooling constraint dictionary.
The first method unpacks a ValueatRiskView into its equations and its significance level, and hands both to the second. The second carries the body: it parses the view equations, replaces any prior references with their actual values, and constructs the corresponding linear constraints for entropy pooling. The statistic is the value at risk of the posterior distribution, not the variance, which the sigma_views family holds.
A value at risk view is linear in the posterior probabilities: it constrains the probability mass at or beyond the target loss, so it needs no auxiliary variable and no moment is fixed on its account.
Mathematical definition
The value at risk at level $\alpha$ is the smallest loss the posterior leaves at most $\alpha$ of its mass beyond, so a view on it is a statement about the tail mass of the sample:
\[\begin{align} \mathrm{VaR}_{\alpha}(x_{i}) \geq \bar{v} \quad &\Longleftrightarrow \quad \sum_{t \in \mathcal{T}_{i}(\bar{v})} p_{t} \geq \alpha\,, \\ \mathrm{VaR}_{\alpha}(x_{i}) = \bar{v} \quad &\Longleftrightarrow \quad \sum_{t \in \mathcal{T}_{i}(\bar{v})} p_{t} = \alpha\,, \\ \mathcal{T}_{i}(\bar{v}) &= \left\{ t : x_{t,\,i} \leq -\lvert \bar{v} \rvert \right\}\,. \end{align}\]
Both are linear in $\boldsymbol{p}$, which is why this view reaches OptimEntropyPooling as readily as JuMPEntropyPooling.
Where:
- $\boldsymbol{p}$: $T \times 1$ posterior probabilities of the observations, summing to one. They are the unknown of the entropy pooling problem.
- $x_{t,\,i}$: Return of asset $i$ at observation $t$.
- $\alpha$: Significance level (left tail probability), $\alpha \in (0, 1)$.
- $\bar{v}$: Target value at risk of the view.
- $\mathcal{T}_{i}(\bar{v})$: Observations of asset $i$ whose loss reaches the target.
The constraint fixes the posterior mass of $\mathcal{T}_{i}(\bar{v})$, and the posterior value at risk of that mass is a sample order statistic: ValueatRisk reads the first observation whose cumulative weight reaches $\alpha$. An entropy pooling solve meets its constraints to its own tolerance, and a mass short of $\alpha$ by as little as 1e-8 reads one observation further down the tail. The posterior value at risk then sits under $\bar{v}$, by the gap between two neighbouring losses. No tolerance on the solve removes this, because the reading is a step function of the mass. The view is met to the resolution the sample has, which is one observation. Read a posterior value at risk against the two observations that bracket the target, and read the tail mass where an exact statement is needed.
Algorithm
- Parse the view equations of
var_views.val, accepting==and>=alone. - Replace every group name by the assets it spans.
- Replace every
prior(...)reference by the prior value at risk atalpha, read underw, throughreplace_prior_views. - Turn the parsed views into the linear constraint blocks
lcs, one for:ineqand one for:eq. Understrict = falseevery row of the group can drop, andlcsis thennothing: the group states no view, and the call returns without adding a row. - Check the three preconditions of the section below.
- For each block present, and each row
iof it, read the asset the row names intoj, and the observations ofview(X, :, j)at or below-abs(B[i])intoidx. - Raise when
idxnames no observation. - Read the sense the row takes into
sign: it is one for an equality row and for a non-negative right-hand side, and minus one otherwise. - Build the row
Aithat carriessignatidxand zero elsewhere, and add it againstsign * alphawithadd_ep_constraint!.
Arguments
var_views: VaR view constraints.epc: Dictionary of entropy pooling constraints, mapping keys to(lhs, rhs)pairs.pr: Prior result containing asset return information.sets: Asset set mapping asset names to indices.alpha: Confidence level for VaR.w: Optional observation weights vectorobservations × 1, or a concrete subtype ofDynamicAbstractWeights. Ifnothing, the computation is unweighted.strict: Iftrue, throws error for missing assets; otherwise, issue warnings.
Validation
- Every coefficient has magnitude zero or one. Any other coefficient raises an
ArgumentError. The check reads the magnitude because the parser normalises a>=row to<=by negation, which carries a coefficient of one into the block as minus one. - Every view names one asset. A view over more than one asset raises an
ArgumentError. - Every target is non-negative. A negative target raises a
DomainError. - The sample must hold at least one observation whose loss reaches the target. A view more extreme than the worst realisation raises a
DomainErrornaming the largest target the asset admits.
Returns
nothing: The function mutatesepcin-place.
Related
ValueatRiskViewadd_ep_constraint!replace_prior_viewsget_pr_value: reads the prior value at risk aprior(...)reference resolves to.MeucciEntropyPoolingPrior
ep_var_views!(var_views::AbstractVector{<:ValueatRiskView}, args...; kwargs...)Add each group of value at risk views under its own significance level.
Every ValueatRiskView in the vector is added in turn, so the groups accumulate into the same constraint set and one entropy pooling solve answers all of them.
Algorithm
- Add each
ValueatRiskViewofvar_viewsin turn, forwardingargs...andkwargs...to each call. - Return
nothing. Each call has already written its rows intoepc.
Arguments
var_views: Groups of VaR views.args...: Additional positional arguments forwarded toep_var_views!.kwargs...: Additional keyword arguments forwarded toep_var_views!.
Returns
nothing: The function mutatesepcin-place.
Related
PortfolioOptimisers.ep_prior_probabilities — Function
ep_prior_probabilities(w::Option{<:StatsBase.ProbabilityWeights},
pr::AbstractPriorResult, Ti::Int)Return the prior probabilities an entropy pooling fit starts from.
A prior that reweights observations works on the observation axis its nested prior answered, not on the axis it was handed. A nested prior may drop rows: a CrossSectionalFactorPrior drops the observations its Descriptors warm up over and the observations its exposure lag consumes, so its scenarios are the window the fit is defined on. So pr is fitted first, and the prior probabilities are read on its rows.
The three sources are read in order. A caller's pe.w wins, because it is the one tilt no fit can state. The nested result's own w comes next, because a nested pooling prior already tilted the scenarios it answered, and uniform is then not the prior. Uniform over the rows of pr.X is the last.
Algorithm
- Take
Tassize(pr.X, 1), the observations the nested prior answered. - When
wis notnothing, check its length againstTand return it. - When
wisnothingandpr.wis not, returnpr.wasStatsBase.pweights. - Otherwise return the uniform
1/TasStatsBase.pweights.
Arguments
w: A caller's prior probabilities, thewfield of the pooling estimator, ornothing.pr: Prior result of the nested estimator, fitted before this call.Ti: Observations the pooling estimator was handed. It is read only by the refusal message.
Validation
length(w) == size(pr.X, 1). A length that does not match raises aDimensionMismatchnaming both counts and the count the estimator was handed.
Returns
w0::StatsBase.ProbabilityWeights: Prior probabilities, on the rows ofpr.X.
Related
PortfolioOptimisers.entropy_pooling — Function
entropy_pooling(w::VecNum, epc::AbstractDict, opt::OptimEntropyPooling)Solve the dual of the entropy pooling problem using Optim.jl.
entropy_pooling computes posterior probabilities by minimising the Kullback-Leibler divergence of the posterior weights from the prior ones, subject to moment and view constraints. The optimisation is performed using Optim.jl. This method is used internally by MeucciEntropyPoolingPrior and EntropyPoolingPrior when the optimiser is an OptimEntropyPooling.
The two optimisation algorithms minimise the same objective and reach the same posterior. They differ only in the arithmetic that evaluates it.
The dual carries one variable per row rather than one per observation, and it has no room for an auxiliary variable, so it expresses no tail view. It also has no slack variable: the fixed equality rows of the :feq key are relaxed by holding their dual variables in the box $[-s_{c2},\, s_{c2}]$, which is the dual of a penalty of weight $s_{c2}$ on the norm of the slack the primal would carry.
An infeasible view set answers without a raise. The dual of such a set is unbounded below, so the minimiser runs away rather than settling. The iterate stops moving once the exponential underflows, Optim reports x_converged or f_converged, and Optim.converged accepts it. The posterior it returns is degenerate: the probability collapses onto the observation with the largest coefficient, and the view the caller wrote is missed by any margin. Read the answer rather than the flag. The effective number of scenarios falls to a handful out of $T$ and one weight sits near one, the Kullback-Leibler divergence is large, and the posterior statistic the view named is far from its target. Views that pull one asset in two directions at once are the common way to reach it: a variance view that shrinks an asset, written beside a conditional value at risk view that fattens the same asset's tail, asks for a thin body and a fat tail at once. The same pair on two different assets is feasible and solves normally, so it is the direction and not the pairing. The gradient of this dual is $\boldsymbol{B} - \mathbf{A} \boldsymbol{y}$, the primal residual of the view set, so Optim.g_converged and Optim.g_residual do separate the two outcomes. Neither is read: Optim.g_converged also refuses a solve that is correct and merely loose, so acting on it needs a tolerance on the residual, and that tolerance is a policy this library does not set.
Mathematical definition
The primal minimises the Kullback-Leibler divergence of the posterior from the prior, over the probabilities that meet every row. Its dual carries one Lagrange multiplier per row, and is unconstrained apart from the box the sense of each row imposes:
\[\begin{align} \underset{\boldsymbol{x}}{\min} &\; \boldsymbol{x}^\intercal \boldsymbol{B} + \sum_{t=1}^{T} q_{t} \exp\!\left(-\boldsymbol{x}^\intercal \mathbf{A}_{\cdot t} - 1\right)\,. \end{align}\]
The optimal posterior probabilities recover from the minimiser as:
\[\begin{align} p_{t}^{*} &= q_{t} \exp\!\left(-\boldsymbol{x}^{*\intercal} \mathbf{A}_{\cdot t} - 1\right)\,. \end{align}\]
Where:
- $\boldsymbol{q}$: $T \times 1$ prior probabilities of the observations, summing to one.
- $\boldsymbol{p}$: $T \times 1$ posterior probabilities of the observations, summing to one. They are the unknown of the entropy pooling problem.
- $\mathbf{A}$: Constraint coefficient matrix.
- $\boldsymbol{B}$: Constraint response vector.
- $T$: Number of observations.
- $s_{c1}$: Constraint scale of the entropy pooling optimiser. It multiplies both sides of a row, so a positive value leaves the feasible set unchanged.
- $s_{c2}$: Slack penalty of the fixed equality rows. It weights the norm of the slack in the objective, so a larger value holds those rows tighter.
- $\boldsymbol{x}$: Lagrange multipliers of the rows, the variable of the dual.
- $\mathbf{A}_{\cdot t}$: $t$-th column of $\mathbf{A}$, the coefficient every row gives observation $t$.
- $q_{t}$, $p_{t}^{*}$: Prior and optimal posterior probability of observation $t$.
Algorithm
- Return
wwhenepcholds no row. An empty view set states nothing, so the posterior is the prior, and it is answered exactly rather than solved for. - Open
AandBwith the row that pins the posterior to sum to one, both sides divided by $\sqrt{T}$. - Stack the block of every key of
epcontoAandB, and set the boxwbof that block's dual variables from the key: free for:eqand:cvar_eq, non-negative for:ineq, and $[-s_{c2},\, s_{c2}]$ for:feq. Raise on any other key. A:feqblock is left out when $s_{c2}$ is zero, because that box pins its dual variables to zero and the fixed rows then carry no weight. - Start every dual variable at $1/\sqrt{T}$, clamped into its own box. A
:feqbox is $[-s_{c2},\, s_{c2}]$, so ans_{c2}below $1/\sqrt{T}$ would otherwise place the start outside it. - Minimise the dual objective over that box with
Optim.optimize, through the branchalgselects. Both the objective and its gradient are multiplied by $s_{c1}$. - Raise when
Optim.convergedreports that the solve failed. - Recover the posterior probabilities from the minimiser, and return them as
StatsBase.pweights.
Arguments
w: Prior weights (length = number of observations).epc: Dictionary of entropy pooling constraints, mapping keys to(lhs, rhs)pairs.opt: Optim.jl-based entropy pooling optimiser.::OptimEntropyPooling{<:Any, <:Any, <:Any, <:Any, <:ExpEntropyPooling}: Evaluate the objective through the exponential of the dual variables.::OptimEntropyPooling{<:Any, <:Any, <:Any, <:Any, <:LogEntropyPooling}: Evaluate the objective in log space.
Validation
- Every key of
epcis one of:eq,:ineq,:cvar_eqand:feq. Any other key raises aKeyError. - The solve must converge. A solve that
Optim.convergedreports as failed raises anErrorException. - An infeasible view set is not caught.
Optim.convergedis true onx_convergedorf_convergedalone, and the dual of an infeasible set stops on one of those. The summary paragraph states the shape of that answer and how to recognise it.
Returns
pw::StatsBase.ProbabilityWeights: Posterior probability weights satisfying the constraints.
Related
OptimEntropyPoolingExpEntropyPoolingLogEntropyPoolingMeucciEntropyPoolingPriorEntropyPoolingPriorJuMPEntropyPooling
References
- [78] A. Meucci. Fully flexible views: theory and practice. Risk 21, 97–102 (2008).
entropy_pooling(w::VecNum, epc::AbstractDict, opt::JuMPEntropyPooling)Solve the primal of the entropy pooling problem using JuMP.jl.
entropy_pooling computes posterior probabilities by minimising the Kullback-Leibler divergence of the posterior weights from the prior ones, subject to moment and view constraints. The optimisation is performed using JuMP.jl. This method is used internally by MeucciEntropyPoolingPrior and EntropyPoolingPrior when the optimiser is a JuMPEntropyPooling.
This method registers no model entry of its own. It is the three-argument shape of a problem that states no tail view, and the four-argument method carries the model, its # JuMP formulation and its # Algorithm.
Algorithm
- Call the four-argument method with an empty
AbstractEntropyPoolingTailViewvector, and return what it answers.
Arguments
w: Prior weights (length = number of observations).epc: Dictionary of entropy pooling constraints, mapping keys to(lhs, rhs)pairs.opt: JuMP.jl-based entropy pooling optimiser.::JuMPEntropyPooling{<:Any, <:Any, <:Any, <:Any, <:ExpEntropyPooling}: Write the divergence against the prior probabilities directly.::JuMPEntropyPooling{<:Any, <:Any, <:Any, <:Any, <:LogEntropyPooling}: Write the divergence against a unit reference and subtract the prior log-probabilities in the objective.
Returns
pw::StatsBase.ProbabilityWeights: Posterior probability weights satisfying the constraints.
Related
JuMPEntropyPoolingExpEntropyPoolingLogEntropyPoolingep_jump_views!: registers the rows ofepc, and the slack that relaxes the fixed equalities.MeucciEntropyPoolingPriorEntropyPoolingPriorOptimEntropyPooling
References
- [78] A. Meucci. Fully flexible views: theory and practice. Risk 21, 97–102 (2008).
entropy_pooling(w::VecNum, epc::AbstractDict, tvs::VecEPTV,
opt::AbstractEntropyPoolingOptimiser)Solve an entropy pooling problem that carries tail view constraints.
entropy_pooling extends the three-argument form with the conditional and entropic value-at-risk views of [1]. A tail view needs auxiliary variables, so it is built into the model by add_ep_tail_view! rather than reduced to rows of epc.
These methods carry the body of the JuMPEntropyPooling route. The OptimEntropyPooling method solves the dual, which has no room for an auxiliary variable, so it accepts an empty tvs alone and forwards to the three-argument form.
Mathematical definition
The primal of the entropy pooling problem minimises the Kullback-Leibler divergence of the posterior probabilities from the prior ones, over the probabilities that meet every row:
\[\begin{align} \underset{\boldsymbol{p}}{\min} \;\; &\sum_{t=1}^{T} p_{t} \ln\!\left(\dfrac{p_{t}}{q_{t}}\right)\\ \textrm{s.t.} \;\; &\sum_{t=1}^{T} p_{t} = 1\\ &\boldsymbol{p} \geq \boldsymbol{0}\\ &\mathbf{A}_{\mathrm{eq}} \boldsymbol{p} = \boldsymbol{B}_{\mathrm{eq}}\\ &\mathbf{A}_{\mathrm{ineq}} \boldsymbol{p} \leq \boldsymbol{B}_{\mathrm{ineq}}\,. \end{align}\]
Where:
- $\boldsymbol{q}$: $T \times 1$ prior probabilities of the observations, summing to one.
- $\boldsymbol{p}$: $T \times 1$ posterior probabilities of the observations, summing to one. They are the unknown of the entropy pooling problem.
- $\mathbf{A}$: Constraint coefficient matrix.
- $\boldsymbol{B}$: Constraint response vector.
- $\text{eq}$: Subscript for equality constraints.
- $\text{ineq}$: Subscript for inequality constraints.
- $T$: Number of observations.
- $q_{t}$, $p_{t}$: Prior and posterior probability of observation $t$.
Algorithm
- Raise when
optis anOptimEntropyPoolingandtvsnames a tail view, and forward to the three-argument form otherwise. - Return
wwhenepcholds no row andtvsnames no tail view. An empty view set states nothing, so the posterior is the prior, and it is answered exactly rather than solved for. - Solve once with
ep_jump_entropy_pooling, givingw1. - Read
iters, the largest number of re-solves a carrier oftvsasks for, withep_refine_iters. It is zero where no carrier is sequential, and the steps below then do not run. - Re-read every carrier at
w1withep_refine_tail_view, which returns the carrier and whether its surrogate row is tight there. Stop where every carrier is tight. - Solve again with the re-read carriers, giving a new
w1, and return to step 5. Take at mostitersre-solves, so the last posterior can hold a slack row when the sequence has not settled. - Return
w1asStatsBase.pweights.
The re-solves are the sequential convex formulations' half of the work. Each re-read row is tight at the posterior it was read at and still holds there, so that posterior stays feasible and the divergence of the next one is at most its own.
Arguments
w: Prior weights (length = number of observations).epc: Dictionary of entropy pooling constraints, mapping keys to(lhs, rhs)pairs.tvs: Tail view constraints.opt: Entropy pooling optimiser.::JuMPEntropyPooling: Builds every tail view into the model.::OptimEntropyPooling: Solves the dual, which has no room for an auxiliary variable, so it accepts an emptytvsalone.
Validation
isa(opt, OptimEntropyPooling)requiresisempty(tvs).
Returns
pw::StatsBase.ProbabilityWeights: Posterior probability weights satisfying the constraints.
Related
ep_jump_entropy_poolingep_refine_tail_viewep_refine_itersadd_ep_tail_view!JuMPEntropyPoolingOptimEntropyPoolingEntropyPoolingPrior
References
- [1] D. Cajas. Entropy Pooling with CVaR and EVaR Views. Available at SSRN 7120258 (2026).
PortfolioOptimisers.ep_jump_entropy_pooling — Function
ep_jump_entropy_pooling(w::VecNum, epc::AbstractDict, tvs::VecEPTV,
opt::JuMPEntropyPooling)Build and solve the entropy pooling model of one set of tail view carriers, once.
ep_jump_entropy_pooling is the body of the JuMPEntropyPooling route of entropy_pooling, which calls it once per set of carriers and re-calls it after re-reading the sequential ones. The two methods differ only in how they represent the divergence, and agree on every view.
Algorithm
- Read
sc1,sc2,soandslvoffopt, and open an emptyJuMP.Model. - Create the posterior variable
xand the divergence variablet. UnderExpEntropyPoolingxalso carries a non-negativity bound, which the cone of step 4 implies in either branch. - Add the row that pins the sum of
xto one. - Add the relative entropy cone that bounds
tbelow by the divergence. UnderExpEntropyPoolingthe cone reads the priorwas its reference, and underLogEntropyPoolingit reads a unit reference instead. - Register
obj_exprasso * t. - Add every view with
ep_jump_views!, which mutatesobj_exprwhen a fixed equality is relaxed. - Set the objective to
obj_exprunderExpEntropyPooling, and toobj_exprlesssotimes the inner product ofxwith the prior log-probabilities underLogEntropyPooling. - Solve with
slv, and raise when no solver configuration succeeds. - Return the value of
xasStatsBase.pweights.
JuMP formulation
Variables
t: $\eta$, the epigraph variable of the divergence, created here.x: $\boldsymbol{p}$, the posterior probabilities, created here. UnderExpEntropyPoolingit carries the bound $\boldsymbol{p} \geq \boldsymbol{0}$.
Expressions
obj_expr: $s_{o} \eta$.ep_jump_views!adds $s_{o} s_{c2} \eta_{c}$ to it whenepcholds a:feqblock.
Constraints
The two rows below are registered under no name.
- $s_{c1} \left(\sum_{t=1}^{T} p_{t} - 1\right) = 0$
- $\left(s_{c1} \eta,\; s_{c1} \boldsymbol{q},\; s_{c1} \boldsymbol{p}\right) \in \mathcal{K}_{\mathrm{relent}}$, which states $\eta \geq \sum_{t=1}^{T} p_{t} \ln(p_{t} / q_{t})$. Under
LogEntropyPoolingthe reference is $s_{c1} \boldsymbol{1}$ in place of $s_{c1} \boldsymbol{q}$, so the row states $\eta \geq \sum_{t=1}^{T} p_{t} \ln(p_{t})$.
ep_jump_views! registers every further row of the model, and its own # JuMP formulation names them.
Objective
Minofobj_exprunderExpEntropyPooling.Minofobj_exprless $s_{o} \boldsymbol{p}^{\intercal} \ln(\boldsymbol{q})$ underLogEntropyPooling. The subtraction turns the cone's $\sum_{t} p_{t} \ln(p_{t})$ into the divergence, so both branches minimise the same quantity.
Relaxation
The encoding is not exact: the entries below bound the quantity instead of reproducing it, and the bound is tight only under the condition stated here.
- The bound is on
obj_expr, and it lies above the divergence of the exactly constrained problem.ep_jump_views!relaxes the:feqrows with a penalised slack, and the penalty entersobj_expr. - The bound is tight when that slack is zero, which holds when the
:feqrows and the views can be met together, and $s_{c2}$ is large enough to pull the slack down.
Where:
- $\boldsymbol{q}$: $T \times 1$ prior probabilities of the observations, summing to one.
- $\boldsymbol{p}$: $T \times 1$ posterior probabilities of the observations, summing to one. They are the unknown of the entropy pooling problem.
- $T$: Number of observations.
- $s_{c1}$: Constraint scale of the entropy pooling optimiser. It multiplies both sides of a row, so a positive value leaves the feasible set unchanged.
- $s_{c2}$: Slack penalty of the fixed equality rows. It weights the norm of the slack in the objective, so a larger value holds those rows tighter.
- $s_{o}$: Objective scale of the entropy pooling optimiser. It multiplies the objective, so a positive value leaves the argument of the optimum unchanged.
- $\eta$: Epigraph variable that bounds the divergence from above. Its model key is
t. - $\eta_{c}$: Norm of the fixed equality slack, which
ep_jump_views!creates under the model keytc. - $\mathcal{K}_{\mathrm{relent}}$: Relative entropy cone,
JuMP.MOI.RelativeEntropyCone(2T + 1).
Arguments
w: Prior weights (length = number of observations).epc: Dictionary of entropy pooling constraints, mapping keys to(lhs, rhs)pairs.tvs: Tail view constraints.opt: Entropy pooling optimiser.
Validation
- One configuration of
opt.slvsolves the model. Otherwise anErrorExceptionis raised.
Returns
pw::StatsBase.ProbabilityWeights: Posterior probability weights satisfying the constraints.
Related
References
- [1] D. Cajas. Entropy Pooling with CVaR and EVaR Views. Available at SSRN 7120258 (2026).
PortfolioOptimisers.ep_refine_iters — Function
ep_refine_iters(tv::AbstractEntropyPoolingTailView)
ep_refine_iters(tvs::VecEPTV)Read the number of re-solves a tail view carrier asks entropy_pooling for.
A carrier whose rows are fixed at construction asks for none. A sequential carrier asks for the iters its formulation holds, and a vector of carriers asks for the largest number among its entries, so one loop serves every sequential view of the model.
Arguments
tv: Tail view constraint.tvs: Tail view constraints.
Returns
iters::Integer: Number of re-solves, zero for a carrier with fixed rows.
Related
ep_refine_tail_view(tv::AbstractSequentialTailViewConstraint, w::VecNum)Re-read the surrogate row of a sequential tail view at a posterior, and say whether the row it held was already tight there.
Algorithm
- Return
tvandtruewhere the primal side is empty. The view is then convex, its dual blocks are exact, and there is nothing to re-read. - Clamp
wbelow at zero and normalise it to sum to one. A conic solver returns a posterior whose smallest entries sit a rounding error below zero, and the searches behind the rows refuse a negative probability. - For each asset of the primal side, read its bound at
wwithep_tail_surrogate_row, and accumulate the coefficient-weighted sum of the bounds into a new rowc,b. The value of the new row atwis the coefficient-weighted sum of the measures there. - Read the gap between the row
tvheld and the new one atw. The old row bounds the same sum from the same side, so the gap is the slack the last solve left. - Return the carrier with the new row, and whether the gap is within
tolof the larger of the target and the largest loss the primal side names.
Arguments
tv: Sequential tail view constraint.w: Posterior probabilities of the last solve.
Returns
tv::AbstractSequentialTailViewConstraint: The carrier with its row re-read atw.tight::Bool: Whether the rowtvheld before the call was tight atw.
Related
PortfolioOptimisers.ep_refine_tail_view — Method
ep_refine_tail_view(tv::AbstractEntropyPoolingTailView, w::VecNum)Re-read a tail view carrier at a posterior, and say whether its rows were already tight there.
A carrier whose rows are fixed at construction is returned unchanged, and is always tight. A sequential carrier re-reads the multipliers of its primal side at w, which is what tightens its surrogate row between two solves of entropy_pooling; its method lives beside it in src/10_Prior/06_EntropyPooling/03_EntropyPoolingPrior.jl.
Arguments
tv: Tail view constraint.w: Posterior probabilities of the last solve.
Returns
tv::AbstractEntropyPoolingTailView: The carrier to solve with next.tight::Bool: Whether the rowstvheld before the call were tight atw, within the tolerance the carrier holds.
Related
PortfolioOptimisers.ep_sigma_views! — Function
ep_sigma_views!(sigma_views::LinearConstraintEstimator, epc::AbstractDict,
pr::AbstractPriorResult, sets::UniverseSets; strict::Bool = false)Add the variance views of a group to the entropy pooling constraint dictionary.
ep_sigma_views! parses variance view equations from a LinearConstraintEstimator, replaces any prior references with their actual values, and constructs the corresponding constraints for entropy pooling. The constraints are then added to the entropy pooling constraint dictionary epc. The statistic is the variance of the posterior distribution, not the value at risk, which the var_views family holds.
The variance is quadratic in the returns and linear in the posterior probabilities only once the mean is a constant. This method therefore returns the assets whose mean fix_mu! must hold at the prior, so a variance view does not move the mean it is measured about.
Mathematical definition
The row states the posterior second central moment about the prior mean, which is linear in the posterior probabilities:
\[\begin{align} \mathrm{Var}_{\boldsymbol{p}}[x_{i}] &= \sum_{t=1}^{T} p_{t} \left(x_{t,\,i} - \mu_{i}\right)^{2}\,, \\ \sum_{i=1}^{N} a_{k,\,i} \mathrm{Var}_{\boldsymbol{p}}[x_{i}] &\lessgtr B_{k}\,, \quad \forall\, k = 1,\ldots,K\,. \end{align}\]
The identity holds only while the posterior mean of asset $i$ equals $\mu_{i}$, which is why the assets this method names are handed to fix_mu!.
Where:
- $\boldsymbol{p}$: $T \times 1$ posterior probabilities of the observations, summing to one. They are the unknown of the entropy pooling problem.
- $x_{t,\,i}$: Return of asset $i$ at observation $t$.
- $\mu_{i}$: Prior mean of asset $i$. It is a constant of the view, and a lower moment view or a fixing row holds the posterior mean at it.
- $T$: Number of observations.
- $N$: Number of assets.
- $\boldsymbol{B}$: Constraint response vector.
- $a_{k,\,i}$: Coefficient asset $i$ takes in view $k$.
- $K$: Number of views the group states.
Algorithm
- Parse the view equations of
sigma_views.val, giving oneParsingResultper view. - Replace every group name by the assets it spans.
- Replace every
prior(...)reference by the prior variance, throughreplace_prior_views. - Turn the parsed views into the linear constraint blocks
lcs, one for:ineqand one for:eq. Understrict = falseevery row of the group can drop, andlcsis thennothing: the group states no view, and the call returns ato_fixthat names no asset. - Build
tmp, the squared deviations of every observation from the prior mean, transposed so a row oflcsmultiplies it from the left. - For each block present, add
A * tmpagainstBunder that key withadd_ep_constraint!, and mark into_fixevery asset the block names.
Arguments
sigma_views: Variance view constraints.epc: Dictionary of entropy pooling constraints, mapping keys to(lhs, rhs)pairs.pr: Prior result containing asset return information.sets: Asset set mapping asset names to indices.strict: Iftrue, throws error for missing assets; otherwise, issue warnings.
Returns
to_fix::BitVector: Boolean vector indicating which assets require their mean to be fixed.
Related
add_ep_constraint!replace_prior_viewsget_pr_value: reads the prior variance aprior(...)reference resolves to.fix_mu!: consumes theto_fixthis method returns.fix_sigma!MeucciEntropyPoolingPrior
PortfolioOptimisers.fix_sigma! — Function
fix_sigma!(epc::AbstractDict, fixed::AbstractVector, to_fix::BitVector,
pr::AbstractPriorResult)Hold the variance of the named assets at the prior value.
fix_sigma! identifies assets in to_fix that are not yet fixed (i.e., not present in fixed), and adds constraints to the entropy pooling constraint dictionary epc to fix their variance to the prior value. This ensures that higher moment views (e.g., skewness, kurtosis, correlation) do not inadvertently alter the variance of these assets. The function updates fixed in-place to reflect the newly fixed assets.
The rows go in under the :feq key, which the optimiser relaxes with a penalised slack rather than enforcing exactly. A fixing row is a wish, not a view: it competes with the views that were asked for, and it yields where the two cannot both hold.
Mathematical definition
The posterior second central moment of every named asset, taken about the prior mean, is held at the prior variance:
\[\sum_{t=1}^{T} p_{t} \left(x_{t,\,i} - \mu_{i}\right)^{2} = \sigma_{i}^{2}\,, \quad \forall\, i \in \mathcal{F}\,.\]
Where:
- $\boldsymbol{p}$: $T \times 1$ posterior probabilities of the observations, summing to one. They are the unknown of the entropy pooling problem.
- $x_{t,\,i}$: Return of asset $i$ at observation $t$.
- $\mu_{i}$: Prior mean of asset $i$. It is a constant of the view, and a lower moment view or a fixing row holds the posterior mean at it.
- $\sigma_{i}^{2}$: Prior variance of asset $i$. It is a constant of the view, and a lower moment view or a fixing row holds the posterior variance at it.
- $T$: Number of observations.
- $\mathcal{F}$: Assets named by
to_fixthatfixeddoes not already hold.
Algorithm
- Read the prior variances, the diagonal of
pr.sigma, intosigma. - Read the assets that
to_fixnames andfixeddoes not already hold intofix. - Return when
fixnames no asset. - Add one
:feqrow per named asset, the squared deviations of that asset from its prior mean againstsigma[fix], withadd_ep_constraint!. - Mark the named assets in
fixed, so a later call adds no second row for them.
Arguments
epc: Dictionary of entropy pooling constraints, mapping keys to(lhs, rhs)pairs.fixed: Boolean vector indicating which assets have their variance fixed.to_fix: Boolean vector indicating which assets should have their variance fixed.pr: Prior result containing asset return information.
Returns
nothing: The function mutatesepcandfixedin-place.
Related
add_ep_constraint!ep_sigma_views!fix_mu!: the same rule, one moment lower.MeucciEntropyPoolingPrior
PortfolioOptimisers.ep_cov_views! — Function
ep_cov_views!(cov_views::LinearConstraintEstimator, epc::AbstractDict,
pr::AbstractPriorResult, sets::UniverseSets; strict::Bool = false)Add the covariance views of a group to the entropy pooling constraint dictionary.
ep_cov_views! parses covariance view equations from a LinearConstraintEstimator, replaces any prior references with their actual values, and constructs the corresponding linear constraints for entropy pooling. The constraints are then added to the entropy pooling constraint dictionary epc. The statistic is the covariance of the posterior distribution, not the correlation, which the rho_views family holds.
The covariance is a product of returns and is linear in the posterior probabilities only once both means are constants. This method therefore returns the assets whose mean and variance fix_mu! and fix_sigma! must hold at the prior, so a covariance view does not move the lower moments it is measured about.
Mathematical definition
The row states the posterior cross moment about the prior means, which is linear in the posterior probabilities:
\[\begin{align} \mathrm{Cov}_{\boldsymbol{p}}[x_{i}, x_{j}] &= \sum_{t=1}^{T} p_{t} x_{t,\,i} x_{t,\,j} - \mu_{i} \mu_{j}\,, \\ c\, \mathrm{Cov}_{\boldsymbol{p}}[x_{i}, x_{j}] &\lessgtr b\,, \end{align}\]
which the body writes with the constants gathered on the right:
\[\begin{align} d\, c \sum_{t=1}^{T} p_{t} x_{t,\,i} x_{t,\,j} &\lessgtr d \left(c\, \mu_{i} \mu_{j} + b\right)\,. \end{align}\]
Where:
- $\boldsymbol{p}$: $T \times 1$ posterior probabilities of the observations, summing to one. They are the unknown of the entropy pooling problem.
- $x_{t,\,i}$: Return of asset $i$ at observation $t$.
- $\mu_{i}$: Prior mean of asset $i$. It is a constant of the view, and a lower moment view or a fixing row holds the posterior mean at it.
- $T$: Number of observations.
- $c$: Coefficient the view gives the pair.
- $b$: Target of the view, one value per spanned asset pair.
- $d$: Sign that
comparison_sign_ineq_flagreads from the operator, so every inequality row reachesepcin the sense the:ineqkey states.
The identity holds only while the posterior means of assets $i$ and $j$ equal $\mu_{i}$ and $\mu_{j}$, which is why the assets this method names are handed to fix_mu! and fix_sigma!.
Algorithm
- Parse the view equations of
cov_views.val, giving oneParsingResultper view. - Replace every group name by the assets it spans, keeping a pair view a pair view.
- Replace every
prior(a, b)reference by the prior covariance, throughreplace_coprior_views. Each view is now aRhoParsingResultcarrying its index pairs. - For each view in turn, drop it when step 3 left it with no pair, and raise unless it names exactly one.
- Read the sign
dand the inequality flag from the operator withcomparison_sign_ineq_flag. - Read the index pair
(i, j), and buildAi, the product of the two return columns scaled bydand the view's coefficient. - Build
Bi, the target moved by the product of the prior means, scaled the same way. A single asset pair gives a scalar, which is wrapped into a one-element vector; a group pair gives one entry per spanned pair. - Add the row against
Biunder:ineqor:eqwithadd_ep_constraint!, and mark both assets of the pair into_fix.
Arguments
cov_views: Covariance view constraints.epc: Dictionary of entropy pooling constraints, mapping keys to(lhs, rhs)pairs.pr: Prior result containing asset return information.sets: Asset set mapping asset names to indices.strict: Iftrue, throws error for missing assets; otherwise, issue warnings.
Validation
- Every view names exactly one asset pair. A view that mixes pairs raises an
ArgumentError. A view left with no pair, because every pair it named holds an asset the universe does not, is dropped with a report understrict = false;strict = truehas already raised by then.
Returns
to_fix::BitVector: Boolean vector indicating which assets require their mean and variance to be fixed.
Related
add_ep_constraint!replace_coprior_viewsRhoParsingResultget_pr_value: reads the prior covariance aprior(a, b)reference resolves to.fix_mu!,fix_sigma!: consume theto_fixthis method returns.ep_rho_views!: the same rule on the correlation.MeucciEntropyPoolingPriorcomparison_sign_ineq_flag
PortfolioOptimisers.ep_rho_views! — Function
ep_rho_views!(rho_views::LinearConstraintEstimator, epc::AbstractDict,
pr::AbstractPriorResult, sets::UniverseSets; strict::Bool = false)Add the correlation views of a group to the entropy pooling constraint dictionary.
ep_rho_views! parses correlation view equations from a LinearConstraintEstimator, replaces any prior references with their actual values, and constructs the corresponding linear constraints for entropy pooling. The constraints are then added to the entropy pooling constraint dictionary epc. The statistic is the correlation of the posterior distribution, not the covariance, which the cov_views family holds.
The correlation is a covariance divided by two standard deviations, and it is linear in the posterior probabilities only once both means and both variances are constants. This method therefore returns the assets whose mean and variance fix_mu! and fix_sigma! must hold at the prior, so a correlation view does not move the lower moments it is measured about.
Mathematical definition
The row states the posterior cross moment about the prior means, with the target multiplied by the prior standard deviations, which is linear in the posterior probabilities:
\[\begin{align} \rho_{\boldsymbol{p}}[x_{i}, x_{j}] &= \dfrac{\sum_{t=1}^{T} p_{t} x_{t,\,i} x_{t,\,j} - \mu_{i} \mu_{j}}{\sigma_{i} \sigma_{j}}\,, \\ c\, \rho_{\boldsymbol{p}}[x_{i}, x_{j}] &\lessgtr b\,, \end{align}\]
which the body writes with the constants gathered on the right:
\[\begin{align} d\, c \sum_{t=1}^{T} p_{t} x_{t,\,i} x_{t,\,j} &\lessgtr d \left(c\, \mu_{i} \mu_{j} + b\, \sigma_{i} \sigma_{j}\right)\,. \end{align}\]
Where:
- $\boldsymbol{p}$: $T \times 1$ posterior probabilities of the observations, summing to one. They are the unknown of the entropy pooling problem.
- $x_{t,\,i}$: Return of asset $i$ at observation $t$.
- $\mu_{i}$: Prior mean of asset $i$. It is a constant of the view, and a lower moment view or a fixing row holds the posterior mean at it.
- $\sigma_{i}^{2}$: Prior variance of asset $i$. It is a constant of the view, and a lower moment view or a fixing row holds the posterior variance at it.
- $T$: Number of observations.
- $\sigma_{i}$: Prior standard deviation of asset $i$, the positive root of $\sigma_{i}^{2}$.
- $c$: Coefficient the view gives the pair.
- $b$: Target of the view, one value per spanned asset pair, in $[-1, 1]$.
- $d$: Sign that
comparison_sign_ineq_flagreads from the operator, so every inequality row reachesepcin the sense the:ineqkey states.
The identity holds only while the posterior means and variances of assets $i$ and $j$ equal the prior ones, which is why the assets this method names are handed to fix_mu! and fix_sigma!.
Algorithm
- Parse the view equations of
rho_views.val, giving oneParsingResultper view. - Replace every group name by the assets it spans, keeping a pair view a pair view.
- Replace every
prior(a, b)reference by the prior correlation, throughreplace_coprior_views. Each view is now aRhoParsingResultcarrying its index pairs. - Read the prior variances, the diagonal of
pr.sigma, intosigma. - For each view in turn, drop it when step 3 left it with no pair, raise unless it names exactly one, and raise unless every target lies in $[-1, 1]$.
- Read the sign
dand the inequality flag from the operator withcomparison_sign_ineq_flag. - Read the index pair
(i, j), and buildsigma_ij, the root of the product of the two prior variances. - Build
Ai, the product of the two return columns scaled bydand the view's coefficient. - Build
Bi, the target multiplied bysigma_ijand moved by the product of the prior means, scaled the same way. A single asset pair gives a scalar, which is wrapped into a one-element vector; a group pair gives one entry per spanned pair. - Add the row against
Biunder:ineqor:eqwithadd_ep_constraint!, and mark both assets of the pair into_fix.
Arguments
rho_views: Correlation view constraints.epc: Dictionary of entropy pooling constraints, mapping keys to(lhs, rhs)pairs.pr: Prior result containing asset return information.sets: Asset set mapping asset names to indices.strict: Iftrue, throws error for missing assets; otherwise, issue warnings.
Validation
- Every view names exactly one asset pair. A view that mixes pairs raises an
ArgumentError. A view left with no pair, because every pair it named holds an asset the universe does not, is dropped with a report understrict = false;strict = truehas already raised by then. - Every target lies in $[-1, 1]$. A target outside that range raises an
ArgumentError.
Returns
to_fix::BitVector: Boolean vector indicating which assets require their mean and variance to be fixed.
Related
add_ep_constraint!replace_coprior_viewsRhoParsingResultget_pr_value: reads the prior correlation aprior(a, b)reference resolves to.fix_mu!,fix_sigma!: consume theto_fixthis method returns.ep_cov_views!: the same rule on the covariance.MeucciEntropyPoolingPriorcomparison_sign_ineq_flag
PortfolioOptimisers.ep_sk_views! — Function
ep_sk_views!(skew_views::LinearConstraintEstimator, epc::AbstractDict,
pr::AbstractPriorResult, sets::UniverseSets; strict::Bool = false)Add the skewness views of a group to the entropy pooling constraint dictionary.
ep_sk_views! parses skewness view equations from a LinearConstraintEstimator, replaces any prior references with their actual values, and constructs the corresponding linear constraints for entropy pooling. The constraints are then added to the entropy pooling constraint dictionary epc. The statistic is the standardised third central moment of the posterior distribution.
The skewness is a third central moment divided by a cube of the standard deviation, and it is linear in the posterior probabilities only once the mean and the variance are constants. This method therefore returns the assets whose mean and variance fix_mu! and fix_sigma! must hold at the prior, so a skewness view does not move the lower moments it is measured about.
Mathematical definition
The third central moment expands into raw moments, and the two lowest of them are the prior constants, so what remains is linear in the posterior probabilities:
\[\begin{align} \mathrm{E}_{\boldsymbol{p}}\!\left[(x_{i} - \mu_{i})^{3}\right] &= \sum_{t=1}^{T} p_{t} x_{t,\,i}^{3} - 3 \mu_{i} \sigma_{i}^{2} - \mu_{i}^{3}\,, \\ \mathrm{Skew}_{\boldsymbol{p}}[x_{i}] &= \dfrac{\mathrm{E}_{\boldsymbol{p}}\!\left[(x_{i} - \mu_{i})^{3}\right]}{\left(\sigma_{i}^{2}\right)^{3/2}} = \sum_{t=1}^{T} p_{t} \dfrac{x_{t,\,i}^{3} - \mu_{i}^{3} - 3 \mu_{i} \sigma_{i}^{2}}{\left(\sigma_{i}^{2}\right)^{3/2}}\,, \\ \sum_{i=1}^{N} a_{k,\,i} \mathrm{Skew}_{\boldsymbol{p}}[x_{i}] &\lessgtr B_{k}\,, \quad \forall\, k = 1,\ldots,K\,. \end{align}\]
The second line uses $\sum_{t} p_{t} = 1$ to carry the two constants inside the sum, which is the form the body builds.
Where:
- $\boldsymbol{p}$: $T \times 1$ posterior probabilities of the observations, summing to one. They are the unknown of the entropy pooling problem.
- $x_{t,\,i}$: Return of asset $i$ at observation $t$.
- $\mu_{i}$: Prior mean of asset $i$. It is a constant of the view, and a lower moment view or a fixing row holds the posterior mean at it.
- $\sigma_{i}^{2}$: Prior variance of asset $i$. It is a constant of the view, and a lower moment view or a fixing row holds the posterior variance at it.
- $T$: Number of observations.
- $N$: Number of assets.
- $\boldsymbol{B}$: Constraint response vector.
- $a_{k,\,i}$: Coefficient asset $i$ takes in view $k$.
- $K$: Number of views the group states.
The identity holds only while the posterior mean and variance of asset $i$ equal $\mu_{i}$ and $\sigma_{i}^{2}$, which is why the assets this method names are handed to fix_mu! and fix_sigma!.
Algorithm
- Parse the view equations of
skew_views.val, giving oneParsingResultper view. - Replace every group name by the assets it spans.
- Replace every
prior(...)reference by the prior skewness, throughreplace_prior_views. - Turn the parsed views into the linear constraint blocks
lcs, one for:ineqand one for:eq. Understrict = falseevery row of the group can drop, andlcsis thennothing: the group states no view, and the call returns ato_fixthat names no asset. - Read the prior variances, the diagonal of
pr.sigma, intosigma. - Build
tmp, the standardised third moment contribution of every observation, transposed so a row oflcsmultiplies it from the left. - For each block present, add
A * tmpagainstBunder that key withadd_ep_constraint!, and mark into_fixevery asset the block names.
Arguments
skew_views: Skewness view constraints.epc: Dictionary of entropy pooling constraints, mapping keys to(lhs, rhs)pairs.pr: Prior result containing asset return information.sets: Asset set mapping asset names to indices.strict: Iftrue, throws error for missing assets; otherwise, issue warnings.
Returns
to_fix::BitVector: Boolean vector indicating which assets require their mean and variance to be fixed.
Related
add_ep_constraint!replace_prior_viewsget_pr_value: reads the prior skewness aprior(...)reference resolves to.fix_mu!,fix_sigma!: consume theto_fixthis method returns.ep_kt_views!: the same rule, one moment higher.MeucciEntropyPoolingPrior
PortfolioOptimisers.ep_kt_views! — Function
ep_kt_views!(kurtosis_views::LinearConstraintEstimator, epc::AbstractDict,
pr::AbstractPriorResult, sets::UniverseSets; strict::Bool = false)Add the kurtosis views of a group to the entropy pooling constraint dictionary.
ep_kt_views! parses kurtosis view equations from a LinearConstraintEstimator, replaces any prior references with their actual values, and constructs the corresponding linear constraints for entropy pooling. The constraints are then added to the entropy pooling constraint dictionary epc. The statistic is the standardised fourth central moment of the posterior distribution.
The kurtosis is a fourth central moment divided by a square of the variance, and it is linear in the posterior probabilities only once the mean and the variance are constants. This method therefore returns the assets whose mean and variance fix_mu! and fix_sigma! must hold at the prior, so a kurtosis view does not move the lower moments it is measured about.
Mathematical definition
The fourth central moment expands into raw moments, and every constant of the expansion is a prior one, so what remains is linear in the posterior probabilities:
\[\begin{align} \mathrm{E}_{\boldsymbol{p}}\!\left[(x_{i} - \mu_{i})^{4}\right] &= \sum_{t=1}^{T} p_{t} \left(x_{t,\,i}^{4} - 4 \mu_{i} x_{t,\,i}^{3} + 6 \mu_{i}^{2} x_{t,\,i}^{2} - 3 \mu_{i}^{4}\right)\,, \\ \mathrm{Kurt}_{\boldsymbol{p}}[x_{i}] &= \dfrac{\mathrm{E}_{\boldsymbol{p}}\!\left[(x_{i} - \mu_{i})^{4}\right]}{\left(\sigma_{i}^{2}\right)^{2}}\,, \\ \sum_{i=1}^{N} a_{k,\,i} \mathrm{Kurt}_{\boldsymbol{p}}[x_{i}] &\lessgtr B_{k}\,, \quad \forall\, k = 1,\ldots,K\,. \end{align}\]
The first line uses $\sum_{t} p_{t} = 1$ to carry the constant $3 \mu_{i}^{4}$ inside the sum, which is the form the body builds.
Where:
- $\boldsymbol{p}$: $T \times 1$ posterior probabilities of the observations, summing to one. They are the unknown of the entropy pooling problem.
- $x_{t,\,i}$: Return of asset $i$ at observation $t$.
- $\mu_{i}$: Prior mean of asset $i$. It is a constant of the view, and a lower moment view or a fixing row holds the posterior mean at it.
- $\sigma_{i}^{2}$: Prior variance of asset $i$. It is a constant of the view, and a lower moment view or a fixing row holds the posterior variance at it.
- $T$: Number of observations.
- $N$: Number of assets.
- $\boldsymbol{B}$: Constraint response vector.
- $a_{k,\,i}$: Coefficient asset $i$ takes in view $k$.
- $K$: Number of views the group states.
The identity holds only while the posterior mean and variance of asset $i$ equal $\mu_{i}$ and $\sigma_{i}^{2}$, which is why the assets this method names are handed to fix_mu! and fix_sigma!.
Algorithm
- Parse the view equations of
kurtosis_views.val, giving oneParsingResultper view. - Replace every group name by the assets it spans.
- Replace every
prior(...)reference by the prior kurtosis, throughreplace_prior_views. - Turn the parsed views into the linear constraint blocks
lcs, one for:ineqand one for:eq. Understrict = falseevery row of the group can drop, andlcsis thennothing: the group states no view, and the call returns ato_fixthat names no asset. - Build
X_sqandmu_sq, the squares of the returns and of the prior means. - Build
tmp, the standardised fourth moment contribution of every observation, transposed so a row oflcsmultiplies it from the left. - For each block present, add
A * tmpagainstBunder that key withadd_ep_constraint!, and mark into_fixevery asset the block names.
Arguments
kurtosis_views: Kurtosis view constraints.epc: Dictionary of entropy pooling constraints, mapping keys to(lhs, rhs)pairs.pr: Prior result containing asset return information.sets: Asset set mapping asset names to indices.strict: Iftrue, throws error for missing assets; otherwise, issue warnings.
Returns
to_fix::BitVector: Boolean vector indicating which assets require their mean and variance to be fixed.
Related
add_ep_constraint!replace_prior_viewsget_pr_value: reads the prior kurtosis aprior(...)reference resolves to.fix_mu!,fix_sigma!: consume theto_fixthis method returns.ep_sk_views!: the same rule, one moment lower.MeucciEntropyPoolingPrior
PortfolioOptimisers.ep_jump_views! — Function
ep_jump_views!(model::JuMP.Model, x, obj_expr, epc::AbstractDict, tvs::VecEPTV,
sc1::Number, sc2::Number, so::Number)Add every view constraint of an entropy pooling problem to a JuMP model.
ep_jump_views! is the shared body of the two JuMPEntropyPooling formulations: they differ only in how they represent the divergence, and agree on every view. It adds the linear rows of epc, relaxes the fixed equalities with a norm one cone bounded slack, and hands each tail view to add_ep_tail_view!.
Algorithm
- Add the row
ceqwhenepcholds an:eqblock. - Add the row
cineqwhenepcholds an:ineqblock. - Add the row
ccvareqwhenepcholds a:cvar_eqblock. - When
epcholds a:feqblock, create the slackcand its normtc, add the rowcfeqthat lets the block miss byc, bound the norm ofcbytc, and add the penaltyso * sc2 * tctoobj_expr. - Hand each tail view of
tvstoadd_ep_tail_view!in turn.
JuMP formulation
Variables
x: $\boldsymbol{p}$, the posterior probabilities, read from the model.tc: $\eta_{c}$, the norm of the fixed equality slack, created whenepcholds a:feqblock.c: $\boldsymbol{c}$, the fixed equality slack, one entry per row of the:feqblock, created withtc.
Constraints
ceq: $s_{c1} \left(\mathbf{A}_{\mathrm{eq}} \boldsymbol{p} - \boldsymbol{B}_{\mathrm{eq}}\right) = 0$cineq: $s_{c1} \left(\mathbf{A}_{\mathrm{ineq}} \boldsymbol{p} - \boldsymbol{B}_{\mathrm{ineq}}\right) \leq 0$ccvareq: $s_{c1} \left(\mathbf{A}_{\mathrm{cvar}} \boldsymbol{p} - \boldsymbol{B}_{\mathrm{cvar}}\right) = 0$cfeq: $s_{c1} \left(\mathbf{A}_{\mathrm{feq}} \boldsymbol{p} - \boldsymbol{B}_{\mathrm{feq}} - \boldsymbol{c}\right) = 0$- Registered under no name, alongside
cfeq: $\left(s_{c1} \eta_{c},\; s_{c1} \boldsymbol{c}\right) \in \mathcal{K}_{1}$, which states $\eta_{c} \geq \lVert \boldsymbol{c} \rVert_{1}$.
Each of the four named rows is registered only when epc holds the block it carries. add_ep_tail_view! registers every row a tail view needs, in src/10_Prior/06_EntropyPooling/03_EntropyPoolingPrior.jl.
Relaxation
The encoding is not exact: the entries below bound the quantity instead of reproducing it, and the bound is tight only under the condition stated here.
- The bound is on the objective, and it lies above the objective of the problem whose
:feqrows are enforced exactly. The rowscfeqlet the:feqblock miss its right-hand side by $\boldsymbol{c}$, and the penalty $s_{o} s_{c2} \eta_{c}$ is what holds $\boldsymbol{c}$ near zero. - The bound is tight when $\boldsymbol{c}$ is zero, which holds when the
:feqrows and the views can be met together, and $s_{c2}$ is large enough to pull the slack down. A:feqrow states a moment the views must leave where the prior put it, so the two can genuinely disagree, and then the row yields.
Where:
- $\boldsymbol{p}$: $T \times 1$ posterior probabilities of the observations, summing to one. They are the unknown of the entropy pooling problem.
- $\mathbf{A}$: Constraint coefficient matrix.
- $\boldsymbol{B}$: Constraint response vector.
- $\text{eq}$: Subscript for equality constraints.
- $\text{ineq}$: Subscript for inequality constraints.
- $s_{c1}$: Constraint scale of the entropy pooling optimiser. It multiplies both sides of a row, so a positive value leaves the feasible set unchanged.
- $s_{c2}$: Slack penalty of the fixed equality rows. It weights the norm of the slack in the objective, so a larger value holds those rows tighter.
- $s_{o}$: Objective scale of the entropy pooling optimiser. It multiplies the objective, so a positive value leaves the argument of the optimum unchanged.
- $\mathrm{cvar}$, $\mathrm{feq}$: Subscripts for the
:cvar_eqand:feqblocks ofepc. - $\boldsymbol{c}$: Slack of the fixed equality rows, one entry per row of the
:feqblock. - $\eta_{c}$: Bound on the $L_{1}$ norm of $\boldsymbol{c}$.
- $\mathcal{K}_{1}$: Norm one cone,
JuMP.MOI.NormOneCone(N + 1).
Arguments
model: Entropy pooling JuMP model.x: Vector of posterior probability variables.obj_expr: Objective expression, mutated when a fixed equality is relaxed.epc: Dictionary of entropy pooling constraints, mapping keys to(lhs, rhs)pairs.tvs: Tail view constraints.sc1: Constraint scaling factor.sc2: Fixed equality slack penalty.so: Objective scaling factor.
Returns
nothing: The function mutatesmodelandobj_exprin-place.
Related
References
- [1]
- D. Cajas. Entropy Pooling with CVaR and EVaR Views. Available at SSRN 7120258 (2026).
- [2]
- D. Cajas. Entropy Pooling with Relativistic Value at Risk Views. Available at SSRN 7329718 (2026).
- [78]
- A. Meucci. Fully flexible views: theory and practice. Risk 21, 97–102 (2008).
- [79]
- A. Vorobets. Sequential entropy pooling heuristics. Available at SSRN 3936392 (2021).