Shrunk Expected Returns
PortfolioOptimisers.GrandMean — Type
struct GrandMean <: AbstractShrunkExpectedReturnsTargetFills the shrinkage target with the grand mean of the sample expected returns.
Every element of the target holds the same value, so a shrinkage estimator pulls each asset toward the average of the whole universe. The three targets are each a multiple of the vector of ones, and only the multiplier separates them.
Mathematical definition
\[\begin{align} b_j &= \bar{\mu} = \frac{1}{N} \sum_{i=1}^{N} \hat{\mu}_i\,, \quad j = 1, \ldots, N\,. \end{align}\]
Where:
- $b_j$: $j$-th entry of the shrinkage target vector.
- $\hat{\boldsymbol{\mu}}$: $N \times 1$ vector of sample expected returns, whose $i$-th entry is $\hat{\mu}_i$.
- $N$: Number of assets.
The sample covariance matrix does not enter the form, so this target is the only one of the three that a singular covariance matrix leaves untouched.
Algorithm
The branch of target_mean that this tag selects runs these steps.
- Take the unweighted mean of
mu, givingval. - Return the constant range that repeats
vallength(mu)times.
Constructors
GrandMean() -> GrandMeanExamples
julia> GrandMean()GrandMean()Related
References
- [5] D. Cajas. Advanced Portfolio Optimization: A Cutting-edge Quantitative Approach (Springer Nature Switzerland, 2025). Equation 3.43.
- [25] A. Meucci. Risk and Asset Allocation (Springer Berlin Heidelberg, 2005).
- [26] Y. Feng and D. P. Palomar. A signal processing perspective of financial engineering. Foundations and Trends in Signal Processing 9, 1–231 (2016).
PortfolioOptimisers.VolatilityWeighted — Type
struct VolatilityWeighted <: AbstractShrunkExpectedReturnsTargetFills the shrinkage target with the inverse-covariance-weighted mean of the sample expected returns.
The inverse covariance matrix supplies the weights. Under a diagonal covariance matrix each weight is the reciprocal of the asset's variance, so a riskier asset counts for less. The name says volatility, and the form reads the whole inverse covariance matrix, so an off-diagonal entry moves the target too.
Mathematical definition
\[\begin{align} b_j &= \bar{\mu}_{\mathrm{vol}} = \frac{\boldsymbol{1}^\intercal \hat{\mathbf{\Sigma}}^{-1} \hat{\boldsymbol{\mu}}}{\boldsymbol{1}^\intercal \hat{\mathbf{\Sigma}}^{-1} \boldsymbol{1}}\,, \quad j = 1, \ldots, N\,. \end{align}\]
Where:
- $b_j$: $j$-th entry of the shrinkage target vector.
- $\hat{\boldsymbol{\mu}}$: $N \times 1$ vector of sample expected returns, whose $i$-th entry is $\hat{\mu}_i$.
- $\hat{\mathbf{\Sigma}}$: Estimated covariance matrix.
- $\boldsymbol{1}$: $N \times 1$ vector of ones.
- $N$: Number of assets.
Algorithm
The branch of target_mean that this tag selects runs these steps.
- When
isigmaisnothing, solvesigma \ LinearAlgebra.I, givingisigma. A caller that already holds the inverse passes it, so the solve runs once per estimate at most. - When
muhas one row, flatten it withvec, so that the productisigma * muis defined. - Divide the sum of
isigma * muby the sum ofisigma, givingval. Summing a matrix-vector product is the numerator $\boldsymbol{1}^\intercal \hat{\mathbf{\Sigma}}^{-1} \hat{\boldsymbol{\mu}}$, and summing the matrix is the denominator $\boldsymbol{1}^\intercal \hat{\mathbf{\Sigma}}^{-1} \boldsymbol{1}$. - Return the constant range that repeats
vallength(mu)times.
Constructors
VolatilityWeighted() -> VolatilityWeightedExamples
julia> VolatilityWeighted()VolatilityWeighted()Related
References
- [5] D. Cajas. Advanced Portfolio Optimization: A Cutting-edge Quantitative Approach (Springer Nature Switzerland, 2025). Equation 3.43.
- [25] A. Meucci. Risk and Asset Allocation (Springer Berlin Heidelberg, 2005).
- [26] Y. Feng and D. P. Palomar. A signal processing perspective of financial engineering. Foundations and Trends in Signal Processing 9, 1–231 (2016).
PortfolioOptimisers.MeanSquaredError — Type
struct MeanSquaredError <: AbstractShrunkExpectedReturnsTargetFills the shrinkage target with the trace of the covariance matrix divided by the number of observations.
Every element of the target holds the same value. The target reads a scale off the covariance matrix alone, so the sample expected returns do not enter it. It is the only one of the three targets that a shift of every asset's mean leaves where it was.
Mathematical definition
\[\begin{align} b_j &= \frac{\mathrm{tr}(\hat{\mathbf{\Sigma}})}{T}\,, \quad j = 1, \ldots, N\,. \end{align}\]
Where:
- $b_j$: $j$-th entry of the shrinkage target vector.
- $\mathrm{tr}(\cdot)$: Matrix trace operator.
- $\hat{\mathbf{\Sigma}}$: Estimated covariance matrix.
- $T$: Number of observations.
- $N$: Number of assets.
Algorithm
The branch of target_mean that this tag selects runs these steps.
- Divide the trace of
sigmabyT, givingval.Tis a required keyword of this branch alone. - Return the constant range that repeats
vallength(mu)times.
Constructors
MeanSquaredError() -> MeanSquaredErrorExamples
julia> MeanSquaredError()MeanSquaredError()Related
References
- [5] D. Cajas. Advanced Portfolio Optimization: A Cutting-edge Quantitative Approach (Springer Nature Switzerland, 2025). Equation 3.43.
- [25] A. Meucci. Risk and Asset Allocation (Springer Berlin Heidelberg, 2005).
- [26] Y. Feng and D. P. Palomar. A signal processing perspective of financial engineering. Foundations and Trends in Signal Processing 9, 1–231 (2016).
PortfolioOptimisers.JamesStein — Type
struct JamesStein{__T_tgt} <: AbstractShrunkExpectedReturnsAlgorithmBlends the sample expected returns with the target under an intensity read off the covariance eigenvalues.
The intensity grows with the number of assets and falls with the distance between the sample mean and the target.
Fields
tgt: Shrinkage target.
Constructors
JamesStein(; tgt::AbstractShrunkExpectedReturnsTarget = GrandMean()) -> JamesSteinKeywords correspond to the struct's fields.
Examples
julia> JamesStein()JamesStein tgt ┴ GrandMean()Related
AbstractShrunkExpectedReturnsAlgorithmAbstractShrunkExpectedReturnsTargetBayesSteinBodnarOkhrinParolyamean(me::ShrunkExpectedReturns{<:Any, <:Any, <:JamesStein}, X::MatNum; dims::Int = 1, kwargs...)
References
PortfolioOptimisers.BayesStein — Type
struct BayesStein{__T_tgt} <: AbstractShrunkExpectedReturnsAlgorithmBlends the sample expected returns with the target under an empirical Bayes intensity.
The intensity falls with the inverse-covariance-weighted distance between the sample mean and the target, so a short sample shrinks harder.
Fields
tgt: Shrinkage target.
Constructors
BayesStein(; tgt::AbstractShrunkExpectedReturnsTarget = GrandMean()) -> BayesSteinKeywords correspond to the struct's fields.
Examples
julia> BayesStein()BayesStein tgt ┴ GrandMean()Related
AbstractShrunkExpectedReturnsAlgorithmAbstractShrunkExpectedReturnsTargetJamesSteinBodnarOkhrinParolyamean(me::ShrunkExpectedReturns{<:Any, <:Any, <:BayesStein}, X::MatNum; dims::Int = 1, kwargs...)
References
PortfolioOptimisers.BodnarOkhrinParolya — Type
struct BodnarOkhrinParolya{__T_tgt} <: AbstractShrunkExpectedReturnsAlgorithmCombines the sample expected returns and the target under two coefficients from random matrix theory.
The two coefficients are set separately and neither is a convex weight, so the result is not a blend between the sample mean and the target. It suits a universe whose asset count is a large fraction of its observation count, and it needs more observations than assets.
Fields
tgt: Shrinkage target.
Constructors
BodnarOkhrinParolya(; tgt::AbstractShrunkExpectedReturnsTarget = GrandMean()) -> BodnarOkhrinParolyaKeywords correspond to the struct's fields.
Examples
julia> BodnarOkhrinParolya()BodnarOkhrinParolya tgt ┴ GrandMean()Related
AbstractShrunkExpectedReturnsAlgorithmAbstractShrunkExpectedReturnsTargetJamesSteinBayesSteinmean(me::ShrunkExpectedReturns{<:Any, <:Any, <:BodnarOkhrinParolya}, X::MatNum; dims::Int = 1, kwargs...)
References
PortfolioOptimisers.ShrunkExpectedReturns — Type
struct ShrunkExpectedReturns{__T_me, __T_ce, __T_alg} <: AbstractShrunkExpectedReturnsEstimatorShrinks the sample expected returns toward a target chosen by the shrinkage algorithm.
It holds the three parts the shrinkage needs: a mean estimator, a covariance estimator and a shrinkage algorithm, which carries the target.
Fields
me: Expected returns estimator.
ce: Covariance estimator.
alg: Expected returns shrinkage algorithm.
Constructors
ShrunkExpectedReturns(; me::AbstractExpectedReturnsEstimator = SimpleExpectedReturns(), ce::StatsBase.CovarianceEstimator = PortfolioOptimisersCovariance(), alg::AbstractShrunkExpectedReturnsAlgorithm = JamesStein()) -> ShrunkExpectedReturnsKeywords correspond to the struct's fields.
Propagated parameters
When factory is called on this type, the following @fprop-tagged fields are automatically propagated:
View parameters
When port_opt_view is called on this type, the following @vprop-tagged fields are automatically subset to the selected indices:
me: Recursively viewed viaport_opt_view.ce: Recursively viewed viaport_opt_view.alg: Recursively viewed viaport_opt_view.
Examples
julia> ShrunkExpectedReturns()ShrunkExpectedReturns me ┼ SimpleExpectedReturns │ w ┴ nothing 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) alg ┼ JamesStein │ tgt ┴ GrandMean()Related
AbstractShrunkExpectedReturnsEstimatorAbstractExpectedReturnsEstimatorStatsBase.CovarianceEstimatorAbstractShrunkExpectedReturnsAlgorithmtarget_meanfactoryport_opt_view
References
- [5] D. Cajas. Advanced Portfolio Optimization: A Cutting-edge Quantitative Approach (Springer Nature Switzerland, 2025). Section 3.4.1.
Statistics.mean — Method
Statistics.mean(me::ShrunkExpectedReturns, X::MatNum; dims::Int = 1, kwargs...)Compute shrunk expected returns using the specified estimator.
This method applies a shrinkage algorithm to the sample expected returns, pulling them toward a target to reduce estimation error, especially in high-dimensional settings. No method of this family clamps its coefficients. JamesStein and BayesStein write (1 - alpha) * mu + alpha * b, and nothing holds alpha inside $[0, 1]$, so the result can sit outside the segment that joins the sample mean and the target. BodnarOkhrinParolya sets its two coefficients separately and they do not sum to one.
Mathematical definition
James-Stein shrinkage of the sample expected returns toward the target:
\[\begin{align} \hat{\boldsymbol{\mu}}_{JS} &= (1 - \alpha)\, \hat{\boldsymbol{\mu}} + \alpha\, \boldsymbol{b}\,, \\ \alpha &= \frac{N \bar{\lambda} - 2 \lambda_{\max}}{T \, \lVert \hat{\boldsymbol{\mu}} - \boldsymbol{b} \rVert_2^2}\,. \end{align}\]
Where:
- $\hat{\boldsymbol{\mu}}_{JS}$: James-Stein shrunk expected returns.
- $\hat{\boldsymbol{\mu}}$: $N \times 1$ vector of sample expected returns, whose $i$-th entry is $\hat{\mu}_i$.
- $\boldsymbol{b}$: $N \times 1$ shrinkage target vector, every entry of which holds the same value.
- $\alpha$: Shrinkage intensity, the weight the blend gives the target.
- $\bar{\lambda}$: Mean eigenvalue of the covariance matrix.
- $\lambda_{\max}$: Maximum eigenvalue of the covariance matrix.
- $T$: Number of observations.
- $N$: Number of assets.
Two consequences of the form bound where it is usable.
- $N \bar{\lambda}$ is the trace of the covariance matrix, so $N \bar{\lambda} \leq 2 \lambda_{\max}$ whenever $N \leq 2$. The intensity is then negative and the blend extrapolates away from the target rather than toward it.
- The denominator is zero when the target equals the sample mean.
GrandMeanandVolatilityWeightedboth reduce to the sample mean at $N = 1$, so a one-asset sample raises aDomainErrorunder either of them.MeanSquaredErrordoes not read the sample mean, so it stays finite there.
Algorithm
- Compute the sample expected returns with
me.me, givingmu. - Compute the covariance matrix with
me.ce, givingsigma. - Read
TandNoffsize(X), and swap them whendimsis2. - Compute the shrinkage target with
target_mean, givingb, and transpose it into a row whendimsis1. - Eigendecompose
sigma, givingevals. - Subtract
bfrommu, givingmb, and form the intensityalphafromevals,mb,NandT. - Return the blend
(1 - alpha) * mu + alpha * b.
Arguments
me: Shrunk expected returns estimator.me::ShrunkExpectedReturns{<:Any, <:Any, <:JamesStein}: Use the James-Stein algorithm.me::ShrunkExpectedReturns{<:Any, <:Any, <:BayesStein}: Use the Bayes-Stein algorithm.me::ShrunkExpectedReturns{<:Any, <:Any, <:BodnarOkhrinParolya}: Use the Bodnar-Okhrin-Parolya algorithm.
X: Data matrixobservations × assetsif thedimskeyword does not exist ordims = 1,assets × observationswhendims = 2.dims: Dimension along which to perform the computation.kwargs...: Additional keyword arguments passed to the mean and covariance estimators.
Validation
!iszero(dot(mu - b, mu - b)). TheJamesSteinintensity divides by this denominator, and it is exactly zero when the target equals the sample mean.GrandMeanandVolatilityWeightedboth do so at $N = 1$, and the other two overloads state their own rules for raising.
Returns
mu::ArrNum: Expected returns vectorassets x 1if thedimskeyword does not exist ordims = 2,1 x assetsifdims = 1.
Related
JamesStein: the tag that selects this method.BayesSteinBodnarOkhrinParolyaShrunkExpectedReturnstarget_meanArrNumMatNum
References
Statistics.mean — Method
mean(
me::ShrunkExpectedReturns{<:Any, <:Any, <:BayesStein},
X::AbstractMatrix{<:Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}};
dims,
kwargs...
) -> Any
BayesStein overload of mean(me::ShrunkExpectedReturns, X::MatNum; dims::Int = 1, kwargs...). Shrinks sample returns toward the target using a Bayesian formula with inverse covariance weighting.
Mathematical definition
Bayes-Stein shrinkage of the sample expected returns toward the target:
\[\begin{align} \alpha &= \frac{N + 2}{(N + 2) + T \, (\hat{\boldsymbol{\mu}} - \boldsymbol{b})^\intercal \hat{\mathbf{\Sigma}}^{-1} (\hat{\boldsymbol{\mu}} - \boldsymbol{b})}\,, \\ \hat{\boldsymbol{\mu}}_{BS} &= (1 - \alpha)\hat{\boldsymbol{\mu}} + \alpha \boldsymbol{b}\,. \end{align}\]
Where:
- $\alpha$: Shrinkage intensity, the weight the blend gives the target.
- $\hat{\boldsymbol{\mu}}_{BS}$: Bayes-Stein shrunk expected returns.
- $\hat{\boldsymbol{\mu}}$: $N \times 1$ vector of sample expected returns, whose $i$-th entry is $\hat{\mu}_i$.
- $\boldsymbol{b}$: $N \times 1$ shrinkage target vector, every entry of which holds the same value.
- $\hat{\mathbf{\Sigma}}$: Estimated covariance matrix.
- $T$: Number of observations.
- $N$: Number of assets.
Two consequences of the form separate this intensity from the James-Stein one.
- The quadratic form is non-negative whenever $\hat{\mathbf{\Sigma}}$ is positive semidefinite, so $\alpha$ then lies in $(0, 1]$. This is the only one of the three algorithms whose coefficient is a convex weight without a clamp, and it returns the target exactly when the quadratic form is zero. A covariance estimator that returns an indefinite matrix breaks the bound.
- The quadratic form uses the inverse of the covariance matrix that
me.cereturns. Equation 3.44 of [5] states the same intensity over the bias-corrected matrix $\bar{\mathbf{\Sigma}} = \frac{T-1}{T-N-1} \hat{\mathbf{\Sigma}}$; this method uses $\hat{\mathbf{\Sigma}}$. The correction raises $\alpha$.
Algorithm
- Compute the sample expected returns with
me.me, givingmu. - Compute the covariance matrix with
me.ce, givingsigma. - Read
TandNoffsize(X), and swap them whendimsis2. - Solve
sigma \ LinearAlgebra.I, givingisigma, and pass it totarget_meanso that theVolatilityWeightedbranch does not solve a second time. - Compute the shrinkage target, giving
b, and transpose it into a row whendimsis1. - Flatten
mu - bwithvec, givingmb, and form the intensityalphafrommb,isigma,NandT. - Return the blend
(1 - alpha) * mu + alpha * b.
Related
BayesStein: the tag that selects this method.mean(me::ShrunkExpectedReturns, X::MatNum; dims::Int = 1, kwargs...): the arguments, the return value and the trap the three overloads share.ShrunkExpectedReturnstarget_mean
References
Statistics.mean — Method
mean(
me::ShrunkExpectedReturns{<:Any, <:Any, <:BodnarOkhrinParolya},
X::AbstractMatrix{<:Union{var"#s136", var"#s53"} where {var"#s136"<:Number, var"#s53"<:AbstractJuMPScalar}};
dims,
kwargs...
) -> Any
BodnarOkhrinParolya overload of mean(me::ShrunkExpectedReturns, X::MatNum; dims::Int = 1, kwargs...). Shrinks sample returns toward the target using the Bodnar-Okhrin-Parolya formula, designed for robust high-dimensional estimation. It needs $T > N$: the term $N/(T-N)$ is undefined at $T = N$ and changes sign below it, so a square or wide returns matrix raises a DomainError.
Mathematical definition
Three inverse-covariance-weighted quadratic forms carry the sample mean and the target:
\[\begin{align} u &= \hat{\boldsymbol{\mu}}^\intercal \hat{\mathbf{\Sigma}}^{-1} \hat{\boldsymbol{\mu}}\,, \\ v &= \boldsymbol{b}^\intercal \hat{\mathbf{\Sigma}}^{-1} \boldsymbol{b}\,, \\ w &= \hat{\boldsymbol{\mu}}^\intercal \hat{\mathbf{\Sigma}}^{-1} \boldsymbol{b}\,. \end{align}\]
The two coefficients and the combination follow from them:
\[\begin{align} \alpha &= \frac{(u - N/(T-N))v - w^2}{uv - w^2}\,, \\ \beta &= \frac{(1-\alpha) w}{u}\,, \\ \hat{\boldsymbol{\mu}}_{BOP} &= \alpha \hat{\boldsymbol{\mu}} + \beta \boldsymbol{b}\,. \end{align}\]
Where:
- $u$, $v$, $w$: Inverse-covariance-weighted quadratic forms.
- $\alpha$, $\beta$: Shrinkage coefficients.
- $\hat{\boldsymbol{\mu}}_{BOP}$: Bodnar-Okhrin-Parolya shrunk expected returns.
- $\hat{\boldsymbol{\mu}}$: $N \times 1$ vector of sample expected returns, whose $i$-th entry is $\hat{\mu}_i$.
- $\boldsymbol{b}$: $N \times 1$ shrinkage target vector, every entry of which holds the same value.
- $\hat{\mathbf{\Sigma}}$: Estimated covariance matrix.
- $T$: Number of observations.
- $N$: Number of assets.
Three consequences of the form separate this algorithm from the other two.
- $\alpha$ and $\beta$ are set separately and do not sum to one, so the result is not a point on the segment that joins $\hat{\boldsymbol{\mu}}$ and $\boldsymbol{b}$. Cancelling the $w^2$ term rewrites the coefficient as $\alpha = 1 - \frac{N}{T-N} \frac{v}{uv - w^2}$, so $\alpha < 1$ always, and $\alpha < 0$ exactly when $\frac{N}{T-N} v > uv - w^2$. The combination then extrapolates away from the sample mean.
- $uv - w^2$ is a Cauchy-Schwarz gap in the inner product $\langle \boldsymbol{x}, \boldsymbol{y} \rangle = \boldsymbol{x}^\intercal \hat{\mathbf{\Sigma}}^{-1} \boldsymbol{y}$, so it vanishes exactly when the target is a multiple of the sample mean. At $N = 1$ every vector is such a multiple, so a one-asset sample raises a
DomainErrorunder all three targets. - Every target of this file is a multiple of the vector of ones, so writing $\boldsymbol{b} = c \boldsymbol{1}$ makes $v$ and $w$ scale with $c^2$ and $c$. The factor cancels in $\alpha$, which is therefore the same for the three targets on one sample, and survives in $\beta \boldsymbol{b}$, which is not.
Algorithm
- Compute the sample expected returns with
me.me, givingmu. - Compute the covariance matrix with
me.ce, givingsigma. - Read
TandNoffsize(X), and swap them whendimsis2. - Solve
sigma \ LinearAlgebra.I, givingisigma, and pass it totarget_meanso that theVolatilityWeightedbranch does not solve a second time. - Compute the shrinkage target, giving
b, and transpose it into a row whendimsis1. - Flatten
muandbinto the vectorsvmandvb, which the quadratic forms need whichever waydimsorients the data. - Form the three quadratic forms
u,vandwfromvm,vbandisigma. - Form
alphafromu,v,w,NandT, thenbetafromalpha,wandu. - Return the combination
alpha * mu + beta * b.
Validation
T > N, the estimator's own published condition. The term $N/(T-N)$ is undefined at $T = N$ and negative below it.!iszero(u * v - w^2). Both coefficients divide by this Cauchy-Schwarz gap, and it is exactly zero when the target is a multiple of the sample mean. Every vector is such a multiple at $N = 1$.
Related
BodnarOkhrinParolya: the tag that selects this method.mean(me::ShrunkExpectedReturns, X::MatNum; dims::Int = 1, kwargs...): the arguments, the return value and the trap the three overloads share.ShrunkExpectedReturnstarget_mean
References
References
- [5]
- D. Cajas. Advanced Portfolio Optimization: A Cutting-edge Quantitative Approach (Springer Nature Switzerland, 2025).
- [25]
- A. Meucci. Risk and Asset Allocation (Springer Berlin Heidelberg, 2005).
- [26]
- Y. Feng and D. P. Palomar. A signal processing perspective of financial engineering. Foundations and Trends in Signal Processing 9, 1–231 (2016).
- [27]
- P. Jorion. Bayes-Stein estimation for portfolio analysis. The Journal of Financial and Quantitative Analysis 21, 279–292 (1986).
- [28]
- T. Bodnar, O. Okhrin and N. Parolya. Optimal shrinkage estimator for high-dimensional mean vector. Journal of Multivariate Analysis 170, 63–79 (2019).