Coverage for src / fast_minimum_variance / __init__.py: 100%
13 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-05-09 14:08 +0000
« prev ^ index » next coverage.py v7.13.5, created at 2026-05-09 14:08 +0000
1"""fast_minimum_variance — fast solvers for the minimum-variance portfolio."""
3import numpy as np
5from .minvar_problem import _MinVarProblem
6from .problem import _Problem
9def Problem( # noqa: N802
10 X: np.ndarray, # noqa: N803
11 target: np.ndarray | None = None,
12 A: np.ndarray | None = None, # noqa: N803
13 b: np.ndarray | None = None,
14 C: np.ndarray | None = None, # noqa: N803
15 d: np.ndarray | None = None,
16 alpha: float = 0.0,
17 rho: float = 0.0,
18 mu: np.ndarray | None = None,
19):
20 """Create a portfolio optimisation problem.
22 Returns a :class:`_MinVarProblem` (shrinking active-set) when no custom
23 constraints are supplied, or a :class:`_Problem` (growing active-set) when
24 any of ``A``, ``b``, ``C``, ``d`` are provided.
26 Args:
27 X: Returns matrix of shape ``(T, N)``.
28 target: Optional ``(N, N)`` regularisation matrix; when supplied the
29 shrinkage term ``alpha * ||target @ w||^2`` is added to the
30 objective. ``None`` disables shrinkage entirely.
31 A: Equality constraint matrix ``(N, m)``: ``A^T w = b``.
32 b: Equality RHS ``(m,)``.
33 C: Inequality constraint matrix ``(N, p)``: ``C^T w <= d``.
34 d: Inequality RHS ``(p,)``.
35 alpha: Shrinkage intensity; only active when ``target`` is provided.
36 rho: Return tilt strength (Markowitz mean-variance).
37 mu: Expected returns vector ``(N,)``; required when ``rho != 0``.
39 Returns:
40 A solver instance with ``solve_kkt()``, ``solve_minres()``,
41 ``solve_cg()``, and ``solve_cvxpy()`` methods, each returning
42 ``(w, n_iters)``.
44 Examples:
45 >>> import numpy as np
46 >>> X = np.random.default_rng(42).standard_normal((500, 20))
47 >>> w, _ = Problem(X).solve_kkt()
48 >>> float(round(w.sum(), 8))
49 1.0
50 >>> bool((w >= 0).all())
51 True
52 """
53 if A is None and b is None and C is None and d is None:
54 return _MinVarProblem(X, target=target, alpha=alpha, rho=rho, mu=mu)
56 # number of assets
57 n = X.shape[1]
59 A = A if A is not None else np.ones((n, 0)) # noqa: N806
60 b = b if b is not None else np.ones(1)
61 C = C if C is not None else -np.eye(n) # noqa: N806
62 d = d if d is not None else np.zeros(n)
64 return _Problem(X, target=target, A=A, b=b, C=C, d=d, alpha=alpha, rho=rho, mu=mu)
67__all__ = ["Problem"]