pyvallocation.bayesian module
Bayesian utilities complement the shrinkage estimators by providing posterior updates for both means and covariances. Highlights include:
pyvallocation.bayesian.NIWPosterior- Normal-Inverse-Wishart updates used across the examples and tests.pyvallocation.bayesian.RobustBayesPosterior- convenient wrapper that exposes mean-uncertainty covariances for robust optimisation.Quantile wrappers for chi-square distributions used when sizing Bayesian uncertainty sets.
Robust-Bayesian uncertainty
The NIW posterior implies a closed-form covariance of the mean \(S_{\\mu}\) (see [Meucci, 2005]):
Use pyvallocation.bayesian.RobustBayesPosterior to access S_mu and
its horizon-scaled variants (log or simple returns) for robust optimisation.
- class pyvallocation.bayesian.NIWParams(T1, mu1, nu1, sigma1)[source]
Bases:
objectA container for the parameters of a Normal-Inverse-Wishart (NIW) posterior distribution. :no-inheritance:
These parameters are the result of a Bayesian update, combining an NIW prior with market data, as detailed in Meucci (2005). The formulas for these posterior parameters are given in Eqs. (11)-(14).
- Parameters:
T1 (int)
mu1 (numpy.typing.NDArray.numpy.floating | pandas.Series.numpy.floating)
nu1 (int)
sigma1 (numpy.typing.NDArray.numpy.floating | pandas.DataFrame.numpy.floating)
- T1: int
- mu1: numpy.typing.NDArray.numpy.floating | pandas.Series.numpy.floating
- nu1: int
- sigma1: numpy.typing.NDArray.numpy.floating | pandas.DataFrame.numpy.floating
- class pyvallocation.bayesian.NIWPosterior(prior_mu, prior_sigma, t0, nu0)[source]
Bases:
objectComputes and manages Normal-Inverse-Wishart (NIW) posterior parameters.
This class implements the Bayesian update rules for an NIW distribution, which is the conjugate prior for a multivariate normal likelihood with unknown mean and covariance. The methodology follows Section 3 of Meucci (2005). It provides methods to calculate posterior parameters, classical-equivalent estimators, and factors used in robust Bayesian asset allocation.
The model assumes that asset returns are independently and identically distributed according to a normal distribution. The investor’s prior knowledge is modeled as an NIW distribution.
How to Use:
Initialize the
NIWPosteriorobject with prior parameters:prior_mu(\(\mu_0\)): The prior estimate for the mean vector.prior_sigma(\(\Sigma_0\)): The prior scale matrix for the covariance.t0(\(T_0\)): The confidence inprior_mu, expressed as apseudo-count of observations.
nu0(\(\nu_0\)): The confidence inprior_sigma, expressed as apseudo-count of observations.
Call the
update()method with sample statistics from observed data:sample_mu(\(\hat{\mu}\)): The mean vector from the data.sample_sigma(\(\hat{\Sigma}\)): The covariance matrix from the data.n_obs(\(T\)): The number of observations in the data sample.
The
update()method returns anNIWParamsobject with the posterior parameters (\(T_1, \mu_1, \nu_1, \Sigma_1\)), which are a blend of the prior and the market data.Use accessor methods like
get_mu_ce(),get_S_mu(), etc., to retrieve various quantities derived from the posterior distribution.
- Parameters:
prior_mu (Union[npt.NDArray[np.floating], 'pd.Series[np.floating]'])
prior_sigma (Union[npt.NDArray[np.floating], 'pd.DataFrame[np.floating]'])
t0 (int)
nu0 (int)
- prior_mu
The prior mean vector (\(\mu_0\)).
- prior_sigma
The prior scale matrix (\(\Sigma_0\)).
- t0
The prior pseudo-count for the mean (\(T_0\)).
- nu0
The prior pseudo-count for the covariance (\(\nu_0\)).
- N
The number of assets.
- _asset_index
Stores pandas.Index if pandas objects are used.
- _posterior
Stores the computed posterior parameters.
- cred_radius_mu(p_mu)[source]
Computes the credibility factor \(\gamma_\mu\) for the mean’s uncertainty.
This factor, \(\gamma_\mu\), appears in the simplified robust mean-variance optimization problem (Eq. 19). It scales the portfolio’s posterior standard deviation to penalize for estimation risk in the mean vector. Its formula is given by Eq. (20):
\[\gamma_\mu = \sqrt{ \frac{q_\mu^2}{T_1} \frac{\nu_1}{\nu_1 - 2} }\]where \(q_\mu^2 = Q_{\chi^2_N}(p_{mu})\) is the squared radius factor from the chi-square distribution.
- Parameters:
p_mu – The confidence level for \(\mu\) (0 < p_mu < 1), which reflects aversion to estimation risk.
- Returns:
The credibility factor \(\gamma_\mu\).
- Raises:
RuntimeError – If posterior parameters have not been computed.
ValueError – If \(\nu_1 \le 2\) or p_mu is not in (0,1).
- Parameters:
p_mu (float)
- Return type:
float
- cred_radius_sigma_factor(p_sigma)[source]
Computes the scaling factor for the worst-case portfolio variance.
In the robust framework, the maximum possible variance of a portfolio within the uncertainty ellipsoid for \(\Sigma\) is not simply \(w'\Sigma_1 w\), but a scaled version of it. This method computes that scaling factor, which we can call \(C_\Sigma\). The derivation is shown in Appendix 7.2, and the final result is presented in the maximization step in Eq. (47):
\[\max_{\Sigma \in \Theta_\Sigma} w'\Sigma w = \underbrace{ \left[ \frac{\nu_1}{\nu_1 + N + 1} + \sqrt{\frac{2\nu_1^2 q_\Sigma^2}{(\nu_1 + N + 1)^3}} \right] }_{C_\Sigma} (w'\Sigma_1 w)\]where \(q_\Sigma^2 = Q_{\chi^2_{dof}}(p_\Sigma)\) with \(dof = N(N+1)/2\).
- Parameters:
p_sigma – The confidence level for \(\Sigma\) (0 < p_sigma < 1), reflecting aversion to estimation risk.
- Returns:
The credibility factor \(C_\Sigma\) for scaling the portfolio variance.
- Raises:
RuntimeError – If posterior parameters have not been computed.
ValueError – If p_sigma is not in (0,1) or internal terms are invalid.
- Parameters:
p_sigma (float)
- Return type:
float
- get_S_mu()[source]
Computes the scatter matrix \(S_{\mu}\) for the posterior of \(\mu\).
This matrix describes the dispersion of the marginal posterior distribution of \(\mu\) and is used to define the location-dispersion ellipsoid for robust optimization. It is defined in Eq. (16):
\[S_{\mu} = \frac{1}{T_1} \frac{\nu_1}{\nu_1 - 2} \Sigma_1\]This computation requires the posterior degrees of freedom \(\nu_1 > 2\).
- Returns:
The scatter matrix \(S_{\mu}\) as a NumPy array or pandas DataFrame.
- Raises:
RuntimeError – If posterior parameters have not been computed.
ValueError – If \(\nu_1 \le 2\), as the scatter matrix is not defined.
- Return type:
Union[npt.NDArray[np.floating], ‘pd.DataFrame[np.floating]’]
- get_mu_ce()[source]
Computes the classical-equivalent estimator for the mean, \(\hat{\mu}_{ce}\).
For the NIW model, this estimator is the posterior mean \(\mu_1\), as defined in Eq. (15).
\[\hat{\mu}_{ce} = \mu_1\]- Returns:
The posterior mean vector \(\mu_1\) as a NumPy array or pandas Series.
- Raises:
RuntimeError – If posterior parameters have not been computed via
update().- Return type:
Union[npt.NDArray[np.floating], ‘pd.Series[np.floating]’]
- get_sigma_ce()[source]
Computes the classical-equivalent estimator for the covariance, \(\hat{\Sigma}_{ce}\).
This estimator is a shrunk version of the posterior scale matrix \(\Sigma_1\), as defined in Eq. (17). It serves as the center of the uncertainty ellipsoid for \(\Sigma\).
\[\hat{\Sigma}_{ce} = \frac{\nu_1}{\nu_1 + N + 1} \Sigma_1\]- Returns:
The classical-equivalent estimator \(\hat{\Sigma}_{ce}\) as a NumPy array or pandas DataFrame.
- Raises:
RuntimeError – If posterior parameters have not been computed.
ValueError – If \(\nu_1 + N + 1 = 0\), which is highly unlikely with valid inputs.
- Return type:
Union[npt.NDArray[np.floating], ‘pd.DataFrame[np.floating]’]
- property is_updated: bool
Whether the posterior has been computed via
update().
- update(sample_mu, sample_sigma, n_obs)[source]
Updates the posterior parameters using sample statistics.
This method implements the Bayesian update rules for the NIW parameters as given by Eqs. (11)-(14) in Meucci (2005).
\[\begin{split}\begin{align*} T_1 &= T_0 + T \\ \mu_1 &= \frac{T_0\mu_0 + T\hat{\mu}}{T_1} \\ \nu_1 &= \nu_0 + T \\ \Sigma_1 &= \frac{1}{\nu_1} \left[ \nu_0\Sigma_0 + T\hat{\Sigma} + \frac{(\mu_0 - \hat{\mu})(\mu_0 - \hat{\mu})'}{\frac{1}{T} + \frac{1}{T_0}} \right] \end{align*}\end{split}\]The resulting posterior parameters blend the investor’s prior with information from the market, with the balance determined by the relative confidence levels (\(T_0, \nu_0\)) versus the amount of data (\(T\)).
- Parameters:
sample_mu – 1D array (length N) of sample means (\(\hat{\mu}\)).
sample_sigma – 2D array (N x N) of the sample covariance matrix (\(\hat{\Sigma}\)).
n_obs – The number of observations in the sample (\(T\)).
- Returns:
A
NIWParamsinstance with the updated posterior parameters. If pandas objects were used in initialization, returns \(\mu_1\) as a Series and \(\Sigma_1\) as a DataFrame.- Raises:
ValueError – If sample statistics have inconsistent shapes or
n_obsis not a positive integer.- Parameters:
sample_mu (Union[npt.NDArray[np.floating], 'pd.Series[np.floating]'])
sample_sigma (Union[npt.NDArray[np.floating], 'pd.DataFrame[np.floating]'])
n_obs (int)
- Return type:
- class pyvallocation.bayesian.RobustBayesPosterior(mu, sigma, s_mu, _nu1=None, _n_assets=None, _T1=None)[source]
Bases:
objectBundle NIW posterior moments with mean-uncertainty helpers.
The Normal-Inverse-Wishart (NIW) posterior implies a covariance of the mean \(S_\mu\) given by [Meucci, 2005]:
\[S_\mu = \frac{\nu_1}{T_1 (\nu_1 - 2)} \Sigma_1.\]This object exposes \(S_\mu\) and convenience transforms into horizon-scaled log- and simple-return units, which are required by robust optimisation routines that penalise mean uncertainty.
- Key fields:
mu: Posterior mean vector (same units as inputs). sigma: Posterior covariance matrix (same units as inputs). s_mu: Posterior covariance of the mean (\(S_\mu\)).
- Parameters:
mu (Union[npt.NDArray[np.floating], pd.Series])
sigma (Union[npt.NDArray[np.floating], pd.DataFrame])
s_mu (Union[npt.NDArray[np.floating], pd.DataFrame])
_nu1 (Optional[float])
_n_assets (Optional[int])
_T1 (Optional[float])
- cred_radius_mu(p_mu=0.75)[source]
Credibility radius for the mean uncertainty ellipsoid (Meucci Eq. 9.156).
- Parameters:
p_mu – Probability level for the chi-square quantile. Defaults to 0.75.
- Returns:
float – Credibility factor gamma_mu.
- Raises:
ValueError – If NIW parameters are not available.
- Parameters:
p_mu (float)
- Return type:
float
- cred_radius_sigma_factor(p_sigma=0.75)[source]
Scaling factor for worst-case variance under Sigma uncertainty (Meucci Eq. 9.157).
- Parameters:
p_sigma – Probability level for the chi-square quantile. Defaults to 0.75.
- Returns:
float – Scaling factor C_sigma.
- Raises:
ValueError – If NIW parameters are not available.
- Parameters:
p_sigma (float)
- Return type:
float
- classmethod from_niw(*, prior_mu, prior_sigma, t0, nu0, sample_mu, sample_sigma, n_obs)[source]
Construct the posterior bundle from NIW inputs.
- Parameters:
prior_mu – Prior mean vector.
prior_sigma – Prior covariance matrix.
t0 – Prior strength for the mean.
nu0 – Prior degrees of freedom for the covariance.
sample_mu – Sample mean vector.
sample_sigma – Sample covariance matrix.
n_obs – Number of observations.
- Returns:
RobustBayesPosterior – Posterior bundle with mean uncertainty.
- Parameters:
prior_mu (Union[npt.NDArray[np.floating], pd.Series])
prior_sigma (Union[npt.NDArray[np.floating], pd.DataFrame])
t0 (int)
nu0 (int)
sample_mu (Union[npt.NDArray[np.floating], pd.Series])
sample_sigma (Union[npt.NDArray[np.floating], pd.DataFrame])
n_obs (int)
- Return type:
- mean_uncertainty_cov_log(*, annualization_factor=1.0)[source]
Return mean-uncertainty covariance in log-return units.
The mean uncertainty scales with the square of the horizon:
\[S_{\mu,\,h} = h^2\, S_\mu.\]- Parameters:
annualization_factor (float)
- Return type:
Union[npt.NDArray[np.floating], pd.DataFrame]
- mean_uncertainty_cov_simple(*, annualization_factor=1.0, exact=False)[source]
Return mean-uncertainty covariance in simple-return units.
Assumes
muands_muare expressed in log-return units. The method annualises and applies a delta approximation to map to simple returns:\[r \approx \exp(\mu_g) - 1, \quad S_{\mu,r} \approx J\,S_{\mu,g}\,J^{\top}, \quad J = \operatorname{diag}(\exp(\mu_g)).\]- Parameters:
annualization_factor – Horizon scaling factor (e.g. 12 for monthly -> annual).
exact – When
True, use the exact delta-method JacobianJ = diag(exp(mu_g + 0.5 * diag(Sigma_g)))which accounts for the Jensen inequality correction. DefaultFalseuses the simplerJ = diag(exp(mu_g)).
- Parameters:
annualization_factor (float)
exact (bool)
- Return type:
Union[npt.NDArray[np.floating], pd.DataFrame]
- mu: numpy.typing.NDArray.numpy.floating | pandas.Series
- s_mu: numpy.typing.NDArray.numpy.floating | pandas.DataFrame
- sigma: numpy.typing.NDArray.numpy.floating | pandas.DataFrame
- property sigma1: npt.NDArray[np.floating] | pd.DataFrame
Return the raw posterior scale matrix Sigma_1 (Meucci Eq. 7.31).
sigmastores the classical-equivalent Sigma_ce = nu1/(nu1+N+1) * Sigma_1. This property recovers Sigma_1 = (nu1+N+1)/nu1 * Sigma_ce for use in the robust Bayesian formulation (Meucci Eq. 9.155).- Returns:
Posterior scale matrix Sigma_1.
- Raises:
ValueError – If the posterior was not constructed via
from_niw.
- pyvallocation.bayesian.chi2_quantile(p, dof, sqrt=False)[source]
Computes the quantile of the chi-square (chi^2) distribution.
This function is used to determine the size of the uncertainty ellipsoids for the market parameters (mean and covariance). The size is determined by a radius factor, \(q\), which is set according to a quantile of the chi-square distribution.
For the mean vector \(\mu\), under the assumption that its posterior distribution is normal, the squared Mahalanobis distance is chi-square distributed. The radius factor squared, \(q_\mu^2\), is set using a quantile of the \(\chi^2_N\) distribution.
\[q_\mu^2 = Q_{\chi_N^2}(p_\mu)\]For the covariance matrix \(\Sigma\), a similar approach is used based on a heuristic argument that the Mahalanobis distance behaves like a \(\chi^2\) distribution with \(N(N+1)/2\) degrees of freedom .
\[q_\Sigma^2 = Q_{\chi_{N(N+1)/2}^2}(p_\Sigma)\]- Parameters:
p – The probability level (0 < p < 1) for the quantile.
dof – The degrees of freedom for the chi-square distribution.
sqrt – If True, returns the square root of the quantile. Defaults to False.
- Returns:
The chi-square quantile \(Q_{\chi^2}(p)\) or \(\sqrt{Q_{\chi^2}(p)}\) if sqrt is True.
- Raises:
ValueError – If p is not strictly between 0 and 1.
- Parameters:
p (float)
dof (int)
sqrt (bool)
- Return type:
float