Coverage for src / cvx / risk / model.py: 100%
14 statements
« prev ^ index » next coverage.py v7.13.0, created at 2025-12-15 12:21 +0000
« prev ^ index » next coverage.py v7.13.0, created at 2025-12-15 12:21 +0000
1# Copyright 2023 Stanford University Convex Optimization Group
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14"""Abstract risk model.
16This module provides the abstract base class for all risk models in cvxrisk.
17Risk models are used to estimate portfolio risk and provide constraints for
18portfolio optimization problems.
20Example:
21 All risk models inherit from the Model class and must implement
22 the estimate, update, and constraints methods:
24 >>> import cvxpy as cp
25 >>> import numpy as np
26 >>> from cvx.risk.sample import SampleCovariance
27 >>> # Create a sample covariance risk model
28 >>> model = SampleCovariance(num=3)
29 >>> # Update the model with a covariance matrix
30 >>> cov = np.array([[1.0, 0.5, 0.0], [0.5, 1.0, 0.5], [0.0, 0.5, 1.0]])
31 >>> model.update(cov=cov, lower_assets=np.zeros(3), upper_assets=np.ones(3))
32 >>> # Create a weights variable and estimate risk
33 >>> weights = cp.Variable(3)
34 >>> risk_expr = model.estimate(weights)
35 >>> isinstance(risk_expr, cp.Expression)
36 True
38"""
40from __future__ import annotations
42from abc import ABC, abstractmethod
43from dataclasses import dataclass, field
45import cvxpy as cp
48@dataclass
49class Model(ABC):
50 """Abstract base class for risk models.
52 This class defines the interface that all risk models must implement.
53 Risk models are used in portfolio optimization to estimate portfolio risk
54 and provide constraints for the optimization problem.
56 Attributes:
57 parameter: Dictionary mapping parameter names to CVXPY Parameter objects.
58 These parameters can be updated without reconstructing the optimization problem.
60 Example:
61 Subclasses must implement the abstract methods:
63 >>> import cvxpy as cp
64 >>> import numpy as np
65 >>> from cvx.risk.sample import SampleCovariance
66 >>> model = SampleCovariance(num=2)
67 >>> model.update(
68 ... cov=np.array([[1.0, 0.5], [0.5, 2.0]]),
69 ... lower_assets=np.zeros(2),
70 ... upper_assets=np.ones(2)
71 ... )
72 >>> # Access model parameters
73 >>> 'chol' in model.parameter
74 True
76 """
78 parameter: dict[str, cp.Parameter] = field(default_factory=dict)
79 """Dictionary of CVXPY parameters for the risk model."""
81 @abstractmethod
82 def estimate(self, weights: cp.Variable, **kwargs) -> cp.Expression:
83 """Estimate the variance given the portfolio weights.
85 This method returns a CVXPY expression representing the risk measure
86 for the given portfolio weights. The expression can be used as an
87 objective function in a convex optimization problem.
89 Args:
90 weights: CVXPY variable representing portfolio weights.
91 **kwargs: Additional keyword arguments specific to the risk model.
93 Returns:
94 CVXPY expression representing the estimated risk (e.g., standard deviation).
96 Example:
97 >>> import cvxpy as cp
98 >>> import numpy as np
99 >>> from cvx.risk.sample import SampleCovariance
100 >>> model = SampleCovariance(num=2)
101 >>> model.update(
102 ... cov=np.array([[1.0, 0.0], [0.0, 1.0]]),
103 ... lower_assets=np.zeros(2),
104 ... upper_assets=np.ones(2)
105 ... )
106 >>> weights = cp.Variable(2)
107 >>> risk = model.estimate(weights)
108 >>> isinstance(risk, cp.Expression)
109 True
111 """
113 @abstractmethod
114 def update(self, **kwargs) -> None:
115 """Update the data in the risk model.
117 This method updates the CVXPY parameters in the model with new data.
118 Because CVXPY supports parametric optimization, updating parameters
119 allows solving new problem instances without reconstructing the problem.
121 Args:
122 **kwargs: Keyword arguments containing data to update the model.
123 The specific arguments depend on the risk model implementation.
125 Example:
126 >>> import numpy as np
127 >>> from cvx.risk.sample import SampleCovariance
128 >>> model = SampleCovariance(num=3)
129 >>> # Update with new covariance data
130 >>> cov = np.array([[1.0, 0.5, 0.0], [0.5, 1.0, 0.5], [0.0, 0.5, 1.0]])
131 >>> model.update(
132 ... cov=cov,
133 ... lower_assets=np.zeros(3),
134 ... upper_assets=np.ones(3)
135 ... )
137 """
139 @abstractmethod
140 def constraints(self, weights: cp.Variable, **kwargs) -> list[cp.Constraint]:
141 """Return the constraints for the risk model.
143 This method returns a list of CVXPY constraints that should be included
144 in the portfolio optimization problem. Common constraints include bounds
145 on asset weights.
147 Args:
148 weights: CVXPY variable representing portfolio weights.
149 **kwargs: Additional keyword arguments specific to the risk model.
151 Returns:
152 List of CVXPY constraints for the risk model.
154 Example:
155 >>> import cvxpy as cp
156 >>> import numpy as np
157 >>> from cvx.risk.sample import SampleCovariance
158 >>> model = SampleCovariance(num=2)
159 >>> model.update(
160 ... cov=np.array([[1.0, 0.0], [0.0, 1.0]]),
161 ... lower_assets=np.zeros(2),
162 ... upper_assets=np.ones(2)
163 ... )
164 >>> weights = cp.Variable(2)
165 >>> constraints = model.constraints(weights)
166 >>> len(constraints) == 2 # Lower and upper bounds
167 True
169 """