qis.plot_overlay_allocation_frontier

qis.plot_overlay_allocation_frontier(portfolio_stats, frontier_stats=None, groups=None, benchmark=None, group_styles=None, highlights=None, annotations=None, label_offsets=None, x_column='bear_sharpe', y_column='sharpe', frontier_label='Optimal stacked portfolios', frontier_color='#009E73', xlabel='Bear Sharpe contribution of the stacked portfolio', ylabel='Arithmetic excess Sharpe ratio of the stacked portfolio', title=None, legend_loc='upper center', figsize=(8.6, 5.2), ax=None, bbox_to_anchor=(0.5, -0.14), ncols=2)[source]

Stacked portfolios by group and an optional solved coverage-floor frontier.

Every point is a portfolio, not a standalone overlay: the benchmark itself, or the benchmark at weight one plus an overlay at the chosen budget, the stacked portfolio of Sepp and Kastenholz (2026, Definition 3). Build the stacked returns r_B + w r_i first and pass them, with the benchmark, through qis.regimes.compute_regime_premium_table, whose bear_sharpe and sharpe columns are the default coordinates. Compute the frontier rows the same way from the solved allocations. Weights and optimiser objects are not needed, and the function does not fit, sort, round or recompute coordinates.

Parameters:
  • portfolio_stats (DataFrame) – statistics of the benchmark and the stacked portfolios, indexed by unique portfolio names

  • frontier_stats (DataFrame | None) – statistics of the solved portfolios in the order of the floor; None draws only the points. Repeated coordinate pairs are kept, as where the floor is slack

  • groups (Series | None) – group label by portfolio name, covering every point of portfolio_stats; None puts the points in one group and the benchmark in its own

  • benchmark (str | None) – name of the benchmark row, whose x coordinate sets the dashed vertical line

  • group_styles (Mapping[str, Mapping[str, Any]] | None) – matplotlib scatter options by group, such as color, marker, s and label; groups without options use the matplotlib colour cycle

  • highlights (Mapping[str, Mapping[str, Any]] | None) – scatter options by portfolio name for selected allocations, drawn once apart from their groups and named in the legend

  • annotations (Sequence[str] | None) – names of the points to label; None labels every point that is not highlighted, and an empty sequence none

  • label_offsets (Mapping[str, Tuple[float, float]] | None) – label offsets in points by portfolio name

  • x_column (str) – column of the x coordinate in both tables, the Bear contribution by default

  • y_column (str) – column of the y coordinate in both tables, the Sharpe ratio by default

  • frontier_label (str) – legend label of the frontier

  • frontier_color (str) – colour of the frontier line

  • xlabel (str) – x-axis label; state the Sharpe convention when it matters

  • ylabel (str) – y-axis label

  • title (str | None) – optional title

  • legend_loc (str | None) – legend location; None draws no legend. The default puts the legend’s upper centre below the axes, in two columns without a frame

  • figsize (Tuple[float, float]) – size of a new figure

  • ax (Axes | None) – axis to draw on; None creates a figure

  • bbox_to_anchor (Tuple[float, float] | None) – legend anchor in axes coordinates; None uses legend_loc alone

  • ncols (int) – number of legend columns

Returns:

the new figure, or None when ax is given

Raises:

ValueError – if the coordinates, the row labels, the groups or a selected name are invalid

Return type:

Figure | None