Entropy Pooling
PortfolioOptimisers.EntropyPoolingPrior — Type
struct EntropyPoolingPrior{__T_pe, __T_mu_views, __T_var_views, __T_cvar_views, __T_evar_views, __T_rlvar_views, __T_sigma_views, __T_sk_views, __T_kt_views, __T_cov_views, __T_rho_views, __T_sets, __T_opt, __T_w, __T_alg, __T_cache} <: AbstractLowOrderPriorEstimator_AFReweights the observations of a prior so that its moments and its tails meet a set of views.
EntropyPoolingPrior is a low order prior estimator that computes the mean and covariance of asset returns using entropy pooling. It supports views on the mean, the variance, the covariance, the correlation, the skewness and the kurtosis, views on the value at risk, the conditional and entropic value at risk views of [1], and the relativistic value at risk views of [2].
The tail views are the difference with MeucciEntropyPoolingPrior. There, a CVaR view is a target the recursive algorithm of Meucci et al. hunts by re-solving the whole entropy pooling problem for each candidate value at risk level, which supports equalities alone. Here each tail view is written as constraints of the single entropy pooling problem, so one solve answers every view, and the operators ==, >= and <= are all available, along with views on the entropic and the relativistic value at risk, and views over several assets of every measure: a positive combination is convex and exact, and a relative view with coefficients of both signs takes the integer formulation or a sequential convex one.
An infeasible view set is not raised on by the OptimEntropyPooling route. The dual of an infeasible set is unbounded, so the minimiser runs away, the posterior collapses onto one observation, and Optim reports the solve as converged. A grossly infeasible view overflows instead, and the non-finite weights reach the moment estimators as an ArgumentError naming Infs or NaNs. Read the result rather than the flag: ens falls to a handful out of the number of observations, one weight sits near one, kld is large, and the posterior statistic the view named is far from its target. entropy_pooling states the mechanism. The JuMPEntropyPooling route does not share it: the solver reports an infeasible model itself.
Algorithm
The constructor derives the prior probabilities, and validates everything else.
- When
wisnothing, derive nothing.priorbuilds the uniform weights1/Tat solve time, one per observation. - When
wis notnothing, normalise it to sum to one, giving the prior probabilities the pooling starts from. A mutablew.valuesis normalised in place withLinearAlgebra.normalize!, and an immutable one is replaced by a newStatsBase.pweightsover the normalised values.
Fields
pe: Prior estimator.
mu_views: Expected returns views estimator or result.
var_views: Value-at-risk views estimator or result.
cvar_views: Conditional value-at-risk views estimator or result.
evar_views: Entropic value-at-risk views estimator or result.
rlvar_views: Relativistic value-at-risk views estimator or result.
sigma_views: Variance views estimator or result.
sk_views: Skewness views estimator or result.
kt_views: Kurtosis views estimator or result.
cov_views: Covariance views estimator or result.
rho_views: Correlation views estimator or result.
sets: Sets used to map estimator values to assets.
opt: Entropy pooling optimisation estimator.
w: Prior observation probability weights, on the observations the wrapped estimator answers, which a wrapped estimator that drops rows makes fewer than the observations it is given. Ifnothing, the wrapped result's ownwis used, and the uniform weights where it carries none.
alg: Entropy pooling algorithm.
cache: Optional partial-fit state. It isnothinguntilpartial_fit!writes one, and the estimator's read-out verb reads it when the caller gives no data matrix. Each propagation channel does one thing with it:factorycarries it unchanged, because a factory call resolves configuration rather than the sample;port_opt_viewslices it to the selected assets by index copy, so the viewed estimator answers over those assets alone; andobs_weights_viewdrops it, because no slice of a state exists on the observation axis. A family whose state has no exact asset slice drops it on both axes and names the reason.
Constructors
EntropyPoolingPrior(; pe::AbstractLowOrderPriorEstimator_A_F_AF = EmpiricalPrior(), mu_views::Option{<:LinearConstraintEstimator} = nothing, var_views::Option{<:VV_VecVV} = nothing, cvar_views::Option{<:CVV_VecCVV} = nothing, evar_views::Option{<:EVV_VecEVV} = nothing, rlvar_views::Option{<:RVV_VecRVV} = nothing, sigma_views::Option{<:LinearConstraintEstimator} = nothing, sk_views::Option{<:LinearConstraintEstimator} = nothing, kt_views::Option{<:LinearConstraintEstimator} = nothing, cov_views::Option{<:LinearConstraintEstimator} = nothing, rho_views::Option{<:LinearConstraintEstimator} = nothing, sets::Option{<:UniverseSets} = nothing, opt::NonCVaREP = OptimEntropyPooling(), w::Option{<:StatsBase.ProbabilityWeights} = nothing, alg::AbstractEntropyPoolingAlgorithm = H1_EntropyPooling(), cache::Option{<:AbstractPartialFitState} = nothing) -> EntropyPoolingPriorKeywords correspond to the struct's fields.
Validation
- If any view constraint is not
nothing,setsmust not benothing. - If
cvar_viewsis notnothing,optmust be aJuMPEntropyPooling. - If a view field is a vector, it must not be empty.
- If
wis notnothing, it must be non-empty and match the number of observations.
Propagated parameters
When factory is called on this type, the following @fprop-tagged fields are automatically propagated:
pe: Recursively updated viafactory.w: Replaced with the incomingObsWeights.
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.sets: Sliced to the selected indices viaport_opt_view.
Observation weight parameters
When obs_weights_view is called on this type, the following fields are automatically indexed to the selected observations:
pe: Recursively indexed viaobs_weights_view.w: Indexed to the selected observations viaobs_weights_view.
View comparison operators
The comparison operators accepted in each view's constraint strings depend on the moment being constrained. An unsupported operator raises a ParseError listing the operators allowed for that view.
mu_views,sigma_views,sk_views,kt_views,cov_views,rho_viewsaccept==,>=and<=.var_views(Value at Risk) accepts only==and>=.cvar_views,evar_viewsandrlvar_viewsaccept==,>=and<=.
Tail views
A tail view needs auxiliary variables, so it is expressed in the JuMP model rather than reduced to rows that multiply the posterior probabilities. Two consequences follow.
optmust be aJuMPEntropyPoolingwhenevercvar_viewsis set, and whenever anevar_viewsorrlvar_viewsentry is anything other than a lower bound underGridEntropicValueatRiskVieworGridRelativisticValueatRiskView, which are the tail formulations that are linear in the posterior probabilities alone.- A view that needs a binary variable — every
IntegerConditionalValueatRiskView, and an upper bound or equality underGridEntropicValueatRiskVieworGridRelativisticValueatRiskView— needs a solver that handles mixed-integer exponential cone programs. ConicRelativisticValueatRiskViewwrites power cones, so its solver must handle the power cone alongside the exponential cone the objective needs.
The alg field of a view group picks the formulation. A single formulation applies to every view in that group, a vector supplies one per view, and nothing lets each view take the cheapest formulation that expresses it exactly: LinearConditionalValueatRiskView, ConicEntropicValueatRiskView and ConicRelativisticValueatRiskView where they apply, IntegerConditionalValueatRiskView, GridEntropicValueatRiskView and GridRelativisticValueatRiskView otherwise.
Tail views at several significance levels
A significance level is part of the statistic, not a detail of the solve: the conditional value at risk at 1% and at 10% are different numbers on the same series. So the level lives on the view rather than on the estimator. var_views, cvar_views, evar_views and rlvar_views each take one ValueatRiskView, ConditionalValueatRiskView, EntropicValueatRiskView or RelativisticValueatRiskView, or a vector of them, and each group carries the alpha its equations are read under. A RelativisticValueatRiskView carries a kappa as well, on the same reasoning: the deformation parameter is part of the statistic. A prior(...) reference inside a group is replaced by the prior value at that group's level.
A tail view group also carries alg, the formulation. For EntropicValueatRiskView that is where the grid of dual variables and the big-M constant live, so a GridEntropicValueatRiskView there gives one group its own pct, K and M. ValueatRiskView has no such field: a value at risk view is linear in the posterior probabilities, so there is no formulation to choose.
Examples
julia> EntropyPoolingPrior(; sets = UniverseSets(; xkey = "nx", dict = Dict("nx" => ["A", "B", "C"])), mu_views = LinearConstraintEstimator(; val = ["A == 0.03", "B + C == 0.04"]))EntropyPoolingPrior 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 mu_views ┼ LinearConstraintEstimator │ val ┼ Vector{String}: ["A == 0.03", "B + C == 0.04"] │ key ┴ nothing var_views ┼ nothing cvar_views ┼ nothing evar_views ┼ nothing rlvar_views ┼ nothing sigma_views ┼ nothing sk_views ┼ nothing kt_views ┼ nothing cov_views ┼ nothing rho_views ┼ nothing sets ┼ UniverseSets │ xkey ┼ String: "nx" │ uxkey ┼ String: "ux" │ tfkey ┼ String: "nf" │ utfkey ┼ String: "uf" │ cfkey ┼ String: "ncf" │ ucfkey ┼ String: "ucf" │ nikey ┼ String: "ni" │ dict ┴ Dict{String, Vector{String}}: Dict("nx" => ["A", "B", "C"]) opt ┼ OptimEntropyPooling │ args ┼ Tuple{}: () │ kwargs ┼ @NamedTuple{}: NamedTuple() │ sc1 ┼ Int64: 1 │ sc2 ┼ Float64: 1000.0 │ alg ┼ ExpEntropyPooling() │ err ┴ nothing w ┼ nothing alg ┴ H1_EntropyPooling()Related
AbstractLowOrderPriorEstimator_AFMeucciEntropyPoolingPriorLinearConditionalValueatRiskViewIntegerConditionalValueatRiskViewConicEntropicValueatRiskViewGridEntropicValueatRiskViewConicRelativisticValueatRiskViewGridRelativisticValueatRiskViewJuMPEntropyPoolingOptimEntropyPoolingAbstractEntropyPoolingAlgorithmfactoryport_opt_viewobs_weights_view
References
- [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).
- [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).
PortfolioOptimisers.prior — Function
prior(pe::EntropyPoolingPrior, X::MatNum, F::Option{<:MatNum} = nothing,
pnl::Option{<:AssetPanel} = nothing; dims::Int = 1, strict::Bool = false,
kwargs...)Compute the entropy pooling prior of asset returns with tail views.
prior orients the data and forwards the estimator's algorithm as a value to ep_prior, which enforces the views in stages or in one optimisation.
Algorithm
- Orient
XandFalongdimswithdims_oriented, so the observations lie in the rows. - Forward
pe.algas a value toep_prior, and return theLowOrderPriorit builds.
Arguments
pe: Entropy pooling prior estimator.X: Asset returns matrix.F: Optional factor returns matrix.pnl: OptionalAssetPanel, the panel the carrier held. A wrapping prior forwards it unchanged, so that it can compose an estimator that is fitted on a panel. An estimator that reads no panel ignores it.dims: Dimension along which the observations lie.strict: Iftrue, throws error for missing assets; otherwise, issue warnings.kwargs...: Additional keyword arguments forwarded to the wrapped prior estimator.
Validation
dims in (1, 2).
Returns
pr::LowOrderPrior: Prior result carrying the posterior probability weights.
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).