# Post-processing weights¶

After optimal weights have been generated, it is often necessary to do some post-processing before they can be used practically. In particular, you are likely using portfolio optimization techniques to generate a portfolio allocation – a list of tickers and corresponding integer quantities that you could go and purchase at a broker.

However, it is not trivial to convert the continuous weights (output by any of our optimization methods) into an actionable allocation. For example, let us say that we have $10,000 that we would like to allocate. If we multiply the weights by this total portfolio value, the result will be dollar amounts of each asset. So if the optimal weight for Apple is 0.15, we need$1500 worth of Apple stock. However, Apple shares come in discrete units ($190 at the time of writing), so we will not be able to buy exactly$1500 of stock. The best we can do is to buy the number of shares that gets us closest to the desired dollar value.

PyPortfolioOpt offers two ways of solving this problem: one using a simple greedy algorithm, the other using integer programming.

## Documentation reference¶

The discrete_allocation module contains the DiscreteAllocation class, which offers multiple methods to generate a discrete portfolio allocation from continuous weights.

class pypfopt.discrete_allocation.DiscreteAllocation(weights, latest_prices, total_portfolio_value=10000, short_ratio=None)[source]

Generate a discrete portfolio allocation from continuous weights

Instance variables:

• Inputs:

• weights - dict
• latest_prices - pd.Series or dict
• total_portfolio_value - int/float
• short_ratio- float
• Output: allocation - dict

Public methods:

• greedy_portfolio() - uses a greedy algorithm
• lp_portfolio() - uses linear programming
__init__(weights, latest_prices, total_portfolio_value=10000, short_ratio=None)[source]
Parameters: weights (dict) – continuous weights generated from the efficient_frontier module latest_prices (pd.Series) – the most recent price for each asset total_portfolio_value (int/float, optional) – the desired total value of the portfolio, defaults to 10000 short_ratio (float, defaults to None.) – the short ratio, e.g 0.3 corresponds to 130/30. If None, defaults to the input weights. TypeError – if weights is not a dict TypeError – if latest_prices isn’t a series ValueError – if short_ratio < 0
_allocation_rmse_error(verbose=True)[source]

Utility function to calculate and print RMSE error between discretised weights and continuous weights. RMSE was used instead of MAE because we want to penalise large variations.

Parameters: verbose (bool) – print weight discrepancies? rmse error float
static _remove_zero_positions(allocation)[source]

Utility function to remove zero positions (i.e with no shares being bought)

greedy_portfolio(reinvest=False, verbose=False)[source]

Convert continuous weights into a discrete portfolio allocation using a greedy iterative approach.

Parameters: reinvest (bool, defaults to False) – whether or not to reinvest cash gained from shorting verbose (bool, defaults to False) – print error analysis? the number of shares of each ticker that should be purchased, along with the amount of funds leftover. (dict, float)
lp_portfolio(reinvest=False, verbose=False, solver='GLPK_MI')[source]

Convert continuous weights into a discrete portfolio allocation using integer programming.

Parameters: reinvest (bool, defaults to False) – whether or not to reinvest cash gained from shorting verbose (bool) – print error analysis? solver (str, defaults to "GLPK_MI") – the CVXPY solver to use (must support mixed-integer programs) the number of shares of each ticker that should be purchased, along with the amount of funds leftover. (dict, float)