diff --git a/cvx/risk/bounds.py b/cvx/risk/bounds.py new file mode 100644 index 00000000..4acf9d4b --- /dev/null +++ b/cvx/risk/bounds.py @@ -0,0 +1,49 @@ +# -*- coding: utf-8 -*- +"""Bounds""" +from __future__ import annotations + +from dataclasses import dataclass + +import cvxpy as cp +import numpy as np + +from cvx.risk import Model + + +@dataclass +class Bounds(Model): + m: int = 0 + + def estimate(self, weights, **kwargs): + """No estimation for bounds""" + raise NotImplementedError("No estimation for bounds") + + def __post_init__(self): + self.parameter["lower"] = cp.Parameter( + shape=self.m, + name="lower bound", + value=np.zeros(self.m), + ) + self.parameter["upper"] = cp.Parameter( + shape=self.m, + name="upper bound", + value=np.ones(self.m), + ) + + def update(self, **kwargs): + # lower = kwargs.get("lower", np.zeros(self.m)) + lower = kwargs["lower"] + self.parameter["lower"].value = np.zeros(self.m) + self.parameter["lower"].value[: len(lower)] = lower + + upper = kwargs["upper"] # .get("upper", np.ones(self.m)) + self.parameter["upper"].value = np.zeros(self.m) + self.parameter["upper"].value[ + : len(upper) + ] = upper # kwargs.get("upper", np.ones(m)) + + def constraints(self, weights, **kwargs): + return [ + weights >= self.parameter["lower"], + weights <= self.parameter["upper"], + ] diff --git a/cvx/risk/cvar/cvar.py b/cvx/risk/cvar/cvar.py index 007189cc..4b3377a5 100644 --- a/cvx/risk/cvar/cvar.py +++ b/cvx/risk/cvar/cvar.py @@ -6,7 +6,7 @@ import cvxpy as cvx import numpy as np -from cvx.risk.model import Bounds +from cvx.risk.bounds import Bounds from cvx.risk.model import Model diff --git a/cvx/risk/factor/factor.py b/cvx/risk/factor/factor.py index bc3d1073..7c74115b 100644 --- a/cvx/risk/factor/factor.py +++ b/cvx/risk/factor/factor.py @@ -9,7 +9,7 @@ import numpy as np from cvx.linalg import cholesky -from cvx.risk.model import Bounds +from cvx.risk.bounds import Bounds from cvx.risk.model import Model diff --git a/cvx/risk/model.py b/cvx/risk/model.py index 197623a9..2b1c74fc 100644 --- a/cvx/risk/model.py +++ b/cvx/risk/model.py @@ -10,7 +10,6 @@ from typing import Dict import cvxpy as cp -import numpy as np @dataclass @@ -36,41 +35,3 @@ def constraints(self, weights, **kwargs): """ Return the constraints for the risk model """ - - -@dataclass -class Bounds(Model): - m: int = 0 - - def estimate(self, weights, **kwargs): - """No estimation for bounds""" - raise NotImplementedError("No estimation for bounds") - - def __post_init__(self): - self.parameter["lower"] = cp.Parameter( - shape=self.m, - name="lower bound", - value=np.zeros(self.m), - ) - self.parameter["upper"] = cp.Parameter( - shape=self.m, - name="upper bound", - value=np.ones(self.m), - ) - - def update(self, **kwargs): - lower = kwargs.get("lower", np.zeros(self.m)) - self.parameter["lower"].value = np.zeros(self.m) - self.parameter["lower"].value[: len(lower)] = lower - - upper = kwargs.get("upper", np.ones(self.m)) - self.parameter["upper"].value = np.zeros(self.m) - self.parameter["upper"].value[ - : len(upper) - ] = upper # kwargs.get("upper", np.ones(m)) - - def constraints(self, weights, **kwargs): - return [ - weights >= self.parameter["lower"], - weights <= self.parameter["upper"], - ] diff --git a/cvx/risk/sample/sample.py b/cvx/risk/sample/sample.py index b2e2e7a8..836b5206 100644 --- a/cvx/risk/sample/sample.py +++ b/cvx/risk/sample/sample.py @@ -9,7 +9,7 @@ import numpy as np from cvx.linalg import cholesky -from cvx.risk.model import Bounds +from cvx.risk.bounds import Bounds from cvx.risk.model import Model diff --git a/tests/test_risk/test_bounds.py b/tests/test_risk/test_bounds.py index 1c2e4723..e69d4098 100644 --- a/tests/test_risk/test_bounds.py +++ b/tests/test_risk/test_bounds.py @@ -5,7 +5,7 @@ import numpy as np import pytest -from cvx.risk.model import Bounds +from cvx.risk.bounds import Bounds def test_raise_not_implemented(): @@ -16,15 +16,6 @@ def test_raise_not_implemented(): bounds.estimate(weights) -def test_implicit_update(): - weights = cp.Variable(3) - bounds = Bounds(m=3) - bounds.update() - - assert bounds.parameter["lower"].value == pytest.approx(np.array([0, 0, 0])) - assert bounds.parameter["upper"].value == pytest.approx(np.array([1, 1, 1])) - - def test_constraints(): weights = cp.Variable(3) bounds = Bounds(m=3)