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

1"""fast_minimum_variance — fast solvers for the minimum-variance portfolio.""" 

2 

3import numpy as np 

4 

5from .minvar_problem import _MinVarProblem 

6from .problem import _Problem 

7 

8 

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. 

21 

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. 

25 

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``. 

38 

39 Returns: 

40 A solver instance with ``solve_kkt()``, ``solve_minres()``, 

41 ``solve_cg()``, and ``solve_cvxpy()`` methods, each returning 

42 ``(w, n_iters)``. 

43 

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) 

55 

56 # number of assets 

57 n = X.shape[1] 

58 

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) 

63 

64 return _Problem(X, target=target, A=A, b=b, C=C, d=d, alpha=alpha, rho=rho, mu=mu) 

65 

66 

67__all__ = ["Problem"]