Coverage for src/jquantstats/_portfolio_base.py: 100%
4 statements
« prev ^ index » next coverage.py v7.15.3, created at 2026-08-06 04:52 +0000
« prev ^ index » next coverage.py v7.15.3, created at 2026-08-06 04:52 +0000
1"""Shared type-only declarations for the Portfolio mixins.
3The four Portfolio mixins (`PortfolioNavMixin`, `PortfolioAttributionMixin`,
4`PortfolioTurnoverMixin`, `PortfolioCostMixin`) each consume attributes and
5properties that are actually defined on *sibling* mixins or on the composed
6`Portfolio` dataclass itself. So that every mixin type-checks in isolation under
7``mypy --strict``, they all inherit this base, which declares that shared
8surface once under ``TYPE_CHECKING``.
10At runtime the body is skipped entirely, so `_PortfolioMembers` is an empty
11class: it adds nothing to instance layout (the mixins are slot-free already) and
12nothing to behaviour — it exists purely to give the type checker a single source
13of truth for the cross-mixin surface instead of repeating the stubs in every
14mixin module.
15"""
17from __future__ import annotations
19from typing import TYPE_CHECKING
21import polars as pl
23if TYPE_CHECKING:
24 from .data import Data
27class _PortfolioMembers:
28 """Type-only declaration of the cross-mixin Portfolio surface (see module docstring)."""
30 if TYPE_CHECKING:
31 # Raw inputs — real ``Portfolio`` dataclass fields.
32 cashposition: pl.DataFrame
33 prices: pl.DataFrame
34 aum: float
35 cost_per_unit: float
36 cost_bps: float
37 annual_fee: float
39 # Derived series / accessors defined on sibling mixins or ``Portfolio``.
40 @property
41 def data(self) -> Data:
42 """Bridge to the legacy `Data` object (defined on `Portfolio`)."""
44 @property
45 def assets(self) -> list[str]:
46 """Asset column names (defined on `Portfolio`)."""
48 @property
49 def returns(self) -> pl.DataFrame:
50 """Daily returns (defined on `PortfolioNavMixin`)."""
52 @property
53 def profit(self) -> pl.DataFrame:
54 """Aggregate daily portfolio profit (defined on `PortfolioNavMixin`)."""
56 @property
57 def nav_accumulated(self) -> pl.DataFrame:
58 """Cumulative additive NAV (defined on `PortfolioNavMixin`)."""
60 @property
61 def turnover(self) -> pl.DataFrame:
62 """Turnover frame (defined on `PortfolioTurnoverMixin`)."""