Commit 8ef605f0 authored by Dr.李's avatar Dr.李

simplified linear_build's interface and made it more generic

parent 19a75eb7
...@@ -28,9 +28,18 @@ def benchmark_build_linear(n_samples: int, n_risks: int, n_loop: int) -> None: ...@@ -28,9 +28,18 @@ def benchmark_build_linear(n_samples: int, n_risks: int, n_loop: int) -> None:
lbound = -0.04 lbound = -0.04
ubound = 0.05 ubound = 0.05
risk_lbound = bm @ risk_exp
risk_ubound = bm @ risk_exp
start = dt.datetime.now() start = dt.datetime.now()
for _ in range(n_loop): for _ in range(n_loop):
status, v, x = linear_build(er, lbound, ubound, risk_exp, bm, solver='ECOS') status, v, x = linear_build(er,
lbound,
ubound,
risk_exp,
risk_target=(risk_lbound,
risk_ubound),
solver='ECOS')
impl_model_time = dt.datetime.now() - start impl_model_time = dt.datetime.now() - start
print('{0:20s}: {1}'.format('Implemented model (ECOS)', impl_model_time)) print('{0:20s}: {1}'.format('Implemented model (ECOS)', impl_model_time))
......
...@@ -19,32 +19,21 @@ def linear_build(er: np.ndarray, ...@@ -19,32 +19,21 @@ def linear_build(er: np.ndarray,
lbound: Union[np.ndarray, float], lbound: Union[np.ndarray, float],
ubound: Union[np.ndarray, float], ubound: Union[np.ndarray, float],
risk_exposure: np.ndarray, risk_exposure: np.ndarray,
bm: np.ndarray, risk_target: Tuple[np.ndarray, np.ndarray],
risk_target: Tuple[np.ndarray, np.ndarray]=None,
exchange_flag: np.ndarray=None,
exchange_limit: Tuple[float, float]=None,
solver: str=None) -> Tuple[str, np.ndarray, np.ndarray]: solver: str=None) -> Tuple[str, np.ndarray, np.ndarray]:
n, m = risk_exposure.shape n, m = risk_exposure.shape
w = cvxpy.Variable(n) w = cvxpy.Variable(n)
curr_risk_exposure = risk_exposure.T @ (w - bm) curr_risk_exposure = risk_exposure.T @ w
if not risk_target: if not risk_target:
risk_eq_target = np.zeros(m)
constraints = [w >= lbound, constraints = [w >= lbound,
w <= ubound, w <= ubound]
curr_risk_exposure == risk_eq_target,
cvxpy.sum_entries(w) == bm.sum()]
else: else:
constraints = [w >= lbound, constraints = [w >= lbound,
w <= ubound, w <= ubound,
curr_risk_exposure >= risk_target[0] * np.abs(risk_exposure.T @ bm), curr_risk_exposure >= risk_target[0],
curr_risk_exposure <= risk_target[1] * np.abs(risk_exposure.T @ bm), curr_risk_exposure <= risk_target[1]]
cvxpy.sum_entries(w) == bm.sum()]
if exchange_flag is not None:
constraints.append(exchange_flag @ w <= exchange_limit[1])
constraints.append(exchange_flag @ w >= exchange_limit[0])
objective = cvxpy.Minimize(-w.T * er) objective = cvxpy.Minimize(-w.T * er)
prob = cvxpy.Problem(objective, constraints) prob = cvxpy.Problem(objective, constraints)
......
...@@ -15,19 +15,24 @@ class TestLinearBuild(unittest.TestCase): ...@@ -15,19 +15,24 @@ class TestLinearBuild(unittest.TestCase):
def setUp(self): def setUp(self):
self.er = np.random.randn(3000) self.er = np.random.randn(3000)
self.risk_exp = np.random.randn(3000, 30) self.risk_exp = np.random.randn(3000, 30)
self.risk_exp = np.concatenate([self.risk_exp, np.ones((3000, 1))], axis=1)
self.bm = np.random.randint(100, size=3000).astype(float) self.bm = np.random.randint(100, size=3000).astype(float)
def test_linear_build(self): def test_linear_build(self):
bm = self.bm / self.bm.sum() bm = self.bm / self.bm.sum()
eplson = 1e-6 eplson = 1e-6
status, _, w = linear_build(self.er, 0., 0.01, self.risk_exp, bm) 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.assertEqual(status, 'optimal')
self.assertAlmostEqual(np.sum(w), 1.) self.assertAlmostEqual(np.sum(w), 1.)
self.assertTrue(np.all(w <= 0.01 + eplson)) self.assertTrue(np.all(w <= 0.01 + eplson))
self.assertTrue(np.all(w >= -eplson)) self.assertTrue(np.all(w >= -eplson))
calc_risk = (w - bm) @self. risk_exp calc_risk = (w - bm) @ self. risk_exp
expected_risk = np.zeros(self.risk_exp.shape[1]) expected_risk = np.zeros(self.risk_exp.shape[1])
np.testing.assert_array_almost_equal(calc_risk, expected_risk) np.testing.assert_array_almost_equal(calc_risk, expected_risk)
...@@ -35,12 +40,19 @@ class TestLinearBuild(unittest.TestCase): ...@@ -35,12 +40,19 @@ class TestLinearBuild(unittest.TestCase):
bm = self.bm / self.bm.sum() bm = self.bm / self.bm.sum()
eplson = 1e-6 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, status, _, w = linear_build(self.er,
0., 0.,
0.01, 0.01,
self.risk_exp, self.risk_exp,
bm, risk_target=(risk_lbound, risk_ubound))
risk_target=(-1e-2, 1e-2))
self.assertEqual(status, 'optimal') self.assertEqual(status, 'optimal')
self.assertAlmostEqual(np.sum(w), 1.) self.assertAlmostEqual(np.sum(w), 1.)
self.assertTrue(np.all(w <= 0.01 + eplson)) self.assertTrue(np.all(w <= 0.01 + eplson))
......
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