Source code for qf_lib.portfolio_construction.optimizers.quadratic_optimizer

#     Copyright 2016-present CERN – European Organization for Nuclear Research
#
#     Licensed under the Apache License, Version 2.0 (the "License");
#     you may not use this file except in compliance with the License.
#     You may obtain a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#     Unless required by applicable law or agreed to in writing, software
#     distributed under the License is distributed on an "AS IS" BASIS,
#     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#     See the License for the specific language governing permissions and
#     limitations under the License.

from typing import Union, Sequence

import numpy as np
from cvxopt import matrix
from cvxopt import solvers

import qf_lib.portfolio_construction.optimizers.helpers.quadratic_constraints_helpers as constr


[docs]class QuadraticOptimizer: """ Class used for optimizing quadratic problems. """ options = { 'show_progress': False, 'abstol': 1e-15, 'reltol': 1e-15, 'feastol': 1e-15, 'maxiters': 1000 }
[docs] @classmethod def get_optimal_weights(cls, P: np.ndarray = None, q: np.ndarray = None, upper_constraints: Union[Sequence, float] = None) -> np.ndarray: """ Solves the problem defined by matrix h, vector f and constraints. Parameters ---------- P a square matrix from the quadratic formula q a vector (can be empty) from the quadratic formula upper_constraints vector of upper limits of weights (if it's a single value, the constraint will be the same for each weight). Example: 0.5 means that max allocation of some asset can be 50%. Returns ------- weights best weights for the given problem. Sum of all weights is equal 1. """ assets_number = P.shape[0] if P is not None: P = matrix(P) else: P = matrix(0.0, (assets_number, assets_number)) if q is not None: q = matrix(q) else: q = matrix(0.0, (assets_number, 1)) A, b = constr.sum_weights_equal_1_constraint(assets_number) G, h = constr.each_weight_greater_than_0_constraint(assets_number) if upper_constraints is not None: G_2, h_2 = constr.upper_bound_constraint(assets_number, upper_constraints) G, h = constr.merge_constraints(G, h, G_2, h_2) initial_weights = matrix(1.0 / assets_number, (assets_number, 1)) # minimize (1/2)x'Px + q'x # subject to Gx <= h; Ax = b result = solvers.qp(P, q, G, h, A, b, initvals=initial_weights, options=cls.options) return np.array(result['x']).squeeze()