Coverage for src / cvx / markowitz / models / trading_costs.py: 100%
17 statements
« prev ^ index » next coverage.py v7.12.0, created at 2025-12-08 13:49 +0000
« prev ^ index » next coverage.py v7.12.0, created at 2025-12-08 13:49 +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"""Model for trading costs."""
16from __future__ import annotations
18from dataclasses import dataclass
20import cvxpy as cp
21import numpy as np
23from cvx.markowitz.model import Model
24from cvx.markowitz.names import DataNames as D
25from cvx.markowitz.types import Expressions, Matrix, Parameter, Variables # noqa: F401
26from cvx.markowitz.utils.fill import fill_vector
29@dataclass(frozen=True)
30class TradingCosts(Model):
31 """Model for trading costs."""
33 def __post_init__(self) -> None:
34 """Initialize trading cost parameters and previous-weights cache."""
35 self.parameter["power"] = cp.Parameter(shape=1, name="power", value=np.ones(1))
37 # initial weights before rebalancing
38 self.data["weights"] = cp.Parameter(shape=self.assets, name="weights", value=np.zeros(self.assets))
40 def estimate(self, variables: Variables) -> cp.Expression:
41 """Estimate trading costs for a rebalance.
43 Args:
44 variables: Optimization variables, expected to contain D.WEIGHTS.
46 Returns:
47 A convex expression representing the p-power cost of trades
48 between current and previous weights.
49 """
50 return cp.sum(
51 cp.power(
52 cp.abs(variables[D.WEIGHTS] - self.data["weights"]),
53 p=self.parameter["power"],
54 )
55 )
57 def update(self, **kwargs: Matrix) -> None:
58 """Update cached data values.
60 Expected keyword arguments:
61 weights: Vector of previous weights used as the trading baseline.
62 """
63 self.data["weights"].value = fill_vector(num=self.assets, x=kwargs["weights"])