Function reference

Meva provides the following top-level functions:

Optimization aopt, nopt, utility, marinal_utility
Risk cov_pca, cov_fa, beta

Optimization

meva.aopt(rho, mu, risk, equality=None, soft=None)

Mean-variance optimal portfolio with linear equality constraints.

Parameters:

rho : float

Risk tolerance; this dilates the return relative to the variance in the objective function, so that the larger rho the more emphasis is placed on return.

mu : ndarray

A 1d array of expected returns.

risk : list

The common and individual risk factors (sometimes called systematic and idiocyncratic). The first element of the list contains the common risk factors: an array, B, of shape (n, k) where n is the number of assets and k is the number of risk factors. The second element of the list contains the individual variance of each asset: an array, D, of shape (n,). D should contain no zeros. The n by n covariance matrix, V, of asset returns is given by V = np.dot(B, B.T) + np.diag(D).

equality : {list, None}, optional

A list containing the equality constraints. The first element of the list contains an array of shape (n, k) where n is the number of assets and k is the number of linear equality constraints. The second element is an array of shape (k,). For each k, we are requiring that np.dot(ac[:,k], x) = bc[k], for the final portfolio x. By default (None) there are no equality constraints on the portfolio.

soft : {list, None}, optional

A list containing three arrays that together describe the soft constraint. Let’s call the three arrays q, q0, and k. If there are s soft constraints then q has shape (n, s), q0 and k have shape (s,). The soft constraint adds a penalty to the utility (objective) function, where the penalty for each soft constraint i is given by

-k[i]*(np.dot(x.T, q[:,i]) - q0[i])**2

The total penalty is the sum of the s penalties. So a soft constraint is a squared penalty on deviations from an equality constraint, or a soft equality constraint. The default (None) is not to include any soft constraints in the optimization.

Returns:

x : ndarray

An array of shape (n,) that contains the mean-variance optimal portfolio.

See also

meva.nopt
numerical portfolio optimization

Notes

This implementation takes an inverse of the covariance matrix.


meva.nopt(rho, mu, risk, sumk, x0=None, tol=[0.0001, 1e-10], position_limit=[-inf, inf], transaction_cost=None, turnover=[0, inf, 1000], soft=None, inequality=None, verbose=False, log=None)

Long-short mean-variance portfolio optimization.

See the manual for details.

Parameters:

rho : double

Risk tolerance. The higher the value, the less concerned you are about risk (or the more concerned you are about return).

mu : ndarray

The expected future return of each asset. A 1d array of size n where n is the number of assets.

risk : list

The common and individual risk factors (sometimes called systematic and idiocyncratic). The first element of the list contains the common risk factors: an array, B, of shape (n, k) where n is the number of assets and k is the number of risk factors. The second element of the list contains the individual variance of each asset: an array, D, of shape (n,). The n by n covariance matrix, V, of asset returns is given by V = np.dot(B, B.T) + np.diag(D).

sumk : list

A two-element list containing the sum of the shorts (first element in list) and the sum of the longs (second element). The sum of the longs, for example, in portfolio x (a 1d array of portfolio weights) is x[x > 0].sum(). If, for example, you’d like the sum of the shorts to be -1 and the sum of the longs to 1, then use sumk = [-1, 1].

Returns:

x : ndarray

The optimized portfolio weights in a 1d array of size n.

Other Parameters:
 

x0 : {ndarray, None}, optional

The weights of the assets in the initial portfolio: a 1d array of size n. Used to calculate transaction cost. The default (None) assumes the initial portfolio weights are all zero.

tol : list, optional

A list containing two (absolute) tolerances used by the optimizer. The first tolerance (default: 1e-4) is used for the sum of the short weights (x[x < 0].sum()) and the sum of the long weights (x[x > 0].sum()). The second tolerance (default: 1e-10) is related to the change in marginal utility of the portfolio. The optimizer iterates many times where each iteration makes a small change to the portfolio. If the change in utility is below the tolerance then the optimization is done.

position_limit : list, optional

A list containing two arrays both of size n or two doubles. The first array contains the lower position limit (default: negative infinity) of each asset; the second array contains the upper position limit (default: infinity). Instead of arrays the limits can be scalars if all assets have the same lower and/or upper position limit.

transaction_cost : list, optional

