Esempio n. 1
0
    def test_lpoptimizer(self):
        objective = np.array([1., 2.])
        lower_bound = np.array([0., 0.2])
        upper_bound = np.array([1., 0.8])

        optimizer = LPOptimizer(np.array([[1., 1., 1., 1.]]), lower_bound,
                                upper_bound, objective)

        self.assertAlmostEqual(optimizer.feval(), 1.2)
        np.testing.assert_array_almost_equal(optimizer.x_value(), [0.8, 0.2])
Esempio n. 2
0
def linear_builder(er: np.ndarray,
                   lbound: Union[np.ndarray, float],
                   ubound: Union[np.ndarray, float],
                   risk_constraints: np.ndarray,
                   risk_target: Tuple[np.ndarray, np.ndarray],
                   turn_over_target: float = None,
                   current_position: np.ndarray = None,
                   method: str = 'ecos') -> Tuple[str, np.ndarray, np.ndarray]:
    er = er.flatten()
    n, m = risk_constraints.shape

    if not risk_target:
        risk_lbound = -np.inf * np.ones((m, 1))
        risk_ubound = np.inf * np.ones((m, 1))
    else:
        risk_lbound = risk_target[0].reshape((-1, 1))
        risk_ubound = risk_target[1].reshape((-1, 1))

    if isinstance(lbound, float):
        lbound = np.ones(n) * lbound

    if isinstance(ubound, float):
        ubound = np.ones(n) * ubound

    if not turn_over_target or current_position is None:
        cons_matrix = np.concatenate(
            (risk_constraints.T, risk_lbound, risk_ubound), axis=1)
        prob = LPOptimizer(cons_matrix, lbound, ubound, -er, method)

        if prob.status() == 0:
            return 'optimal', prob.feval(), prob.x_value()
        else:
            raise PortfolioBuilderException(prob.status())
    else:
        if method in ("simplex", "interior"):
            # we need to expand bounded condition and constraint matrix to handle L1 bound
            w_u_bound = np.minimum(
                np.maximum(np.abs(current_position - lbound),
                           np.abs(current_position - ubound)),
                turn_over_target).reshape((-1, 1))

            current_position = current_position.reshape((-1, 1))

            lbound = np.concatenate((lbound, np.zeros(n)), axis=0)
            ubound = np.concatenate((ubound, w_u_bound.flatten()), axis=0)

            risk_lbound = np.concatenate((risk_lbound, [[0.]]), axis=0)
            risk_ubound = np.concatenate((risk_ubound, [[turn_over_target]]),
                                         axis=0)

            risk_constraints = np.concatenate(
                (risk_constraints.T, np.zeros((m, n))), axis=1)
            er = np.concatenate((er, np.zeros(n)), axis=0)

            turn_over_row = np.zeros(2 * n)
            turn_over_row[n:] = 1.
            risk_constraints = np.concatenate(
                (risk_constraints, [turn_over_row]), axis=0)

            turn_over_matrix = np.zeros((2 * n, 2 * n))
            for i in range(n):
                turn_over_matrix[i, i] = 1.
                turn_over_matrix[i, i + n] = -1.
                turn_over_matrix[i + n, i] = 1.
                turn_over_matrix[i + n, i + n] = 1.

            risk_constraints = np.concatenate(
                (risk_constraints, turn_over_matrix), axis=0)

            risk_lbound = np.concatenate((risk_lbound, -np.inf * np.ones(
                (n, 1))),
                                         axis=0)
            risk_lbound = np.concatenate((risk_lbound, current_position),
                                         axis=0)

            risk_ubound = np.concatenate((risk_ubound, current_position),
                                         axis=0)
            risk_ubound = np.concatenate((risk_ubound, np.inf * np.ones(
                (n, 1))),
                                         axis=0)

            cons_matrix = np.concatenate(
                (risk_constraints, risk_lbound, risk_ubound), axis=1)
            prob = LPOptimizer(cons_matrix, lbound, ubound, -er, method)

            if prob.status() == 0:
                return 'optimal', prob.feval(), prob.x_value()[:n]
            else:
                raise PortfolioBuilderException(prob.status())
        elif method.lower() == 'ecos':
            from cvxpy import Problem
            from cvxpy import Variable
            from cvxpy import multiply
            from cvxpy import norm1
            from cvxpy import Minimize

            w = Variable(n)
            current_risk_exposure = risk_constraints.T @ w

            constraints = [
                w >= lbound, w <= ubound,
                current_risk_exposure >= risk_lbound.flatten(),
                current_risk_exposure <= risk_ubound.flatten(),
                norm1(w - current_position) <= turn_over_target
            ]

            objective = Minimize(-w.T * er)
            prob = Problem(objective, constraints)
            prob.solve(solver='ECOS',
                       feastol=1e-10,
                       abstol=1e-10,
                       reltol=1e-10)

            if prob.status == 'optimal' or prob.status == 'optimal_inaccurate':
                return prob.status, prob.value, w.value.flatten()
            else:
                raise PortfolioBuilderException(prob.status)
        else:
            raise ValueError("{0} is not recognized".format(method))
