Coverage for cvxrisk/sample/sample.py: 100%
22 statements
« prev ^ index » next coverage.py v7.8.2, created at 2025-06-18 11:11 +0000
« prev ^ index » next coverage.py v7.8.2, created at 2025-06-18 11:11 +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"""Risk models based on the sample covariance matrix."""
16from __future__ import annotations
18from dataclasses import dataclass
20import cvxpy as cvx
21import numpy as np
23from ..bounds import Bounds
24from ..linalg import cholesky
25from ..model import Model
28@dataclass
29class SampleCovariance(Model):
30 """Risk model based on the Cholesky decomposition of the sample cov matrix."""
32 num: int = 0
34 def __post_init__(self):
35 """Initialize the parameters after the class is instantiated.
37 Creates the Cholesky decomposition parameter and initializes the bounds.
38 """
39 self.parameter["chol"] = cvx.Parameter(
40 shape=(self.num, self.num),
41 name="cholesky of covariance",
42 value=np.zeros((self.num, self.num)),
43 )
44 self.bounds = Bounds(m=self.num, name="assets")
46 def estimate(self, weights: cvx.Variable, **kwargs) -> cvx.Expression:
47 """Estimate the portfolio risk using the Cholesky decomposition of the covariance matrix.
49 Computes the L2 norm of the product of the Cholesky factor and the weights vector,
50 which is equivalent to the square root of the portfolio variance.
52 Args:
53 weights: CVXPY variable representing portfolio weights
55 **kwargs: Additional keyword arguments (not used)
57 Returns:
58 CVXPY expression: The portfolio risk (standard deviation)
60 """
61 return cvx.norm2(self.parameter["chol"] @ weights)
63 def update(self, **kwargs) -> None:
64 """Update the Cholesky decomposition parameter and bounds.
66 Args:
67 **kwargs: Keyword arguments containing:
68 - cov: Covariance matrix (numpy.ndarray)
69 - Other parameters passed to bounds.update()
71 """
72 cov = kwargs["cov"]
73 n = cov.shape[0]
75 self.parameter["chol"].value[:n, :n] = cholesky(cov)
76 self.bounds.update(**kwargs)
78 def constraints(self, weights: cvx.Variable, **kwargs) -> list[cvx.Constraint]:
79 """Return constraints for the sample covariance model.
81 Args:
82 weights: CVXPY variable representing portfolio weights
84 **kwargs: Additional keyword arguments (not used)
86 Returns:
87 List of CVXPY constraints from the bounds object
89 """
90 return self.bounds.constraints(weights)