A list containing two arrays both of size n or two doubles. The first array contains linear transaction costs (default: 0) of each asset; the second array contains the quadratic transaction costs (default: 0). Instead of arrays the costs can be scalars if all assets have the same linear and/or quadratic transaction costs.

turnover : list, optional

A list containing three scalars. The first elemment (default 0) is the minimum allowed turnover. The second element (default infinity) is the maximum allowed turnover. The third element (defauly 1000) is the maximum number of iterations to use in attempting to satisfy the turnover contraints.

soft : {list, None}, optional

A list containing three arrays that together describe the soft constraint. Let’s call the three arrays q, q0, and k. If there are s soft constraints then q has shape (n, s), q0 and k have shape (s,). The soft constraint adds a penalty to the utility (objective) function, where the penalty for each soft constraint i is given by

-k[i]*(np.dot(x.T, q[:,i]) - q0[i])**2

The total penalty is the sum of the s penalties. So a soft constraint is a squared penalty on deviations from an equality constraint, or a soft equality constraint. The default (None) is not to include any soft constraints in the optimization.

inequality : list, optional

A list of the following form:

[2-d ndarray, 1-d ndarray, list of tuple of strings, float]

We now describe each entry in inequality:

The 2-d array, call it Q, and 1-d array c define inequalities

we desire to attain, of the form np.abs(np.dot(Q.T, x)) <= c (element-by element). This is a symmetric inequality centered at zero.

The third entry is just used for explaining what is happening

in verbose status updates. For each column of Q and entry in c, it should contain a tuple of 2 strings describing that particular inequality. You can leave one of the strings blank if you want; two are provided so that you can make the printout more descriptive if you desire.

The last entry is an increment: internally, the optimizer tries to

satisfy these inequalities via a quadratic penalty on the dot products, and this value determines the step size used to increment the penalty until the constraint is satisfied.

For a quick example, if you have a 1-d array beta and you want

to, for example, restrict the beta exposure to be no more than 0.05, and you want the soft penalty to move in steps of 0.1, then you can set

>>> inequality = [beta.reshape(-1, 1),
                  np.array([0.05])
                  [('risk', 'beta')],
                  0.1]

See also

meva.aopt
analytical portfolio optimization

meva.utility(rho, mu, risk, x)

Portfolio utility.

Utility, U, is defined as:

U = rho * dot(mu, x) - 0.5 * dot(x, dot(v, x))

where the covariance matrix of asset returns, v, is

v = dot(b, b.T) + diag(d)

and b=risk[0], d=risk[1], dot=np.dot, and diag=np.diag.

Parameters:

rho : double

Risk tolerance. The higher the value, the less concerned you are about risk (or the more concerned you are about return).

mu : ndarray

The expected future return of each asset. A 1d array of size n where n is the number of assets.

risk : list

The common and individual risk factors (sometimes called systematic and idiocyncratic). The first element of the list contains the common risk factors: an array of shape (n, k) where n is the number of assets and k is the number of risk factors. The second element of the list contains the individual variance of each asset: an array of shape (n,).

x : ndarray

The weights of the assets in the portfolio: a 1d array of size n.

Returns:

u : float

The utility of portfolio x.

See also

meva.marginal_utility
marginal portfolio utility

meva.marginal_utility(rho, mu, risk, x)

Marginal portfolio utility of a small move in x.

The marginal utility, du, is

du = rho * mu - dot(v, x)

where the covariance matrix of asset returns, v, is

v = dot(b, b.T) + diag(d)

and b=risk[0], d=risk[1], dot=np.dot, and diag=np.diag.

Parameters:

rho : double

Risk tolerance. The higher the value, the less concerned you are about risk (or the more concerned you are about return).

mu : ndarray

The expected future return of each asset. A 1d array of size n where n is the number of assets.

risk : list

The common and individual risk factors (sometimes called systematic and idiocyncratic). The first element of the list contains the common risk factors: an array of shape (n, k) where n is the number of assets and k is the number of risk factors. The second element of the list contains the individual variance of each asset: an array of shape (n,).

x : ndarray

The weights of the assets in the portfolio: a 1d array of size n.

Returns:

u : float

The marginal utility of portfolio x.

See also

meva.utility
portfolio utility

Risk

meva.cov_pca(ret, nfactor, shrinkage=0, nvar=None)

Covariance estimation by PCA-based algorithm.

The common and individual risk factors are sometimes referred to as the systematic variance and the idiosyncratic variance, respectively.