Esempio n. 3
0
def linear_build(er: np.ndarray,
                 lbound: Union[np.ndarray, float],
                 ubound: Union[np.ndarray, float],
                 risk_constraints: np.ndarray,
                 risk_target: Tuple[np.ndarray, np.ndarray],
                 turn_over_target: float = None,
                 current_position: np.ndarray = None) -> Tuple[str, np.ndarray, np.ndarray]:
    er = er.flatten()
    n, m = risk_constraints.shape

    if not risk_target:
        risk_lbound = -np.inf * np.ones((m, 1))
        risk_ubound = np.inf * np.ones((m, 1))
    else:
        risk_lbound = risk_target[0].reshape((-1, 1))
        risk_ubound = risk_target[1].reshape((-1, 1))

    if isinstance(lbound, float):
        lbound = np.ones(n) * lbound

    if isinstance(ubound, float):
        ubound = np.ones(n) * ubound

    if not turn_over_target:
        cons_matrix = np.concatenate((risk_constraints.T, risk_lbound, risk_ubound), axis=1)
        opt = LPOptimizer(cons_matrix, lbound, ubound, -er)

        status = opt.status()

        if status == 0:
            status = 'optimal'

        return status, opt.feval(), opt.x_value()
    else:
        current_position = current_position.reshape((-1, 1))

        # we need to expand bounded condition and constraint matrix to handle L1 bound
        lbound = np.concatenate((lbound, np.zeros(n)), axis=0)
        ubound = np.concatenate((ubound, np.inf * np.ones(n)), axis=0)

        risk_lbound = np.concatenate((risk_lbound, [[0.]]), axis=0)
        risk_ubound = np.concatenate((risk_ubound, [[turn_over_target]]), axis=0)

        risk_constraints = np.concatenate((risk_constraints.T, np.zeros((m, n))), axis=1)
        er = np.concatenate((er, np.zeros(n)), axis=0)

        turn_over_row = np.zeros(2 * n)
        turn_over_row[n:] = 1.
        risk_constraints = np.concatenate((risk_constraints, [turn_over_row]), axis=0)

        turn_over_matrix = np.zeros((2 * n, 2 * n))
        for i in range(n):
            turn_over_matrix[i, i] = 1.
            turn_over_matrix[i, i + n] = -1.
            turn_over_matrix[i + n, i] = 1.
            turn_over_matrix[i + n, i + n] = 1.

        risk_constraints = np.concatenate((risk_constraints, turn_over_matrix), axis=0)

        risk_lbound = np.concatenate((risk_lbound, -np.inf * np.ones((n, 1))), axis=0)
        risk_lbound = np.concatenate((risk_lbound, current_position), axis=0)

        risk_ubound = np.concatenate((risk_ubound, current_position), axis=0)
        risk_ubound = np.concatenate((risk_ubound, np.inf * np.ones((n, 1))), axis=0)

        cons_matrix = np.concatenate((risk_constraints, risk_lbound, risk_ubound), axis=1)
        opt = LPOptimizer(cons_matrix, lbound, ubound, -er)

        status = opt.status()

        if status == 0:
            status = 'optimal'

        return status, opt.feval(), opt.x_value()[:n]