def test_mean_variance_builder_with_none_unity_lambda(self):
        er = np.array([0.01, 0.02, 0.03])
        cov = np.array([[0.02, 0.01, 0.02], [0.01, 0.02, 0.03],
                        [0.02, 0.03, 0.02]])
        ids_var = np.diag([0.01, 0.02, 0.03])
        cov += ids_var

        bm = np.array([0.3, 0.3, 0.4])
        lbound = np.array([0., 0., 0.])
        ubound = np.array([0.4, 0.4, 0.5])

        risk_exposure = np.array([[1., 1., 1.], [1., 0., 1.]]).T
        risk_target = (np.array([bm.sum(), 0.3]), np.array([bm.sum(), 0.7]))

        model = dict(cov=cov,
                     factor_cov=None,
                     factor_loading=None,
                     idsync=None)
        status, _, x = mean_variance_builder(er,
                                             model,
                                             bm,
                                             lbound,
                                             ubound,
                                             risk_exposure,
                                             risk_target,
                                             lam=100)

        self.assertTrue(status == 'optimal')
        self.assertAlmostEqual(x.sum(), bm.sum())
        self.assertTrue(np.all(x <= ubound + 1.e-6))
        self.assertTrue(np.all(x >= lbound) - 1.e-6)
        self.assertTrue(np.all(x @ risk_exposure <= risk_target[1] + 1.e-6))
        self.assertTrue(np.all(x @ risk_exposure >= risk_target[0] - 1.e-6))
        np.testing.assert_array_almost_equal(x, [0.2950, 0.3000, 0.4050])
Exemple #2
0
    def test_mean_variance_builder(self):
        er = np.array([0.01, 0.02, 0.03])
        cov = np.array([[0.02, 0.01, 0.02],
                        [0.01, 0.02, 0.03],
                        [0.02, 0.03, 0.02]])
        ids_var = np.diag([0.01, 0.02, 0.03])
        cov += ids_var

        bm = np.array([0.3, 0.3, 0.4])
        lbound = np.array([0., 0., 0.])
        ubound = np.array([0.4, 0.4, 0.5])

        risk_exposure = np.array([[1., 1., 1.],
                                  [1., 0., 1.]]).T
        risk_target = (np.array([bm.sum(), 0.3]), np.array([bm.sum(), 0.7]))

        status, _, x = mean_variance_builder(er, cov, bm, lbound, ubound, risk_exposure, risk_target)

        self.assertTrue(status == 'optimal')
        self.assertAlmostEqual(x.sum(), bm.sum())
        self.assertTrue(np.all(x <= ubound + 1.e-6))
        self.assertTrue(np.all(x >= lbound) - 1.e-6)
        self.assertTrue(np.all(x @ risk_exposure <= risk_target[1] + 1.e-6))
        self.assertTrue(np.all(x @ risk_exposure >= risk_target[0] - 1.e-6))
        np.testing.assert_array_almost_equal(x, [0.1, 0.4, 0.5])
    def test_mean_variance_builder_without_constraints(self):
        er = np.array([0.01, 0.02, 0.03])
        cov = np.array([[0.02, 0.01, 0.02], [0.01, 0.02, 0.03],
                        [0.02, 0.03, 0.02]])
        ids_var = np.diag([0.01, 0.02, 0.03])
        cov += ids_var

        bm = np.array([0., 0., 0.])

        model = dict(cov=cov,
                     factor_cov=None,
                     factor_loading=None,
                     idsync=None)
        status, _, x = mean_variance_builder(er,
                                             model,
                                             bm,
                                             None,
                                             None,
                                             None,
                                             None,
                                             lam=1)
        np.testing.assert_array_almost_equal(x, np.linalg.inv(cov) @ er)
Exemple #4
0
def er_portfolio_analysis(
        er: np.ndarray,
        industry: np.ndarray,
        dx_return: np.ndarray,
        constraints: Optional[Union[LinearConstraints, Constraints]] = None,
        detail_analysis=True,
        benchmark: Optional[np.ndarray] = None,
        is_tradable: Optional[np.ndarray] = None,
        method='risk_neutral',
        **kwargs) -> Tuple[pd.DataFrame, Optional[pd.DataFrame]]:
    er = er.flatten()

    def create_constraints(benchmark, **kwargs):
        if 'lbound' in kwargs:
            lbound = kwargs['lbound'].copy()
            del kwargs['lbound']
        else:
            lbound = np.maximum(0., benchmark - 0.01)

        if 'ubound' in kwargs:
            ubound = kwargs['ubound'].copy()
            del kwargs['ubound']
        else:
            ubound = 0.01 + benchmark
        if is_tradable is not None:
            ubound[~is_tradable] = np.minimum(lbound, ubound)[~is_tradable]

        risk_lbound, risk_ubound = constraints.risk_targets()
        cons_exp = constraints.risk_exp
        return lbound, ubound, cons_exp, risk_lbound, risk_ubound

    if method == 'risk_neutral':
        lbound, ubound, cons_exp, risk_lbound, risk_ubound = create_constraints(
            benchmark, **kwargs)

        turn_over_target = kwargs.get('turn_over_target')
        current_position = kwargs.get('current_position')

        status, _, weights = linear_builder(er,
                                            risk_constraints=cons_exp,
                                            lbound=lbound,
                                            ubound=ubound,
                                            risk_target=(risk_lbound,
                                                         risk_ubound),
                                            turn_over_target=turn_over_target,
                                            current_position=current_position)
        if status != 'optimal':
            raise ValueError(
                'linear programming optimizer in status: {0}'.format(status))

    elif method == 'rank':
        weights = rank_build(
            er, use_rank=kwargs['use_rank'],
            masks=is_tradable).flatten() * benchmark.sum() / kwargs['use_rank']
    elif method == 'ls' or method == 'long_short':
        weights = long_short_builder(er).flatten()
    elif method == 'mv' or method == 'mean_variance':
        lbound, ubound, cons_exp, risk_lbound, risk_ubound = create_constraints(
            benchmark, **kwargs)
        cov = kwargs['cov']

        if 'lam' in kwargs:
            lam = kwargs['lam']
        else:
            lam = 1.

        status, _, weights = mean_variance_builder(er,
                                                   cov=cov,
                                                   bm=benchmark,
                                                   lbound=lbound,
                                                   ubound=ubound,
                                                   risk_exposure=cons_exp,
                                                   risk_target=(risk_lbound,
                                                                risk_ubound),
                                                   lam=lam)
        if status != 'optimal':
            raise ValueError(
                'mean variance optimizer in status: {0}'.format(status))

    elif method == 'tv' or method == 'target_vol':
        lbound, ubound, cons_exp, risk_lbound, risk_ubound = create_constraints(
            benchmark, **kwargs)
        cov = kwargs['cov']

        if 'target_vol' in kwargs:
            target_vol = kwargs['target_vol']
        else:
            target_vol = 1.

        status, _, weights = target_vol_builder(er,
                                                cov=cov,
                                                bm=benchmark,
                                                lbound=lbound,
                                                ubound=ubound,
                                                risk_exposure=cons_exp,
                                                risk_target=(risk_lbound,
                                                             risk_ubound),
                                                vol_low=0,
                                                vol_high=target_vol)
    else:
        raise ValueError("Unknown building type ({0})".format(method))

    if detail_analysis:
        analysis = simple_settle(weights, dx_return, industry, benchmark)
    else:
        analysis = None
    return pd.DataFrame({'weight': weights,
                         'industry': industry,
                         'er': er}), \
           analysis