Optimization & Rebalancing
This page documents the optimization and rebalancing probability functionality, which is all a part of the Optimization object.
Efficient Frontiers and Target Return
The general formulation used for efficient frontier optimization as well as efficient portfolios with return targets is given by:
subject to:
Here \(\mathcal{R}\left(e\right)\), which can be either variance, CVaR, or LSAD, denotes the risk of exposure \(e\), while \(\mathcal{E}\) is the feasible portfolio exposure set. Finally, \(v\) is the vector of relative market values from the Portfolio Management Framework for Derivative Instruments.
Benchmark Efficient and Target Risk
For benchmark efficient portfolios and efficient portfolios with target risk, the following formulation is used:
subject to:
Resampled Portfolio Stacking
For efficient frontiers, benchmark efficient portfolios, and efficient portfolios with a risk target, it is possible to introduce uncertainty into the expected return vector \(\mu\). For more details on the fundamental perspectives, see the Portfolio Optimization and Parameter Uncertainty article and the Portfolio Construction and Risk Management book.
Optimization Algorithms and Parameters
For the variance risk measure with target return constraints, a standard quadratic programming solver is used. For the variance risk measure with tracking error or target risk constraints, a second-order cone programming solver is used. For the CVaR and LSAD risk measures, proprietary algorithms are used to solve the problems efficiently.
For CVaR and LSAD optimization, the following control parameters are available:
'demean_cvar'Boolean indicating whether to use demeaned P&L when calculating CVaR. Default:
True.'pnl_scalar'Scaling factor for the P&L simulation. Default:
10000.'mean_scalar'Scaling factor for the expected returns used by the return target constraint. Default:
100.'maxiter'Maximum number of iterations for the algorithm. Default:
125.'reltol'Relative tolerance for the difference between the currently best upper and lower bounds. Default:
1e-8.'abstol'Absolute tolerance for the difference between the currently best upper and lower bounds if the lower bound is less than
1e-10. Default:1e-8.
These control parameters can be set globally using the cvar_options dictionary, e.g.,
from fortitudo.tech import investment_analysis as ia
ia.cvar_options['demean_cvar'] = False
ia.cvar_options['maxiter'] = 200
or for a particular Optimization instance:
opt = ia.Optimization(pf, pnl, cvar_options={'demean_cvar': False, 'maxiter': 200})
The algorithm stops when one of the 'maxiter', 'reltol',
or 'abstol' conditions are satisfied. The parameters have been tested
with “percentage return” P&L and work well. In most cases, the algorithm stops
due to relative convergence in less than 100 iterations. If you use P&L
simulations that are scaled differently, you might need to adjust them.
Rebalancing Probability
The Optimization object implements the Resampled Portfolio Rebalancing functionality as described in the Portfolio Construction and Risk Management book.
It is possible to compute the Resampled Rebalanced Probability using either the marginal risk contributions, marginal return contributions, or the exposures as the rebalancing target functions. Additionally, rebalancing can be performed manually for other user-defined rebalancing target functions by setting the parameter keep_bootstrap_results to True. Bootstrap portfolios can then be accessed through the get_bootstrap_results_keys and get_bootstrap_results methods.
It is important to underline that both the investments restrictions as well as the uncertainty about expected returns affect the distribution of the metric. The uncertainty about expected returns can be controlled using the set_mean_uncertainty method, while portfolio restrictions are set using the Portfolio object, which is done prior to initializing the Optimization object.
- class Optimization(portfolio, pnl, probability=None, **kwargs)
Object for portfolio optimization.
- Parameters:
portfolio (
Portfolio) – Fortitudo Technologies Portfolio object. If the Portfolio object does not contain any restrictions, the Optimization object will assume long-only restrictions.pnl (
DataFrame) – P&L simulation used for portfolio optimization with shape (S, I).probability (
ndarray) – Probability vector with shape (S,) for the S P&L scenarios in pnl. Set to np.ones(S) / S by default.kwargs (
dict) – cvar_options dictionary containing control parameters.
- Raises:
ValueError – If there is a mismatch between portfolio and pnl instruments.
ValueError – If probability is not a vector with shape (S,) containing strictly positive elements that sum to 1.
ValueError – If portfolio constraints are infeasible.
- benchmark_efficient_portfolio(target_risk, tracking_error_max, risk='cvar', num_samples=0, cvar_alpha=0.95, stacking='5-risk', details='essential', keep_bootstrap_results=False)
Method for computing a benchmark efficient portfolio.
- Parameters:
target_risk (
float) – Risk target for the benchmark efficient portfolio.tracking_error_max (
float) – Max tracking error for the benchmark efficient portfolio.risk (
str) – Risk measure used in the portfolio optimization: {‘variance’, ‘cvar’, ‘lsad’}. Default: ‘cvar’.num_samples (
int) – Number of bootstrap samples for resampled portfolio optimization. Default: 0.cvar_alpha (
float) – Alpha value used for CVaR optimization. Default: 0.95.stacking (
str) – Method for weighting bootstrap portfolios. Can be a simple average, Exposure Stacking, marginal risk stacking, or marginal return stacking: {‘L-es’, ‘L-risk’, ‘L-return’, ‘average’} for some integer L. Default: ‘5-risk’.details (
str) – Determines the output of the method: {‘essential’, ‘all’, ‘raw’}. Default: ‘essential’.keep_bootstrap_results (
bool) – Whether to store bootstrap results in the optimization object or not. Default: False.
- Return type:
Union[DataFrame,Tuple[DataFrame,DataFrame,DataFrame],ndarray]- Returns:
details=’essential’ returns a pd.DataFrame with portfolio exposures, details=’all’ returns three pd.DataFrames with exposures, buy, and sell turnover, details=’raw’ returns a np.ndarray with exposures, buy, and sell turnover concatenated.
- Raises:
TypeError – If target_risk or tracking_error_max are not floats or integers.
ValueError – If the portfolio does not have a benchmark.
ValueError – If risk is not in {‘variance’, ‘cvar’, ‘lsad’}.
ValueError – If stacking is not in {‘L-es’, ‘L-risk’, ‘L-return’, ‘average’} for some integer L.
ValueError – If L is not in [2, num_samples].
ValueError – If num_samples is negative or not an integer.
ValueError – If target_risk and tracking_error_max are not both positive numbers for risk in {‘variance’, ‘lsad’}.
ValueError – If details is not in {‘essential’, ‘all’, ‘raw’}.
ValueError – If the risk target is not feasible.
- efficient_frontier(num_portfolios=9, risk='cvar', num_samples=0, cvar_alpha=0.95, stacking='5-risk', details='essential', keep_bootstrap_results=False)
Method for computing an efficient frontier.
- Parameters:
num_portfolios (
int) – Number of portfolios used to span the efficient frontier. Default: 9.risk (
str) – Risk measure used in the portfolio optimization: {‘variance’, ‘cvar’, ‘lsad’}. Default: ‘cvar’.num_samples (
int) – Number of bootstrap samples for resampled portfolio optimization. Default: 0.cvar_alpha (
float) – Alpha value used for CVaR optimization. Default: 0.95.stacking (
str) – Method for weighting bootstrap portfolios. Can be a simple average, Exposure Stacking, marginal risk stacking, or marginal return stacking: {‘L-es’, ‘L-risk’, ‘L-return’, ‘average’} for some integer L. Default: ‘5-risk’.details (
str) – Determines the output of the method: {‘essential’, ‘all’, ‘raw’}. Default: ‘essential’.keep_bootstrap_results (
bool) – Whether to store bootstrap results in the optimization object or not. Default: False.
- Return type:
Union[DataFrame,Tuple[DataFrame,DataFrame,DataFrame],ndarray]- Returns:
details=’essential’ returns a pd.DataFrame with portfolio exposures, details=’all’ returns three pd.DataFrames with exposures, buy, and sell turnover, details=’raw’ returns a np.ndarray with exposures, buy and sell turnover concatenated.
- Raises:
ValueError – If num_portfolios is not an integer greater than or equal to 2.
ValueError – If stacking is not in {‘L-es’, ‘L-risk’, ‘L-return’, ‘average’} for some integer L.
ValueError – If L is not in [2, num_samples].
ValueError – If risk is not in {‘variance’, ‘cvar’, ‘lsad’}.
ValueError – If num_samples is negative or not an integer.
ValueError – If details is not in {‘essential’, ‘all’, ‘raw’}.
ValueError – If the minimum risk portfolio cannot be financed.
- efficient_portfolio(target_return=None, target_risk=None, risk='cvar', num_samples=0, cvar_alpha=0.95, stacking='5-risk', details='essential', keep_bootstrap_results=False)
Method for computing an efficient portfolio.
- Parameters:
target_return (
float) – Return target for the efficient portfolio. Default: None.target_risk (
float) – Risk target for the efficient portfolio. Default: None.risk (
str) – Risk measure used in the portfolio optimization: {‘variance’, ‘cvar’, ‘lsad’}. Default: ‘cvar’.num_samples (
int) – Number of bootstrap samples for resampled portfolio optimization. Default: 0.cvar_alpha (
float) – Alpha value used for CVaR optimization. Default: 0.95.stacking (
str) – Method for weighting bootstrap portfolios. Can be a simple average, Exposure Stacking, marginal risk stacking, or marginal return stacking: {‘L-es’, ‘L-risk’, ‘L-return’, ‘average’} for some integer L. Default: ‘5-risk’.details (
str) – Determines the output of the method: {‘essential’, ‘all’, ‘raw’}. Default: ‘essential’.keep_bootstrap_results (
bool) – Whether to store bootstrap results in the optimization object or not. Default: False.
- Return type:
Union[DataFrame,Tuple[DataFrame,DataFrame,DataFrame],ndarray]- Returns:
details=’essential’ returns a pd.DataFrame with portfolio exposures, details=’all’ returns three pd.DataFrames with exposures, buy, and sell turnover, details=’raw’ returns a np.ndarray with exposures, buy and sell turnover concatenated.
- Raises:
ValueError – If both target_return and target_risk have been specified.
ValueError – If risk is not in {‘variance’, ‘cvar’, ‘lsad’}.
ValueError – If stacking is not in {‘L-es’, ‘L-risk’, ‘L-return’, ‘average’} for some integer L.
ValueError – If L is not in [2, num_samples].
ValueError – If num_samples is not a non-negative integer.
ValueError – If details is not in {‘essential’, ‘all’, ‘raw’}.
TypeError – If target_return or target_risk is not a float or an integer when they are different from None.
ValueError – If target_risk is non-positive when risk is in {‘variance’, ‘lsad’}.
ValueError – If the risk target is infeasible.
- get_bootstrap_results(key)
Method for getting the bootstrap results for a particular key.
- Parameters:
key (
str) – Key for the desired bootstrap results.- Return type:
ndarray- Returns:
Bootstrap results as an np.ndarray with shape (num_samples, I, num_portfolios).
- Raises:
KeyError – If bootstrap results have not been computed for the key.
- get_bootstrap_results_keys()
Method for getting the bootstrap results keys.
- Return type:
list- Returns:
List of bootstrap result keys.
- rebalancing_probability(target_portfolio, risk='cvar', rebalancing_function='risk', num_samples=1000, cvar_alpha=0.95, return_distribution=False, keep_bootstrap_results=False)
Method for computing the Resampled Rebalancing Probability of a portfolio.
- Parameters:
target_portfolio (
DataFrame) – pd.DataFrame of shape (I, 1) containing the portfolio to rebalance towards.risk (
str) – Risk measure used in the portfolio optimization: {‘variance’, ‘cvar’, ‘lsad’}. Default: ‘cvar’.rebalancing_function (
str) – Function for computing the resampled rebalancing target, using either the marginal risk, marginal return, or the exposures: {‘risk’, ‘return’, ‘exposures’}. Default: ‘risk’.num_samples (
int) – Number of bootstrap samples in the interval [100, 1000] used for computing the resampled rebalancing probability. Default: 1000.cvar_alpha (
float) – Alpha value used for CVaR risk measure. Default: 0.95.return_distribution (
bool) – Boolean indicating whether to also return the rebalancing distribution and test statistic.keep_bootstrap_results (
bool) – Whether to store bootstrap results in the optimization object or not. Default: False.
- Return type:
Union[float,Tuple[float,ndarray,float]]- Returns:
The rebalancing probability if return_distributions is False. The rebalancing probability, the rebalancing distribution as an array of shape (num_samples,), and the rebalancing test statistic if return_distribution is True.
- Raises:
TypeError – If target_portfolio is not a pd.DataFrame with shape (I, 1).
ValueError – If rebalancing_function is not in {‘risk’, ‘return’, ‘exposures’}.
ValueError – If risk is not in {‘cvar’, ‘variance’, ‘lsad’}.
TypeError – If num_samples is not an integer.
ValueError – If the risk of the target portfolio is not a feasible risk target for resampling.
- set_mean_uncertainty(mean_uncertainty)
Method for setting the mean uncertainty for resampled efficient portfolio optimization.
- Parameters:
mean_uncertainty (
ndarray) – Vector of shape (I,) with uncertainties relative to instrument standard deviations.- Raises:
ValueError – If mean_uncertainty is not a vector with shape (I,) and all elements in (0, 1].