Coverage for src/jquantstats/_plots/_portfolio/_rolling.py: 100%
13 statements
« prev ^ index » next coverage.py v7.16.1, created at 2026-09-23 04:11 +0000
« prev ^ index » next coverage.py v7.16.1, created at 2026-09-23 04:11 +0000
1"""Rolling-window and per-year risk charts for a portfolio.
3Split out of the former single-module `_plots/_portfolio.py`; composed into
4:class:`PortfolioPlots` by `_core.py`.
5"""
7from __future__ import annotations
9from typing import TYPE_CHECKING, Literal, overload
11from .._render import render
12from .._specs import (
13 annual_sharpe_spec,
14 portfolio_rolling_sharpe_spec,
15 portfolio_rolling_volatility_spec,
16)
18if TYPE_CHECKING:
19 from matplotlib.figure import Figure as MplFigure
20 from plotly.graph_objects import Figure as PlotlyFigure
22 from .._backend import Backend
23 from .._protocol import PortfolioLike
24 from .._render import Figure
27class _RollingPortfolioPlotsMixin:
28 """Rolling-window and annual risk charts for :class:`PortfolioPlots`."""
30 __slots__ = ()
32 _portfolio: PortfolioLike
34 @overload
35 def rolling_sharpe_plot(self, window: int = ..., *, backend: Literal["plotly"] | None = ...) -> PlotlyFigure: ...
37 @overload
38 def rolling_sharpe_plot(self, window: int = ..., *, backend: Literal["matplotlib"]) -> MplFigure: ...
40 def rolling_sharpe_plot(self, window: int = 63, *, backend: Backend | None = None) -> Figure:
41 """Plot rolling annualised Sharpe ratio over time.
43 Computes the rolling Sharpe for each asset column using the given
44 window and renders one line per asset.
46 Args:
47 window: Rolling-window size in periods. Defaults to 63.
48 backend: Renderer to use. Defaults to the ambient selection.
50 Returns:
51 Figure: A chart with one line per asset.
53 Raises:
54 ValueError: If ``window`` is not a positive integer.
56 """
57 return render(portfolio_rolling_sharpe_spec(self._portfolio, window), backend)
59 @overload
60 def rolling_volatility_plot(
61 self, window: int = ..., *, backend: Literal["plotly"] | None = ...
62 ) -> PlotlyFigure: ...
64 @overload
65 def rolling_volatility_plot(self, window: int = ..., *, backend: Literal["matplotlib"]) -> MplFigure: ...
67 def rolling_volatility_plot(self, window: int = 63, *, backend: Backend | None = None) -> Figure:
68 """Plot rolling annualised volatility over time.
70 Computes the rolling volatility for each asset column using the given
71 window and renders one line per asset.
73 Args:
74 window: Rolling-window size in periods. Defaults to 63.
75 backend: Renderer to use. Defaults to the ambient selection.
77 Returns:
78 Figure: A chart with one line per asset.
80 Raises:
81 ValueError: If ``window`` is not a positive integer.
83 """
84 return render(portfolio_rolling_volatility_spec(self._portfolio, window), backend)
86 @overload
87 def annual_sharpe_plot(self, *, backend: Literal["plotly"] | None = ...) -> PlotlyFigure: ...
89 @overload
90 def annual_sharpe_plot(self, *, backend: Literal["matplotlib"]) -> MplFigure: ...
92 def annual_sharpe_plot(self, *, backend: Backend | None = None) -> Figure:
93 """Plot annualised Sharpe ratio broken down by calendar year.
95 Computes the Sharpe ratio for each calendar year from the portfolio
96 returns and renders a grouped bar chart with one bar per year per
97 asset.
99 Args:
100 backend: Renderer to use. Defaults to the ambient selection.
102 Returns:
103 Figure: A grouped bar chart, one bar group per asset.
105 """
106 return render(annual_sharpe_spec(self._portfolio), backend)