Coverage for src/jquantstats/_plots/_data/_rolling.py: 100%

19 statements  

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

1"""Rolling risk/return metric line charts (Sharpe, Sortino, volatility, beta).""" 

2 

3from __future__ import annotations 

4 

5from typing import TYPE_CHECKING, Literal, overload 

6 

7from .._render import render 

8from .._specs import ( 

9 rolling_beta_spec, 

10 rolling_sharpe_spec, 

11 rolling_sortino_spec, 

12 rolling_volatility_spec, 

13) 

14 

15if TYPE_CHECKING: 

16 from matplotlib.figure import Figure as MplFigure 

17 from plotly.graph_objects import Figure as PlotlyFigure 

18 

19 from jquantstats._protocol import DataLike 

20 

21 from .._backend import Backend 

22 from .._render import Figure 

23 

24 

25class _RollingPlotsMixin: 

26 """Rolling-window metric plots for :class:`DataPlots`.""" 

27 

28 __slots__ = () 

29 

30 _data: DataLike 

31 

32 @overload 

33 def rolling_sharpe( 

34 self, 

35 rolling_period: int = ..., 

36 periods_per_year: int = ..., 

37 title: str = ..., 

38 *, 

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

40 ) -> PlotlyFigure: ... 

41 

42 @overload 

43 def rolling_sharpe( 

44 self, 

45 rolling_period: int = ..., 

46 periods_per_year: int = ..., 

47 title: str = ..., 

48 *, 

49 backend: Literal["matplotlib"], 

50 ) -> MplFigure: ... 

51 

52 def rolling_sharpe( 

53 self, 

54 rolling_period: int = 126, 

55 periods_per_year: int = 252, 

56 title: str = "Rolling Sharpe Ratio", 

57 *, 

58 backend: Backend | None = None, 

59 ) -> Figure: 

60 """Rolling annualised Sharpe ratio over time. 

61 

62 Computes ``rolling_mean / rolling_std * sqrt(periods_per_year)`` with a 

63 trailing window of *rolling_period* observations for every column in the 

64 dataset (assets and benchmark when present). 

65 

66 Args: 

67 rolling_period: Trailing window size. Defaults to 126 (6 months). 

68 periods_per_year: Annualisation factor. Defaults to 252. 

69 title: Chart title. Defaults to ``"Rolling Sharpe Ratio"``. 

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

71 

72 Returns: 

73 Figure: A line chart. 

74 

75 """ 

76 spec = rolling_sharpe_spec(self._data, rolling_period, periods_per_year, title) 

77 return render(spec, backend) 

78 

79 @overload 

80 def rolling_sortino( 

81 self, 

82 rolling_period: int = ..., 

83 periods_per_year: int = ..., 

84 title: str = ..., 

85 *, 

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

87 ) -> PlotlyFigure: ... 

88 

89 @overload 

90 def rolling_sortino( 

91 self, 

92 rolling_period: int = ..., 

93 periods_per_year: int = ..., 

94 title: str = ..., 

95 *, 

96 backend: Literal["matplotlib"], 

97 ) -> MplFigure: ... 

98 

99 def rolling_sortino( 

100 self, 

101 rolling_period: int = 126, 

102 periods_per_year: int = 252, 

103 title: str = "Rolling Sortino Ratio", 

104 *, 

105 backend: Backend | None = None, 

106 ) -> Figure: 

107 """Rolling annualised Sortino ratio over time. 

108 

109 Computes ``rolling_mean / rolling_downside_std * sqrt(periods_per_year)`` 

110 where downside deviation considers only negative returns. 

111 

112 Args: 

113 rolling_period: Trailing window size. Defaults to 126 (6 months). 

114 periods_per_year: Annualisation factor. Defaults to 252. 

115 title: Chart title. Defaults to ``"Rolling Sortino Ratio"``. 

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

117 

118 Returns: 

119 Figure: A line chart. 

120 

121 """ 

122 spec = rolling_sortino_spec(self._data, rolling_period, periods_per_year, title) 

123 return render(spec, backend) 

124 

125 @overload 

126 def rolling_volatility( 

127 self, 

128 rolling_period: int = ..., 

129 periods_per_year: int = ..., 

130 title: str = ..., 

131 *, 

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

133 ) -> PlotlyFigure: ... 

134 

135 @overload 

136 def rolling_volatility( 

137 self, 

138 rolling_period: int = ..., 

139 periods_per_year: int = ..., 

140 title: str = ..., 

141 *, 

142 backend: Literal["matplotlib"], 

143 ) -> MplFigure: ... 

144 

145 def rolling_volatility( 

146 self, 

147 rolling_period: int = 126, 

148 periods_per_year: int = 252, 

149 title: str = "Rolling Volatility", 

150 *, 

151 backend: Backend | None = None, 

152 ) -> Figure: 

153 """Rolling annualised volatility over time. 

154 

155 Computes ``rolling_std * sqrt(periods_per_year)`` for every column in 

156 the dataset. 

157 

158 Args: 

159 rolling_period: Trailing window size. Defaults to 126 (6 months). 

160 periods_per_year: Annualisation factor. Defaults to 252. 

161 title: Chart title. Defaults to ``"Rolling Volatility"``. 

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

163 

164 Returns: 

165 Figure: A line chart. 

166 

167 """ 

168 spec = rolling_volatility_spec(self._data, rolling_period, periods_per_year, title) 

169 return render(spec, backend) 

170 

171 @overload 

172 def rolling_beta( 

173 self, 

174 rolling_period: int = ..., 

175 rolling_period2: int | None = ..., 

176 title: str = ..., 

177 figsize: tuple[int, int] | None = ..., 

178 *, 

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

180 ) -> PlotlyFigure: ... 

181 

182 @overload 

183 def rolling_beta( 

184 self, 

185 rolling_period: int = ..., 

186 rolling_period2: int | None = ..., 

187 title: str = ..., 

188 figsize: tuple[int, int] | None = ..., 

189 *, 

190 backend: Literal["matplotlib"], 

191 ) -> MplFigure: ... 

192 

193 def rolling_beta( 

194 self, 

195 rolling_period: int = 126, 

196 rolling_period2: int | None = 252, 

197 title: str = "Rolling Beta", 

198 figsize: tuple[int, int] | None = None, 

199 *, 

200 backend: Backend | None = None, 

201 ) -> Figure: 

202 """Rolling beta versus the benchmark. 

203 

204 Plots one line per asset per window size. Beta is estimated via the 

205 standard OLS formula: ``cov(asset, bench) / var(bench)`` computed over 

206 a trailing window. 

207 

208 Args: 

209 rolling_period: Primary trailing window size. Defaults to 126. 

210 rolling_period2: Optional second window size overlaid on the same 

211 chart. Defaults to 252. Pass ``None`` to omit. 

212 title: Chart title. Defaults to ``"Rolling Beta"``. 

213 figsize: Optional ``(width, height)`` in pixels. 

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

215 

216 Returns: 

217 Figure: A line chart. 

218 

219 Raises: 

220 NoBenchmarkError: If no benchmark columns are present in the data. 

221 

222 """ 

223 spec = rolling_beta_spec(self._data, rolling_period, rolling_period2, title, figsize) 

224 return render(spec, backend)