Coverage for src / jquantstats / _reports / _protocol.py: 100%
3 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-03-26 18:44 +0000
« prev ^ index » next coverage.py v7.13.5, created at 2026-03-26 18:44 +0000
1"""Protocols describing the minimal interfaces required by the _reports subpackage."""
3from __future__ import annotations
5from typing import Protocol, runtime_checkable
7import polars as pl
10@runtime_checkable
11class StatsLike(Protocol): # pragma: no cover
12 """Structural interface for the statistics methods used by :class:`~jquantstats._reports._data.Reports`."""
14 def sharpe(self, periods: int | float | None = None) -> dict[str, float]:
15 """Annualised Sharpe ratio per asset."""
16 ...
18 def sortino(self, periods: int | float | None = None) -> dict[str, float]:
19 """Annualised Sortino ratio per asset."""
20 ...
22 def max_drawdown(self) -> dict[str, float]:
23 """Maximum drawdown per asset."""
24 ...
26 def volatility(self, periods: int | float | None = None) -> dict[str, float]:
27 """Annualised volatility per asset."""
28 ...
30 def value_at_risk(self, alpha: float = 0.05) -> dict[str, float]:
31 """Value at Risk per asset."""
32 ...
34 def win_loss_ratio(self) -> dict[str, float]:
35 """Win/loss ratio per asset."""
36 ...
38 def skew(self) -> dict[str, float]:
39 """Skewness per asset."""
40 ...
42 def kurtosis(self) -> dict[str, float]:
43 """Kurtosis per asset."""
44 ...
46 def summary(self) -> pl.DataFrame:
47 """Full summary DataFrame (one row per metric, one column per asset)."""
48 ...
51@runtime_checkable
52class DataLike(Protocol): # pragma: no cover
53 """Structural interface required by the :class:`~jquantstats._reports._data.Reports` class.
55 Any object satisfying this protocol can be passed as ``data`` without a
56 concrete dependency on :class:`~jquantstats._data.Data`.
57 """
59 @property
60 def stats(self) -> StatsLike:
61 """Statistics facade."""
62 ...
65@runtime_checkable
66class PlotsLike(Protocol): # pragma: no cover
67 """Structural interface for the portfolio plots facade used by :class:`~jquantstats._reports._portfolio.Report`."""
69 def snapshot(self) -> object:
70 """NAV + drawdown snapshot figure."""
71 ...
73 def rolling_sharpe_plot(self) -> object:
74 """Rolling Sharpe figure."""
75 ...
77 def rolling_volatility_plot(self) -> object:
78 """Rolling volatility figure."""
79 ...
81 def annual_sharpe_plot(self) -> object:
82 """Annual Sharpe figure."""
83 ...
85 def monthly_returns_heatmap(self) -> object:
86 """Monthly returns heatmap figure."""
87 ...
89 def correlation_heatmap(self) -> object:
90 """Correlation heatmap figure."""
91 ...
93 def lead_lag_ir_plot(self) -> object:
94 """Lead/lag IR figure."""
95 ...
97 def trading_cost_impact_plot(self) -> object:
98 """Trading cost impact figure."""
99 ...
102@runtime_checkable
103class PortfolioLike(Protocol): # pragma: no cover
104 """Structural interface required by the :class:`~jquantstats._reports._portfolio.Report` class.
106 Any object satisfying this protocol can be passed as ``portfolio`` without a
107 concrete dependency on :class:`~jquantstats.portfolio.Portfolio`.
108 """
110 prices: pl.DataFrame
111 aum: float
113 @property
114 def assets(self) -> list[str]:
115 """Asset names."""
116 ...
118 @property
119 def plots(self) -> PlotsLike:
120 """Portfolio plots facade."""
121 ...
123 @property
124 def stats(self) -> StatsLike:
125 """Statistics facade."""
126 ...
128 def turnover_summary(self) -> pl.DataFrame:
129 """Turnover summary DataFrame."""
130 ...