Welcome to Py-vAllocation

Py-vAllocation is a modular toolkit for single-period portfolio construction. It exposes a consistent Python API for mean-variance, mean-CVaR and robust optimisation, integrates view-based Bayesian updates, and ships with portfolio ensembling utilities so research portfolios can become investable allocations.

Key capabilities

  • Multiple risk models, one wrapper - switch between mean-variance, CVaR, and robust formulations without changing how you declare constraints or transaction costs.

  • Investor views made actionable - entropy pooling and Black-Litterman helpers transform qualitative views into posterior distributions.

  • Scenario-aware statistics - shrinkage estimators, Bayesian updates and scenario bootstrapping reduce estimation error out of the box.

  • Portfolio ensembling - average exposures, stack frontiers, and discretise weights to bridge the gap between optimisation outputs and tradeable lists.

  • Stress testing made easy - probability tilts, linear shocks, and PnL summaries reuse the same scenario machinery to keep analyses consistent.

Where to start

  • Getting Started for installation and a minimal efficient frontier example.

  • <no title> for the end-to-end multi-asset ETF walkthrough with stress tests and horizon projections.

  • Tutorials for all interactive notebooks covering mean-variance, CVaR, risk parity, stress testing, views, repricing, and ensembles.

  • Examples & Notebooks for a catalog of runnable scripts and notebooks.

  • The examples/ directory offers runnable scripts that mirror the tutorials - try python examples/stress_and_pnl.py for probability tilts and performance summaries.

Install & quickstart

# Clone and install the library (full instructions in :doc:`getting_started`)
git clone https://github.com/enexqnt/py-vallocation.git
cd py-vallocation
python -m pip install -e .[robust]
import numpy as np
from pyvallocation.portfolioapi import PortfolioWrapper

wrapper = PortfolioWrapper.from_scenarios(np.random.normal(0, 0.01, size=(252, 4)))
frontier = wrapper.variance_frontier(num_portfolios=11)
weights, ret, risk = frontier.tangency(risk_free_rate=0.01)
print(weights.round(3))

Tutorials & Examples

Indices and tables