Coverage for src/jquantstats/_plots/_portfolio/_nav.py: 100%

13 statements  

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

1"""Accumulated-NAV charts for a portfolio. 

2 

3Split out of the former single-module `_plots/_portfolio.py`; composed into 

4:class:`PortfolioPlots` by `_core.py`. 

5""" 

6 

7from __future__ import annotations 

8 

9from typing import TYPE_CHECKING, Literal, overload 

10 

11from .._render import render 

12from .._specs import ( 

13 lagged_performance_spec, 

14 portfolio_snapshot_spec, 

15 smoothed_holdings_performance_spec, 

16) 

17 

18if TYPE_CHECKING: 

19 from matplotlib.figure import Figure as MplFigure 

20 from plotly.graph_objects import Figure as PlotlyFigure 

21 

22 from .._backend import Backend 

23 from .._protocol import PortfolioLike 

24 from .._render import Figure 

25 

26 

27class _NavPlotsMixin: 

28 """Accumulated-NAV charts for :class:`PortfolioPlots`.""" 

29 

30 __slots__ = () 

31 

32 _portfolio: PortfolioLike 

33 

34 @overload 

35 def snapshot(self, log_scale: bool = ..., *, backend: Literal["plotly"] | None = ...) -> PlotlyFigure: ... 

36 

37 @overload 

38 def snapshot(self, log_scale: bool = ..., *, backend: Literal["matplotlib"]) -> MplFigure: ... 

39 

40 def snapshot(self, log_scale: bool = False, *, backend: Backend | None = None) -> Figure: 

41 """Return a snapshot dashboard of NAV and drawdown. 

42 

43 When the portfolio has a non-zero ``cost_model.cost_per_unit``, an additional 

44 ``"Net-of-Cost NAV"`` trace is overlaid on the NAV panel showing the 

45 realised NAV path after deducting position-delta trading costs. 

46 

47 Args: 

48 log_scale: If True, display NAV on a log scale. Defaults to False. 

49 backend: Renderer to use. Defaults to the ambient selection. 

50 

51 Returns: 

52 Figure: Accumulated NAV (including tilt/timing) over a shaded 

53 drawdown panel. 

54 

55 """ 

56 return render(portfolio_snapshot_spec(self._portfolio, log_scale=log_scale), backend) 

57 

58 @overload 

59 def lagged_performance_plot( 

60 self, 

61 lags: list[int] | None = ..., 

62 log_scale: bool = ..., 

63 *, 

64 backend: Literal["plotly"] | None = ..., 

65 ) -> PlotlyFigure: ... 

66 

67 @overload 

68 def lagged_performance_plot( 

69 self, 

70 lags: list[int] | None = ..., 

71 log_scale: bool = ..., 

72 *, 

73 backend: Literal["matplotlib"], 

74 ) -> MplFigure: ... 

75 

76 def lagged_performance_plot( 

77 self, 

78 lags: list[int] | None = None, 

79 log_scale: bool = False, 

80 *, 

81 backend: Backend | None = None, 

82 ) -> Figure: 

83 """Plot NAV_accumulated for multiple lagged portfolios. 

84 

85 Creates a figure with one line per lag value showing the accumulated 

86 NAV series for the portfolio with cash positions shifted by that lag. 

87 By default, lags [0, 1, 2, 3, 4] are used. 

88 

89 Args: 

90 lags: A list of integer lags to apply; defaults to [0, 1, 2, 3, 4]. 

91 log_scale: If True, set the primary y-axis to logarithmic scale. 

92 backend: Renderer to use. Defaults to the ambient selection. 

93 

94 Returns: 

95 Figure: One trace per requested lag. 

96 

97 Raises: 

98 TypeError: If ``lags`` is not a list of integers. 

99 

100 """ 

101 return render(lagged_performance_spec(self._portfolio, lags, log_scale), backend) 

102 

103 @overload 

104 def smoothed_holdings_performance_plot( 

105 self, 

106 windows: list[int] | None = ..., 

107 log_scale: bool = ..., 

108 *, 

109 backend: Literal["plotly"] | None = ..., 

110 ) -> PlotlyFigure: ... 

111 

112 @overload 

113 def smoothed_holdings_performance_plot( 

114 self, 

115 windows: list[int] | None = ..., 

116 log_scale: bool = ..., 

117 *, 

118 backend: Literal["matplotlib"], 

119 ) -> MplFigure: ... 

120 

121 def smoothed_holdings_performance_plot( 

122 self, 

123 windows: list[int] | None = None, 

124 log_scale: bool = False, 

125 *, 

126 backend: Backend | None = None, 

127 ) -> Figure: 

128 """Plot NAV_accumulated for smoothed-holding portfolios. 

129 

130 Builds portfolios with cash positions smoothed by a trailing rolling 

131 mean over the previous ``n`` steps (window size n+1) for n in 

132 ``windows`` (defaults to [0, 1, 2, 3, 4]) and plots their 

133 accumulated NAV curves. 

134 

135 Args: 

136 windows: List of non-negative integers specifying smoothing steps 

137 to include; defaults to [0, 1, 2, 3, 4]. 

138 log_scale: If True, set the primary y-axis to logarithmic scale. 

139 backend: Renderer to use. Defaults to the ambient selection. 

140 

141 Returns: 

142 Figure: One line per requested smoothing level. 

143 

144 Raises: 

145 TypeError: If ``windows`` is not a list of non-negative integers. 

146 

147 """ 

148 return render(smoothed_holdings_performance_spec(self._portfolio, windows, log_scale), backend)