Coverage for src/fast_minimum_variance/__init__.py: 100%
14 statements
« prev ^ index » next coverage.py v7.15.0, created at 2026-07-02 13:28 +0000
« prev ^ index » next coverage.py v7.15.0, created at 2026-07-02 13:28 +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 target_lr: tuple[float, np.ndarray, np.ndarray] | None = None,
20 pcg_lr: tuple[float, np.ndarray, np.ndarray] | None = None,
21) -> _MinVarProblem | _Problem:
22 """Create a portfolio optimisation problem.
24 Returns a :class:`_MinVarProblem` (shrinking active-set) when no custom
25 constraints are supplied, or a :class:`_Problem` (growing active-set) when
26 any of ``A``, ``b``, ``C``, ``d`` are provided.
28 Args:
29 X: Returns matrix of shape ``(T, N)``.
30 target: Optional ``(N, N)`` regularisation matrix; when supplied the
31 shrinkage term ``alpha * ||target @ w||^2`` is added to the
32 objective. ``None`` disables shrinkage entirely.
33 A: Equality constraint matrix ``(N, m)``: ``A^T w = b``.
34 b: Equality RHS ``(m,)``.
35 C: Inequality constraint matrix ``(N, p)``: ``C^T w <= d``.
36 d: Inequality RHS ``(p,)``.
37 alpha: Shrinkage intensity; only active when ``target`` is provided.
38 rho: Return tilt strength (Markowitz mean-variance).
39 mu: Expected returns vector ``(N,)``; required when ``rho != 0``.
40 target_lr: Low-rank factored target ``(bar_lam, U_k, delta_k)`` for
41 RMT eigenvalue-cleaning; replaces ``target`` in the CG matvec.
42 pcg_lr: RMT preconditioner ``(bar_lam, U_k, delta_k)`` for
43 ``solve_pcg``; ignored unless PCG is invoked.
45 Returns:
46 A solver instance with ``solve_kkt()``, ``solve_minres()``,
47 ``solve_cg()``, and ``solve_cvxpy()`` methods, each returning
48 ``(w, n_iters)``.
50 Examples:
51 >>> import numpy as np
52 >>> X = np.random.default_rng(42).standard_normal((500, 20))
53 >>> w, _ = Problem(X).solve_kkt()
54 >>> float(round(w.sum(), 8))
55 1.0
56 >>> bool((w >= 0).all())
57 True
58 """
59 if A is None and b is None and C is None and d is None:
60 return _MinVarProblem(X, target=target, alpha=alpha, rho=rho, mu=mu, target_lr=target_lr, pcg_lr=pcg_lr)
62 # number of assets
63 n = X.shape[1]
65 A = A if A is not None else np.ones((n, 0)) # noqa: N806
66 b = b if b is not None else np.ones(1)
67 C = C if C is not None else -np.eye(n) # noqa: N806
68 d = d if d is not None else np.zeros(n)
70 return _Problem(X, target=target, A=A, b=b, C=C, d=d, alpha=alpha, rho=rho, mu=mu)
73from .data import simulate_equity_returns # noqa: E402
75__all__ = ["Problem", "simulate_equity_returns"]