Пример #1
0
    def test_linear_build_with_to_constraint(self):
        bm = self.bm / self.bm.sum()
        eplson = 1e-6
        turn_over_target = 0.1

        risk_lbound = bm @ self.risk_exp
        risk_ubound = bm @ self.risk_exp

        risk_tolerance = 0.01 * np.abs(risk_lbound[:-1])

        risk_lbound[:-1] = risk_lbound[:-1] - risk_tolerance
        risk_ubound[:-1] = risk_ubound[:-1] + risk_tolerance

        status, _, w = linear_build(self.er,
                                    0.,
                                    0.01,
                                    self.risk_exp,
                                    risk_target=(risk_lbound, risk_ubound),
                                    turn_over_target=turn_over_target,
                                    current_position=self.current_pos)
        self.assertEqual(status, 'optimal')
        self.assertAlmostEqual(np.sum(w), 1.)
        self.assertTrue(np.all(w <= 0.01 + eplson))
        self.assertTrue(np.all(w >= -eplson))
        self.assertAlmostEqual(
            np.abs(w - self.current_pos).sum(), turn_over_target)

        calc_risk = (w - bm) @ self.risk_exp / np.abs(bm @ self.risk_exp)
        self.assertTrue(np.all(np.abs(calc_risk) <= 1.0001e-2))
Пример #2
0
def benchmark_build_linear(n_samples: int, n_risks: int, n_loop: int) -> None:
    print("-" * 60)
    print("Starting portfolio construction by linear programming")
    print("Parameters(n_samples: {0}, n_risks: {1}, n_loop: {2})".format(n_samples, n_risks, n_loop))

    er = np.random.randn(n_samples)
    risk_exp = np.random.randn(n_samples, n_risks)
    bm = np.random.rand(n_samples)
    bm /= bm.sum()

    lbound = -0.04
    ubound = 0.05

    risk_lbound = bm @ risk_exp
    risk_ubound = bm @ risk_exp

    start = dt.datetime.now()
    for _ in range(n_loop):
        status, v, x = linear_build(er,
                                    lbound,
                                    ubound,
                                    risk_exp,
                                    risk_target=(risk_lbound,
                                                 risk_ubound))
    impl_model_time = dt.datetime.now() - start
    print('{0:20s}: {1}'.format('Implemented model (ECOS)', impl_model_time))

    c = - er
    bounds = [(lbound, ubound) for _ in range(n_samples)]
    a_eq = np.ones((1, n_samples))
    a_eq = np.vstack((a_eq, risk_exp.T))
    b_eq = np.hstack((np.array([1.]), risk_exp.T @ bm))
    start = dt.datetime.now()
    for _ in range(n_loop):
        res = linprog(c, A_eq=a_eq, b_eq=b_eq, bounds=bounds, options={'maxiter': 10000})
    benchmark_model_time = dt.datetime.now() - start
    print('{0:20s}: {1}'.format('Benchmark model (scipy)', benchmark_model_time))
    np.testing.assert_array_almost_equal(x, res['x'])

    c = matrix(-er)
    aneq = matrix(a_eq)
    b = matrix(b_eq)
    g = matrix(np.vstack((np.diag(np.ones(n_samples)), -np.diag(np.ones(n_samples)))))
    h = matrix(np.hstack((ubound * np.ones(n_samples), -lbound * np.ones(n_samples))))

    solvers.lp(c, g, h, solver='glpk')
    start = dt.datetime.now()
    for _ in range(n_loop):
        res2 = solvers.lp(c, g, h, aneq, b, solver='glpk')
    benchmark_model_time = dt.datetime.now() - start
    print('{0:20s}: {1}'.format('Benchmark model (glpk)', benchmark_model_time))
    np.testing.assert_array_almost_equal(x, np.array(res2['x']).flatten())
Пример #3
0
    def test_linear_build(self):
        bm = self.bm / self.bm.sum()
        eplson = 1e-6

        status, _, w = linear_build(self.er, 0., 0.01, self.risk_exp,
                                    (bm @ self.risk_exp, bm @ self.risk_exp))
        self.assertEqual(status, 'optimal')
        self.assertAlmostEqual(np.sum(w), 1.)
        self.assertTrue(np.all(w <= 0.01 + eplson))
        self.assertTrue(np.all(w >= -eplson))

        calc_risk = (w - bm) @ self.risk_exp
        expected_risk = np.zeros(self.risk_exp.shape[1])
        np.testing.assert_array_almost_equal(calc_risk, expected_risk)
Пример #4
0
def build_portfolio(er: np.ndarray,
                    builder: Optional[str] = 'long_short',
                    **kwargs) -> np.ndarray:

    builder = builder.lower()

    if builder == 'ls' or builder == 'long_short':
        return long_short_build(er, **kwargs).flatten()
    elif builder == 'rank':
        return rank_build(er, **kwargs).flatten()
    elif builder == 'percent':
        return percent_build(er, **kwargs).flatten()
    elif builder == 'linear_prog' or builder == 'linear':
        status, _, weight = linear_build(er, **kwargs)
        if status != 'optimal':
            raise ValueError(
                'linear programming optimizer in status: {0}'.format(status))
        else:
            return weight
Пример #5
0
    def test_linear_build_with_inequality_constraints(self):
        bm = self.bm / self.bm.sum()
        eplson = 1e-6

        risk_lbound = bm @ self.risk_exp
        risk_ubound = bm @ self.risk_exp

        risk_tolerance = 0.01 * np.abs(risk_lbound[:-1])

        risk_lbound[:-1] = risk_lbound[:-1] - risk_tolerance
        risk_ubound[:-1] = risk_ubound[:-1] + risk_tolerance

        status, _, w = linear_build(self.er,
                                    0.,
                                    0.01,
                                    self.risk_exp,
                                    risk_target=(risk_lbound, risk_ubound))
        self.assertEqual(status, 'optimal')
        self.assertAlmostEqual(np.sum(w), 1.)
        self.assertTrue(np.all(w <= 0.01 + eplson))
        self.assertTrue(np.all(w >= -eplson))

        calc_risk = (w - bm) @ self.risk_exp / np.abs(bm @ self.risk_exp)
        self.assertTrue(np.all(np.abs(calc_risk) <= 1e-2))
Пример #6
0
def er_portfolio_analysis(
        er: np.ndarray,
        industry: np.ndarray,
        dx_return: np.ndarray,
        constraints: Optional[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 = 0.

        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 benchmark is not None and 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_build(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_build(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))
    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
Пример #7
0
er = normed_factor @ factor_weights

# portfolio construction

bm = total_data[index_components].values
lbound = 0.
ubound = 0.01 + bm
lbound_exposure = -0.01
ubound_exposure = 0.01
risk_exposure = total_data[risk_factors_names].values

status, value, ret = linear_build(er,
                                  lbound=lbound,
                                  ubound=ubound,
                                  risk_exposure=risk_exposure,
                                  bm=bm,
                                  risk_target=(lbound_exposure,
                                               ubound_exposure),
                                  solver='GLPK')

if status != 'optimal':
    raise ValueError('target is not feasible')
else:
    portfolio = pd.DataFrame(
        {
            'weight': ret,
            'industry': total_data['申万一级行业'].values,
            'zz500': total_data[index_components].values
        },
        index=total_data.Code)