Coverage for src/jquantstats/_reports/_protocol.py: 100%

5 statements  

« prev     ^ index     » next       coverage.py v7.16.1, created at 2026-09-23 04:11 +0000

1"""Protocols describing the minimal interfaces required by the _reports subpackage.""" 

2 

3from __future__ import annotations 

4 

5from typing import TYPE_CHECKING, Protocol, runtime_checkable 

6 

7import polars as pl 

8 

9from jquantstats._protocol import DataLike, StatsLike 

10 

11if TYPE_CHECKING: 

12 import plotly.graph_objects as go 

13 

14__all__ = ["DataLike", "PlotsLike", "PortfolioLike", "StatsLike"] 

15 

16 

17@runtime_checkable 

18class PlotsLike(Protocol): # pragma: no cover 

19 """Structural interface for the portfolio plots facade used by `Report`.""" 

20 

21 def snapshot(self) -> go.Figure: 

22 """NAV + drawdown snapshot figure.""" 

23 ... 

24 

25 def rolling_sharpe_plot(self) -> go.Figure: 

26 """Rolling Sharpe figure.""" 

27 ... 

28 

29 def rolling_volatility_plot(self) -> go.Figure: 

30 """Rolling volatility figure.""" 

31 ... 

32 

33 def annual_sharpe_plot(self) -> go.Figure: 

34 """Annual Sharpe figure.""" 

35 ... 

36 

37 def monthly_returns_heatmap(self) -> go.Figure: 

38 """Monthly returns heatmap figure.""" 

39 ... 

40 

41 def correlation_heatmap(self) -> go.Figure: 

42 """Correlation heatmap figure.""" 

43 ... 

44 

45 def lead_lag_ir_plot(self) -> go.Figure: 

46 """Lead/lag IR figure.""" 

47 ... 

48 

49 def trading_cost_impact_plot(self) -> go.Figure: 

50 """Trading cost impact figure.""" 

51 ... 

52 

53 

54@runtime_checkable 

55class PortfolioLike(Protocol): # pragma: no cover 

56 """Structural interface required by the `Report` class. 

57 

58 Any object satisfying this protocol can be passed as ``portfolio`` without a 

59 concrete dependency on `Portfolio`. 

60 """ 

61 

62 @property 

63 def prices(self) -> pl.DataFrame: 

64 """Price (holding) DataFrame.""" 

65 ... 

66 

67 @property 

68 def aum(self) -> float: 

69 """Assets under management.""" 

70 ... 

71 

72 @property 

73 def assets(self) -> list[str]: 

74 """Asset names.""" 

75 ... 

76 

77 @property 

78 def plots(self) -> PlotsLike: 

79 """Portfolio plots facade.""" 

80 ... 

81 

82 @property 

83 def stats(self) -> StatsLike: 

84 """Statistics facade.""" 

85 ... 

86 

87 def turnover_summary(self) -> pl.DataFrame: 

88 """Turnover summary DataFrame.""" 

89 ...