Coverage for src / cvx / risk / model.py: 100%

15 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-04-09 03:39 +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. 

15 

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. 

19 

20Example: 

21 All risk models inherit from the Model class and must implement 

22 the estimate, update, and constraints methods: 

23 

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 

37 

38""" 

39 

40from __future__ import annotations 

41 

42from abc import ABC, abstractmethod 

43from dataclasses import dataclass, field 

44from typing import Any 

45 

46import cvxpy as cp 

47 

48 

49@dataclass 

50class Model(ABC): 

51 """Abstract base class for risk models. 

52 

53 This class defines the interface that all risk models must implement. 

54 Risk models are used in portfolio optimization to estimate portfolio risk 

55 and provide constraints for the optimization problem. 

56 

57 Attributes: 

58 parameter: Dictionary mapping parameter names to CVXPY Parameter objects. 

59 These parameters can be updated without reconstructing the optimization problem. 

60 

61 Example: 

62 Subclasses must implement the abstract methods: 

63 

64 >>> import cvxpy as cp 

65 >>> import numpy as np 

66 >>> from cvx.risk.sample import SampleCovariance 

67 >>> model = SampleCovariance(num=2) 

68 >>> model.update( 

69 ... cov=np.array([[1.0, 0.5], [0.5, 2.0]]), 

70 ... lower_assets=np.zeros(2), 

71 ... upper_assets=np.ones(2) 

72 ... ) 

73 >>> # Access model parameters 

74 >>> 'chol' in model.parameter 

75 True 

76 

77 The parameter dictionary holds CVXPY Parameter objects that can be 

78 updated without reconstructing the optimization problem: 

79 

80 >>> param = model.parameter['chol'] 

81 >>> isinstance(param, cp.Parameter) 

82 True 

83 >>> param.shape 

84 (2, 2) 

85 

86 Multiple risk models can be composed by combining their constraints: 

87 

88 >>> from cvx.risk.bounds import Bounds 

89 >>> extra_bounds = Bounds(m=2, name="extra") 

90 >>> extra_bounds.update( 

91 ... lower_extra=np.array([0.2, 0.2]), 

92 ... upper_extra=np.array([0.8, 0.8]) 

93 ... ) 

94 >>> weights = cp.Variable(2) 

95 >>> all_constraints = model.constraints(weights) + extra_bounds.constraints(weights) 

96 >>> len(all_constraints) 

97 4 

98 

99 """ 

100 

101 parameter: dict[str, cp.Parameter] = field(default_factory=dict) 

102 """Dictionary of CVXPY parameters for the risk model.""" 

103 

104 @abstractmethod 

105 def estimate(self, weights: cp.Variable, **kwargs: Any) -> cp.Expression: 

106 """Estimate the variance given the portfolio weights. 

107 

108 This method returns a CVXPY expression representing the risk measure 

109 for the given portfolio weights. The expression can be used as an 

110 objective function in a convex optimization problem. 

111 

112 Args: 

113 weights: CVXPY variable representing portfolio weights. 

114 **kwargs: Additional keyword arguments specific to the risk model. 

115 

116 Returns: 

117 CVXPY expression representing the estimated risk (e.g., standard deviation). 

118 

119 Example: 

120 >>> import cvxpy as cp 

121 >>> import numpy as np 

122 >>> from cvx.risk.sample import SampleCovariance 

123 >>> model = SampleCovariance(num=2) 

124 >>> model.update( 

125 ... cov=np.array([[1.0, 0.0], [0.0, 1.0]]), 

126 ... lower_assets=np.zeros(2), 

127 ... upper_assets=np.ones(2) 

128 ... ) 

129 >>> weights = cp.Variable(2) 

130 >>> risk = model.estimate(weights) 

131 >>> isinstance(risk, cp.Expression) 

132 True 

133 

134 """ 

135 

136 @abstractmethod 

137 def update(self, **kwargs: Any) -> None: 

138 """Update the data in the risk model. 

139 

140 This method updates the CVXPY parameters in the model with new data. 

141 Because CVXPY supports parametric optimization, updating parameters 

142 allows solving new problem instances without reconstructing the problem. 

143 

144 Args: 

145 **kwargs: Keyword arguments containing data to update the model. 

146 The specific arguments depend on the risk model implementation. 

147 

148 Example: 

149 >>> import numpy as np 

150 >>> from cvx.risk.sample import SampleCovariance 

151 >>> model = SampleCovariance(num=3) 

152 >>> # Update with new covariance data 

153 >>> cov = np.array([[1.0, 0.5, 0.0], [0.5, 1.0, 0.5], [0.0, 0.5, 1.0]]) 

154 >>> model.update( 

155 ... cov=cov, 

156 ... lower_assets=np.zeros(3), 

157 ... upper_assets=np.ones(3) 

158 ... ) 

159 

160 """ 

161 

162 @abstractmethod 

163 def constraints(self, weights: cp.Variable, **kwargs: Any) -> list[cp.Constraint]: 

164 """Return the constraints for the risk model. 

165 

166 This method returns a list of CVXPY constraints that should be included 

167 in the portfolio optimization problem. Common constraints include bounds 

168 on asset weights. 

169 

170 Args: 

171 weights: CVXPY variable representing portfolio weights. 

172 **kwargs: Additional keyword arguments specific to the risk model. 

173 

174 Returns: 

175 List of CVXPY constraints for the risk model. 

176 

177 Example: 

178 >>> import cvxpy as cp 

179 >>> import numpy as np 

180 >>> from cvx.risk.sample import SampleCovariance 

181 >>> model = SampleCovariance(num=2) 

182 >>> model.update( 

183 ... cov=np.array([[1.0, 0.0], [0.0, 1.0]]), 

184 ... lower_assets=np.zeros(2), 

185 ... upper_assets=np.ones(2) 

186 ... ) 

187 >>> weights = cp.Variable(2) 

188 >>> constraints = model.constraints(weights) 

189 >>> len(constraints) == 2 # Lower and upper bounds 

190 True 

191 

192 """