Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,5 @@ __pycache__/*
.git/*
*.ipynb_checkpoints/*
*.coverage.*
dev/*
dev/*
uv.lock
117 changes: 100 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,44 +1,128 @@
# PenFolioOp
Portfolio Optimizations for *Pension Funds*

## Supported optimizers
[![codecov](https://codecov.io/gh/quantfinlib/heavy-tail/graph/badge.svg?token=Z60B2PYJ44)](https://codecov.io/gh/quantfinlib/penfolioop)
[![tests](https://github.com/quantfinlib/heavy-tail/actions/workflows/test.yml/badge.svg)](https://github.com/quantfinlib/heavy-tail/actions/workflows/test.yml)
[![docs](https://github.com/quantfinlib/heavy-tail/actions/workflows/gh-pages.yml/badge.svg)](https://github.com/quantfinlib/heavy-tail/actions/workflows/gh-pages.yml)
[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg?style=flat)](https://github.com/quantfinlib/heavy-tail/blob/main/LICENSE)

- Surplus Return Maximization
- Surplus Variance Minimization
- Surplus Sharpe Ratio Maximization
- Mean-Variance Optimization

Surplus return is defined as the return of the portfolio minus the return of the liabilities, while surplus variance is the variance of the portfolio returns in excess of the liabilities.
## Conventions

## Supported constraints
In this framework, for convenience, we make use of the following conventions:

Asset weight constraints can be applied to ensure that the portfolio adheres to specific investment guidelines.
`expected_returns` $\mathbf{R}$ is an array of the expected returns of the assets and the liabilities.

Usage of the library is straightforward. You can create a portfolio object, define your assets, and then use the optimizers to find the optimal asset weights based on your constraints and objectives.
$$
\mathbf{R} = \begin{bmatrix}
R_1 \\
R_2 \\
\vdots \\
R_n \\
R_L
\end{bmatrix} = \begin{bmatrix}
\mathbf{R}_{A} \\
R_L
\end{bmatrix}
$$

`covariance_matrix` $\mathbf{\Sigma} $ is the covariance matrix of the asset and the liability returns.

$$
\mathbf{\Sigma} = \begin{bmatrix}
\mathbf{\Sigma}_{A} & \mathbf{\Sigma}_{AL} \\
\mathbf{\Sigma}_{AL} & \sigma^{2}_{L}
\end{bmatrix},
$$

where $\mathbf{\Sigma}_{A}$ is the covariance matrix of the asset returns, $\mathbf{\Sigma}_{AL}$ is a vector of the covariance between the asset and liability returns, and $\sigma^{2}_{L}$ is the variance of the liability returns.

The output of the optimization process is a weight vector $\mathbf{W}$ consisting of the optimal asset weights, and the liability weight is always set to -1. The optimization process aims to find the asset weights that maximize or minimize the chosen objective function while satisfying the specified constraints.

$$
\mathbf{W} = \begin{bmatrix}
w_1 \\
w_2 \\
\vdots \\
w_n \\
-1
\end{bmatrix} = \begin{bmatrix}
\mathbf{W}_{A} \\
-1
\end{bmatrix}
$$

`surplus_return` $\mathbf{R}_{S}$ is the return of the portfolio minus the return of the liabilities.

$$
\mathbf{R}_{S} = \mathbf{R}_{P} - \mathbf{R}_{L} = \mathbf{W}_{A} ^ {T}\mathbf{R}_{A} - \mathbf{R}_{L} = \mathbf{W} ^ {T} \mathbf{R}
$$


`surplus_variance` $\sigma^{2}_{S}$ is the variance of the surplus returns.

$$
\sigma^{2}_{S} = \mathbf{W}_{A}^{T} \mathbf{\Sigma}_{A} \mathbf{W}_{A} - 2 \mathbf{W}_{A}^{T} \mathbf{\Sigma}_{AL} + \sigma^{2}_{L} = \mathbf{W}^{T} \mathbf{\Sigma} \mathbf{W}
$$

## Optimizers

With the defined surplus return and variance, we can now outline the optimization problems.
All the optimizers are subject to these general constraints:

$$
\begin{align*}
(1) &\quad& \sum_{i=1}^{n_{assets}} w_{i} = \mathrm{SUM}(\mathbf{W}_{A}) = 1, \\
(2) &\quad& w_{i} \geq 0, \quad \forall i \in \{1, \ldots, n_{assets}\}, \\
(3) &\quad& w_{L} = -1
\end{align*}
$$

## Example


| optimizer | formulation | constraints |
|------------------------------------------|--------------------------------------------------------------------------|-----------------------------------------------------------------|
| `max_surplus_return_optimizer`| $\underset{\mathbf{W}}{\mathrm{maximize}} \quad \mathbf{W}^{T}\mathbf{R}$ | $\mathbf{W}^{T} \mathbf{\Sigma} \mathbf{W} \leq$ `surplus_risk_upper_limit`|
| `min_surplus_variance_optimizer`| $\underset{\mathbf{W}}{\mathrm{minimize}} \quad \mathbf{W}^{T} \mathbf{\Sigma} \mathbf{W}$ | $\mathbf{W}^{T}\mathbf{R} \geq$ `surplus_return_lower_limit`|
| `max_surplus_sharpe_ratio_optimizer`| $\underset{\mathbf{W}}{\mathrm{maximize}} \quad \frac{\mathbf{W}^{T}\mathbf{R}}{\sqrt{\mathbf{W}^{T} \mathbf{\Sigma} \mathbf{W}}}$ | `None` |
| `surplus_mean_variance_optimizer`| $\underset{\mathbf{W}}{\mathrm{maximize}} \\ \quad \mathbf{W}^{T}\mathbf{R} - \frac{\lambda}{2} \mathbf{W}^{T} \mathbf{\Sigma} \mathbf{W}$ | `None` |

In the above table, $\lambda$ is a risk aversion parameter that balances the trade-off between maximizing surplus returns and minimizing surplus risk.
In addition to the above optimizers, the user can also call the `efficient_frontier` function to compute the weights of the efficient frontier portfolio.
These portfolios can be found by varying the `surplus_return_lower_limit` in the following `min_surplus_variance_optimizer` optimizer. In this case, the user needs to provide a range of values for the `surplus_return_lower_limit` parameter.


## Additional Constraints

Asset weight constraints can be applied to ensure that the portfolio adheres to specific investment guidelines.



## Example

Usage of the library is straightforward. You can create a portfolio object, define your assets, and then use the optimizers to find the optimal asset weights based on your constraints and objectives.
The first step is to create a `Portfolio` object with your assets, their expected returns, and covariances. The last item in the list of assets should be the liability, which is treated differently from the other assets in the optimization process. The optimizaters always set the liability weight to -1 and require the other asset weights to be between 0 and 1 and sum to 1.

The user can then define additional constraints on the asset weights, such as requiring a minimum or maximum weight for certain assets or limiting the weight of one asset to be less than another.
The user can then define additional constraints on the asset weights, such as requiring a minimum or maximum weight for certain assets or limiting the weight of one or more assets to be less than another.

For a comprehensive description of the constraints, refer to the API documentation.


```python
from penfolioop import Portfolio, SurplusReturnMaximization

import numpy as np

from penfolioop.portfolio import Portfolio
from penfolioop.optimizers import max_surplus_return_optimizer

names = ['Asset A', 'Asset B', 'Asset C', 'Liability']
returns = [0.05, 0.07, 0.06, 0.04]
covariances = [[0.0001, 0.00005, 0.00002, 0.00003],
expected_returns = np.array([0.05, 0.07, 0.06, 0.04])
covariance_matrix = np.array([[0.0001, 0.00005, 0.00002, 0.00003],
[0.00005, 0.0002, 0.00001, 0.00004],
[0.00002, 0.00001, 0.00015, 0.00002],
[0.00003, 0.00004, 0.00002, 0.0001]]

portfolio = Portfolio(names, returns, covariances)
portfolio = Portfolio(names=names, expected_returns=expected_returns, covariance_matrix=covariance_matrix)

constraints = [
{
Expand All @@ -53,6 +137,5 @@ constraints = [
}
]

weights = SurplusReturnMaximization(portfolio=portfolio, asset_constraints=constraints)
```
weights = max_surplus_return_optimizer(portfolio=portfolio, asset_constraints=constraints, surplus_risk_upper_limit=0.0001)

5,469 changes: 5,469 additions & 0 deletions docs/Example_US_Asset_Classes.ipynb

Large diffs are not rendered by default.

4 changes: 1 addition & 3 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,13 @@


[🌐 **GitHub**](https://github.com/quantfinlib/penfolioop)

[📖 **Documentation**](https://quantfinlib.github.io/penfolioop/)
    [🔗 **API**](penfolioop)
    [📖 **Docs**](https://quantfinlib.github.io/penfolioop/)


## Getting Started

* [Basic example with synthetic data](Example_Synthetic_data.html)
* [Basic example with US Asset Classes](Example_US_Asset_Classes.html)


## Documentation
Expand Down
Loading
Loading