Commit 18a6bd84 authored by Dr.李's avatar Dr.李

using cvxpy's ecos solver in linear optimization case

parent a63cf5e2
Subproject commit 299865f2a9a80213c844fab849d1eb0a002246ce
Subproject commit fcb2195d34732d8f845738f0dd24d1c60c9644cc
......@@ -18,7 +18,7 @@ def linear_builder(er: np.ndarray,
risk_target: Tuple[np.ndarray, np.ndarray],
turn_over_target: float = None,
current_position: np.ndarray = None,
method: str='simplex') -> Tuple[str, np.ndarray, np.ndarray]:
method: str='ecos') -> Tuple[str, np.ndarray, np.ndarray]:
er = er.flatten()
n, m = risk_constraints.shape
......@@ -46,15 +46,16 @@ def linear_builder(er: np.ndarray,
return status, opt.feval(), opt.x_value()
else:
if method in ("simplex", "interior"):
# we need to expand bounded condition and constraint matrix to handle L1 bound
w_l_bound = np.minimum(np.maximum(np.abs(current_position - lbound),
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_l_bound.flatten()), 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)
......@@ -75,11 +76,11 @@ def linear_builder(er: np.ndarray,
risk_constraints = np.concatenate((risk_constraints, turn_over_matrix), axis=0)
risk_lbound = np.concatenate((risk_lbound, current_position), 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, 2. * w_l_bound), 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, method)
......@@ -90,6 +91,29 @@ def linear_builder(er: np.ndarray,
status = 'optimal'
return status, opt.feval(), opt.x_value()[:n]
elif method.lower() == 'ecos':
from cvxpy import Problem
from cvxpy import Variable
from cvxpy import multiply
from cvxpy import pnorm
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(),
pnorm(w - current_position, 1) <= turn_over_target]
objective = Minimize(-w.T * er)
prob = Problem(objective, constraints)
prob.solve(solver='ECOS')
return prob.status, prob.value, w.value.flatten()
else:
raise ValueError("{0} is not recognized".format(method))
if __name__ == '__main__':
......@@ -111,7 +135,8 @@ if __name__ == '__main__':
cons,
(risk_lbound, risk_ubound),
turn_over_target,
current_pos)
current_pos,
method='ecos')
print(status)
print(fvalue)
......
......@@ -110,6 +110,36 @@ class TestLinearBuild(unittest.TestCase):
calc_risk = (w - bm) @ self.risk_exp / np.abs(bm @ self.risk_exp)
self.assertTrue(np.all(np.abs(calc_risk) <= 1.0001e-2))
def test_linear_build_with_to_constraint_with_ecos(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_builder(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,
method='ecos')
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))
if __name__ == '__main__':
unittest.main()
arrow >= 0.10.0
cython >= 0.25.2
cvxpy >= 1.0.3
deprecated >= 1.1.0
ecos >= 2.0.4
numpy >= 1.12.1
pandas >= 0.19.2
scikit-learn >= 0.18.1
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment