Coverage for src/jquantstats/_reports/_protocol.py: 100%
6 statements
« prev ^ index » next coverage.py v7.14.1, created at 2026-06-23 06:13 +0000
« prev ^ index » next coverage.py v7.14.1, created at 2026-06-23 06:13 +0000
1"""Protocols describing the minimal interfaces required by the _reports subpackage."""
3from __future__ import annotations
5from typing import Protocol, runtime_checkable
7import plotly.graph_objects as go
8import polars as pl
10from jquantstats._protocol import DataLike, StatsLike
12__all__ = ["DataLike", "PlotsLike", "PortfolioLike", "StatsLike"]
15@runtime_checkable
16class PlotsLike(Protocol): # pragma: no cover
17 """Structural interface for the portfolio plots facade used by `Report`."""
19 def snapshot(self) -> go.Figure:
20 """NAV + drawdown snapshot figure."""
21 ...
23 def rolling_sharpe_plot(self) -> go.Figure:
24 """Rolling Sharpe figure."""
25 ...
27 def rolling_volatility_plot(self) -> go.Figure:
28 """Rolling volatility figure."""
29 ...
31 def annual_sharpe_plot(self) -> go.Figure:
32 """Annual Sharpe figure."""
33 ...
35 def monthly_returns_heatmap(self) -> go.Figure:
36 """Monthly returns heatmap figure."""
37 ...
39 def correlation_heatmap(self) -> go.Figure:
40 """Correlation heatmap figure."""
41 ...
43 def lead_lag_ir_plot(self) -> go.Figure:
44 """Lead/lag IR figure."""
45 ...
47 def trading_cost_impact_plot(self) -> go.Figure:
48 """Trading cost impact figure."""
49 ...
52@runtime_checkable
53class PortfolioLike(Protocol): # pragma: no cover
54 """Structural interface required by the `Report` class.
56 Any object satisfying this protocol can be passed as ``portfolio`` without a
57 concrete dependency on `Portfolio`.
58 """
60 @property
61 def prices(self) -> pl.DataFrame:
62 """Price (holding) DataFrame."""
63 ...
65 @property
66 def aum(self) -> float:
67 """Assets under management."""
68 ...
70 @property
71 def assets(self) -> list[str]:
72 """Asset names."""
73 ...
75 @property
76 def plots(self) -> PlotsLike:
77 """Portfolio plots facade."""
78 ...
80 @property
81 def stats(self) -> StatsLike:
82 """Statistics facade."""
83 ...
85 def turnover_summary(self) -> pl.DataFrame:
86 """Turnover summary DataFrame."""
87 ...