The nfactor risk factors are extracted (using principal component analysis) from a modified covariance matrix that is a linear combination of the sample covariance matrix C and the constant correlation covariance matrix CC:

modified cov = shrinkage * CC + (1 - shrinkage) * C.

The constant correlation covariance matrix is calculated as follows:

  1. Calculate the sample correlation matrix from ret.
  2. Find the mean correlation (mean of off-diagonal terms).
  3. Make a correlation matrix where every off-diagnal term is equal to the mean in #2.
  4. Using each asset’s variance convert the correlation matrix in #3 to a covariance matrix.

Use NaN to mark missing returns in ret.

Using the output of covbd (b and d), the estimated covariance matrix V is:

np.dot(b, b.T) + np.diag(d).
Parameters:

ret : ndarray

A 2d array of log returns of shape (n, t) where n is the number of assets and t is the number of time periods. A NaN is considered a missing return.

nfactor : int

The number of common risk factors. It cannot be greater than n (i.e, ret.shape[0]).

shrinkage : float, optional

The risk factors are extracted from a modified covariance matrix:

modified cov = shrinkage * CC + (1 - shrinkage) * C

where C is the sample covariance matrix and CC is the constant correlation covariance matrix. By default shinkage is 0.

nvar : {int, None}, optional

The variance of each asset (as opposed to the covariance) can be calculated using a different number of periods. For example if ret has shape (100, 250) the covariance structure is calculated on the full 250 periods but the variance (the diagonal of the covariance matrix) can be calculated on anywhere from 1 to 250 periods. The default value of None means use all data to calculate the variance.

Returns:

b : ndarray

The common risk factors: an array of shape (n, nfactor) where n is the number of assets.

d : ndarray

The individual asset variances: an array of shape (n,) where n is the number of assets.

See also

meva.cov_fa
factor analysis covariance

meva.cov_fa(ret, nfactor, niterations, bguess=None, dguess=None)

Covariance estimation by factor analysis based algorithm.

The common and individual risk factors are sometimes referred to as the systematic variance and the idiosyncratic variance, respectively.

The nfactor risk factors are extracted using an EM algorithm to estimate latent ‘factor’ variables, and then jointly estimate the distribution of these latent factors and the market returns.

Using the output of cov_pca (b and d), the estimated covariance matrix V is:

np.dot(b, b.T) + np.diag(d).

This function cannot handle missing returns. Therefore ret should not contain NaNs. The cov_pca function can handle missing returns.

Parameters:

ret : ndarray

A 2d array of log returns of shape (n, t) where n is the number of assets and t is the number of time periods. ‘ret’ cannot contains NaNs.

nfactor : int

The number of common risk factors. It cannot be greater than n (i.e, ret.shape[0]).

niterations : int

The number of iterations in the EM algorithm used to fit the model.

bguess : {ndarray, None}, optional

An initial guess at the output b. If you use the output of cov_pca, it will converge in far fewer iterations. If None, then a random guess is used.

dguess : {ndarray, None}, optional

An initial guess at the output d. If you use the output of cov_pca, it will converge in far fewer iterations. If None, then it is initiallized to marginal sample variance for each asset.

Returns:

b : ndarray

The common risk factors: an array of shape (n, nfactor) where n is the number of assets.

d : ndarray

The individual asset variances: an array of shape (n,) where n is the number of assets.

See also

meva.cov_pca
pca-based covariance

meva.beta(risk, index, index_sum=None)

Beta of each asset relative to index given covariance matrix.

Parameters:

risk : list

The common and individual risk factors (sometimes called systematic and idiocyncratic). The first element of the list contains the common risk factors: an array, B, of shape (n, k) where n is the number of assets and k is the number of risk factors. The second element of the list contains the individual variance of each asset: an array, D, of shape (n,). The n by n covariance matrix, V, of asset returns is given by V = np.dot(B, B.T) + np.diag(D). NaNs in b and d are set to zero and then any asset with a NaNs in b or d is assigned a beta of NaN.

index : ndarray

A 1d array containing index weights. We want the beta of each asset relative to this index. NaNs in index are set to 0.

index_sum : {float, None}, optional

The index is normalized to sum to index_sum. Useful when index contains NaNs, which are set to zero. By default (None) the sum of the index is not normalized.

Returns:

beta : ndarray

A 1d array containing the beta of each asset relative to the index.