qis 3.2.8__tar.gz → 3.2.10__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (147) hide show
  1. {qis-3.2.8 → qis-3.2.10}/PKG-INFO +1 -1
  2. {qis-3.2.8 → qis-3.2.10}/pyproject.toml +1 -1
  3. {qis-3.2.8 → qis-3.2.10}/qis/portfolio/multi_portfolio_data.py +55 -11
  4. {qis-3.2.8 → qis-3.2.10}/qis/portfolio/portfolio_data.py +9 -8
  5. {qis-3.2.8 → qis-3.2.10}/qis/portfolio/reports/strategy_benchmark_factsheet.py +44 -21
  6. {qis-3.2.8 → qis-3.2.10}/LICENSE.txt +0 -0
  7. {qis-3.2.8 → qis-3.2.10}/README.md +0 -0
  8. {qis-3.2.8 → qis-3.2.10}/qis/__init__.py +0 -0
  9. {qis-3.2.8 → qis-3.2.10}/qis/examples/best_returns.py +0 -0
  10. {qis-3.2.8 → qis-3.2.10}/qis/examples/bootstrap_analysis.py +0 -0
  11. {qis-3.2.8 → qis-3.2.10}/qis/examples/boxplot_conditional_returns.py +0 -0
  12. {qis-3.2.8 → qis-3.2.10}/qis/examples/btc_asset_corr.py +0 -0
  13. {qis-3.2.8 → qis-3.2.10}/qis/examples/constant_notional.py +0 -0
  14. {qis-3.2.8 → qis-3.2.10}/qis/examples/constant_weight_portfolios.py +0 -0
  15. {qis-3.2.8 → qis-3.2.10}/qis/examples/core/perf_bbg_prices.py +0 -0
  16. {qis-3.2.8 → qis-3.2.10}/qis/examples/core/price_plots.py +0 -0
  17. {qis-3.2.8 → qis-3.2.10}/qis/examples/core/us_election.py +0 -0
  18. {qis-3.2.8 → qis-3.2.10}/qis/examples/credit_spreads.py +0 -0
  19. {qis-3.2.8 → qis-3.2.10}/qis/examples/europe_futures.py +0 -0
  20. {qis-3.2.8 → qis-3.2.10}/qis/examples/factsheets/multi_assets.py +0 -0
  21. {qis-3.2.8 → qis-3.2.10}/qis/examples/factsheets/multi_strategy.py +0 -0
  22. {qis-3.2.8 → qis-3.2.10}/qis/examples/factsheets/pyblogs_reports.py +0 -0
  23. {qis-3.2.8 → qis-3.2.10}/qis/examples/factsheets/strategy.py +0 -0
  24. {qis-3.2.8 → qis-3.2.10}/qis/examples/factsheets/strategy_benchmark.py +0 -0
  25. {qis-3.2.8 → qis-3.2.10}/qis/examples/generate_option_rolls.py +0 -0
  26. {qis-3.2.8 → qis-3.2.10}/qis/examples/interpolation_infrequent_returns.py +0 -0
  27. {qis-3.2.8 → qis-3.2.10}/qis/examples/leveraged_strategies.py +0 -0
  28. {qis-3.2.8 → qis-3.2.10}/qis/examples/long_short.py +0 -0
  29. {qis-3.2.8 → qis-3.2.10}/qis/examples/momentum_indices.py +0 -0
  30. {qis-3.2.8 → qis-3.2.10}/qis/examples/ohlc_vol_analysis.py +0 -0
  31. {qis-3.2.8 → qis-3.2.10}/qis/examples/overnight_returns.py +0 -0
  32. {qis-3.2.8 → qis-3.2.10}/qis/examples/perf_external_assets.py +0 -0
  33. {qis-3.2.8 → qis-3.2.10}/qis/examples/readme_performances.py +0 -0
  34. {qis-3.2.8 → qis-3.2.10}/qis/examples/risk_return_frontier.py +0 -0
  35. {qis-3.2.8 → qis-3.2.10}/qis/examples/rolling_performance.py +0 -0
  36. {qis-3.2.8 → qis-3.2.10}/qis/examples/seasonality.py +0 -0
  37. {qis-3.2.8 → qis-3.2.10}/qis/examples/sharpe_vs_sortino.py +0 -0
  38. {qis-3.2.8 → qis-3.2.10}/qis/examples/simulate_quant_strats.py +0 -0
  39. {qis-3.2.8 → qis-3.2.10}/qis/examples/test_ewm.py +0 -0
  40. {qis-3.2.8 → qis-3.2.10}/qis/examples/test_scatter.py +0 -0
  41. {qis-3.2.8 → qis-3.2.10}/qis/examples/try_pybloqs.py +0 -0
  42. {qis-3.2.8 → qis-3.2.10}/qis/examples/universe_corrs.py +0 -0
  43. {qis-3.2.8 → qis-3.2.10}/qis/examples/vix_beta_to_equities_bonds.py +0 -0
  44. {qis-3.2.8 → qis-3.2.10}/qis/examples/vix_conditional_returns.py +0 -0
  45. {qis-3.2.8 → qis-3.2.10}/qis/examples/vix_spy_by_year.py +0 -0
  46. {qis-3.2.8 → qis-3.2.10}/qis/examples/vix_tenor_analysis.py +0 -0
  47. {qis-3.2.8 → qis-3.2.10}/qis/examples/vol_without_weekends.py +0 -0
  48. {qis-3.2.8 → qis-3.2.10}/qis/file_utils.py +0 -0
  49. {qis-3.2.8 → qis-3.2.10}/qis/local_path.py +0 -0
  50. {qis-3.2.8 → qis-3.2.10}/qis/models/README.md +0 -0
  51. {qis-3.2.8 → qis-3.2.10}/qis/models/__init__.py +0 -0
  52. {qis-3.2.8 → qis-3.2.10}/qis/models/linear/__init__.py +0 -0
  53. {qis-3.2.8 → qis-3.2.10}/qis/models/linear/auto_corr.py +0 -0
  54. {qis-3.2.8 → qis-3.2.10}/qis/models/linear/corr_cov_matrix.py +0 -0
  55. {qis-3.2.8 → qis-3.2.10}/qis/models/linear/ewm.py +0 -0
  56. {qis-3.2.8 → qis-3.2.10}/qis/models/linear/ewm_convolution.py +0 -0
  57. {qis-3.2.8 → qis-3.2.10}/qis/models/linear/ewm_factors.py +0 -0
  58. {qis-3.2.8 → qis-3.2.10}/qis/models/linear/ewm_winsor_outliers.py +0 -0
  59. {qis-3.2.8 → qis-3.2.10}/qis/models/linear/pca.py +0 -0
  60. {qis-3.2.8 → qis-3.2.10}/qis/models/linear/plot_correlations.py +0 -0
  61. {qis-3.2.8 → qis-3.2.10}/qis/models/linear/ra_returns.py +0 -0
  62. {qis-3.2.8 → qis-3.2.10}/qis/models/stats/__init__.py +0 -0
  63. {qis-3.2.8 → qis-3.2.10}/qis/models/stats/bootstrap.py +0 -0
  64. {qis-3.2.8 → qis-3.2.10}/qis/models/stats/ohlc_vol.py +0 -0
  65. {qis-3.2.8 → qis-3.2.10}/qis/models/stats/rolling_stats.py +0 -0
  66. {qis-3.2.8 → qis-3.2.10}/qis/models/stats/test_bootstrap.py +0 -0
  67. {qis-3.2.8 → qis-3.2.10}/qis/perfstats/README.md +0 -0
  68. {qis-3.2.8 → qis-3.2.10}/qis/perfstats/__init__.py +0 -0
  69. {qis-3.2.8 → qis-3.2.10}/qis/perfstats/cond_regression.py +0 -0
  70. {qis-3.2.8 → qis-3.2.10}/qis/perfstats/config.py +0 -0
  71. {qis-3.2.8 → qis-3.2.10}/qis/perfstats/desc_table.py +0 -0
  72. {qis-3.2.8 → qis-3.2.10}/qis/perfstats/fx_ops.py +0 -0
  73. {qis-3.2.8 → qis-3.2.10}/qis/perfstats/perf_stats.py +0 -0
  74. {qis-3.2.8 → qis-3.2.10}/qis/perfstats/regime_classifier.py +0 -0
  75. {qis-3.2.8 → qis-3.2.10}/qis/perfstats/returns.py +0 -0
  76. {qis-3.2.8 → qis-3.2.10}/qis/perfstats/timeseries_bfill.py +0 -0
  77. {qis-3.2.8 → qis-3.2.10}/qis/plots/README.md +0 -0
  78. {qis-3.2.8 → qis-3.2.10}/qis/plots/__init__.py +0 -0
  79. {qis-3.2.8 → qis-3.2.10}/qis/plots/bars.py +0 -0
  80. {qis-3.2.8 → qis-3.2.10}/qis/plots/boxplot.py +0 -0
  81. {qis-3.2.8 → qis-3.2.10}/qis/plots/contour.py +0 -0
  82. {qis-3.2.8 → qis-3.2.10}/qis/plots/derived/__init__.py +0 -0
  83. {qis-3.2.8 → qis-3.2.10}/qis/plots/derived/data_timeseries.py +0 -0
  84. {qis-3.2.8 → qis-3.2.10}/qis/plots/derived/desc_table.py +0 -0
  85. {qis-3.2.8 → qis-3.2.10}/qis/plots/derived/drawdowns.py +0 -0
  86. {qis-3.2.8 → qis-3.2.10}/qis/plots/derived/perf_table.py +0 -0
  87. {qis-3.2.8 → qis-3.2.10}/qis/plots/derived/prices.py +0 -0
  88. {qis-3.2.8 → qis-3.2.10}/qis/plots/derived/regime_class_table.py +0 -0
  89. {qis-3.2.8 → qis-3.2.10}/qis/plots/derived/regime_data.py +0 -0
  90. {qis-3.2.8 → qis-3.2.10}/qis/plots/derived/regime_pdf.py +0 -0
  91. {qis-3.2.8 → qis-3.2.10}/qis/plots/derived/regime_scatter.py +0 -0
  92. {qis-3.2.8 → qis-3.2.10}/qis/plots/derived/returns_heatmap.py +0 -0
  93. {qis-3.2.8 → qis-3.2.10}/qis/plots/derived/returns_scatter.py +0 -0
  94. {qis-3.2.8 → qis-3.2.10}/qis/plots/errorbar.py +0 -0
  95. {qis-3.2.8 → qis-3.2.10}/qis/plots/heatmap.py +0 -0
  96. {qis-3.2.8 → qis-3.2.10}/qis/plots/histogram.py +0 -0
  97. {qis-3.2.8 → qis-3.2.10}/qis/plots/histplot2d.py +0 -0
  98. {qis-3.2.8 → qis-3.2.10}/qis/plots/lineplot.py +0 -0
  99. {qis-3.2.8 → qis-3.2.10}/qis/plots/pie.py +0 -0
  100. {qis-3.2.8 → qis-3.2.10}/qis/plots/qqplot.py +0 -0
  101. {qis-3.2.8 → qis-3.2.10}/qis/plots/reports/__init__.py +0 -0
  102. {qis-3.2.8 → qis-3.2.10}/qis/plots/reports/econ_data_single.py +0 -0
  103. {qis-3.2.8 → qis-3.2.10}/qis/plots/reports/gantt_data_history.py +0 -0
  104. {qis-3.2.8 → qis-3.2.10}/qis/plots/reports/price_history.py +0 -0
  105. {qis-3.2.8 → qis-3.2.10}/qis/plots/reports/utils.py +0 -0
  106. {qis-3.2.8 → qis-3.2.10}/qis/plots/scatter.py +0 -0
  107. {qis-3.2.8 → qis-3.2.10}/qis/plots/stackplot.py +0 -0
  108. {qis-3.2.8 → qis-3.2.10}/qis/plots/table.py +0 -0
  109. {qis-3.2.8 → qis-3.2.10}/qis/plots/time_series.py +0 -0
  110. {qis-3.2.8 → qis-3.2.10}/qis/plots/utils.py +0 -0
  111. {qis-3.2.8 → qis-3.2.10}/qis/portfolio/README.md +0 -0
  112. {qis-3.2.8 → qis-3.2.10}/qis/portfolio/__init__.py +0 -0
  113. {qis-3.2.8 → qis-3.2.10}/qis/portfolio/backtester.py +0 -0
  114. {qis-3.2.8 → qis-3.2.10}/qis/portfolio/ewm_portfolio_risk.py +0 -0
  115. {qis-3.2.8 → qis-3.2.10}/qis/portfolio/reports/__init__.py +0 -0
  116. {qis-3.2.8 → qis-3.2.10}/qis/portfolio/reports/brinson_attribution.py +0 -0
  117. {qis-3.2.8 → qis-3.2.10}/qis/portfolio/reports/config.py +0 -0
  118. {qis-3.2.8 → qis-3.2.10}/qis/portfolio/reports/multi_assets_factsheet.py +0 -0
  119. {qis-3.2.8 → qis-3.2.10}/qis/portfolio/reports/multi_strategy_factseet_pybloqs.py +0 -0
  120. {qis-3.2.8 → qis-3.2.10}/qis/portfolio/reports/multi_strategy_factsheet.py +0 -0
  121. {qis-3.2.8 → qis-3.2.10}/qis/portfolio/reports/strategy_benchmark_factsheet_pybloqs.py +0 -0
  122. {qis-3.2.8 → qis-3.2.10}/qis/portfolio/reports/strategy_factsheet.py +0 -0
  123. {qis-3.2.8 → qis-3.2.10}/qis/portfolio/reports/strategy_signal_factsheet.py +0 -0
  124. {qis-3.2.8 → qis-3.2.10}/qis/portfolio/signal_data.py +0 -0
  125. {qis-3.2.8 → qis-3.2.10}/qis/portfolio/strats/__init__.py +0 -0
  126. {qis-3.2.8 → qis-3.2.10}/qis/portfolio/strats/quant_strats_delta1.py +0 -0
  127. {qis-3.2.8 → qis-3.2.10}/qis/portfolio/strats/seasonal_strats.py +0 -0
  128. {qis-3.2.8 → qis-3.2.10}/qis/settings.yaml +0 -0
  129. {qis-3.2.8 → qis-3.2.10}/qis/sql_engine.py +0 -0
  130. {qis-3.2.8 → qis-3.2.10}/qis/test_data.py +0 -0
  131. {qis-3.2.8 → qis-3.2.10}/qis/utils/README.md +0 -0
  132. {qis-3.2.8 → qis-3.2.10}/qis/utils/__init__.py +0 -0
  133. {qis-3.2.8 → qis-3.2.10}/qis/utils/dates.py +0 -0
  134. {qis-3.2.8 → qis-3.2.10}/qis/utils/df_agg.py +0 -0
  135. {qis-3.2.8 → qis-3.2.10}/qis/utils/df_cut.py +0 -0
  136. {qis-3.2.8 → qis-3.2.10}/qis/utils/df_freq.py +0 -0
  137. {qis-3.2.8 → qis-3.2.10}/qis/utils/df_groups.py +0 -0
  138. {qis-3.2.8 → qis-3.2.10}/qis/utils/df_melt.py +0 -0
  139. {qis-3.2.8 → qis-3.2.10}/qis/utils/df_ops.py +0 -0
  140. {qis-3.2.8 → qis-3.2.10}/qis/utils/df_str.py +0 -0
  141. {qis-3.2.8 → qis-3.2.10}/qis/utils/df_to_scores.py +0 -0
  142. {qis-3.2.8 → qis-3.2.10}/qis/utils/df_to_weights.py +0 -0
  143. {qis-3.2.8 → qis-3.2.10}/qis/utils/generic.py +0 -0
  144. {qis-3.2.8 → qis-3.2.10}/qis/utils/np_ops.py +0 -0
  145. {qis-3.2.8 → qis-3.2.10}/qis/utils/ols.py +0 -0
  146. {qis-3.2.8 → qis-3.2.10}/qis/utils/sampling.py +0 -0
  147. {qis-3.2.8 → qis-3.2.10}/qis/utils/struct_ops.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: qis
3
- Version: 3.2.8
3
+ Version: 3.2.10
4
4
  Summary: Implementation of visualisation and reporting analytics for Quantitative Investment Strategies
5
5
  License: LICENSE.txt
6
6
  Keywords: quantitative,investing,portfolio optimization,systematic strategies,volatility
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "qis"
3
- version = "3.2.8"
3
+ version = "3.2.10"
4
4
  description = "Implementation of visualisation and reporting analytics for Quantitative Investment Strategies"
5
5
  license = "LICENSE.txt"
6
6
  authors = ["Artur Sepp <artursepp@gmail.com>"]
@@ -192,8 +192,12 @@ class MultiPortfolioData:
192
192
 
193
193
  def compute_tracking_error_implied_by_covar(self,
194
194
  strategy_idx: int = 0,
195
- benchmark_idx: int = 1
196
- ) -> pd.Series:
195
+ benchmark_idx: int = 1,
196
+ is_grouped: bool = False,
197
+ group_data: pd.Series = None,
198
+ group_order: List[str] = None,
199
+ total_column: Optional[str] = 'Total'
200
+ ) -> Union[pd.Series, pd.DataFrame]:
197
201
  """
198
202
  compute Ex ante tracking error =
199
203
  (strategy_weights - strategy_weights) @ covar @ (strategy_weights - strategy_weights).T
@@ -208,11 +212,33 @@ class MultiPortfolioData:
208
212
  benchmark_weights = benchmark_weights.reindex(index=covar_index, columns=investable_assets).ffill().fillna(0.0)
209
213
 
210
214
  weight_diffs = benchmark_weights - strategy_weights
211
- tracking_error = {}
212
- for date, pd_covar in self.covar_dict.items():
213
- w = weight_diffs.loc[date]
214
- tracking_error[date] = np.sqrt(w @ pd_covar @ w.T)
215
- tracking_error = pd.Series(tracking_error, name='Tracking error')
215
+ if not is_grouped:
216
+ tracking_error = {}
217
+ for date, pd_covar in self.covar_dict.items():
218
+ w = weight_diffs.loc[date]
219
+ tracking_error[date] = np.sqrt(w @ pd_covar @ w.T)
220
+ tracking_error = pd.Series(tracking_error, name='Tracking error')
221
+ else:
222
+ if group_data is None:
223
+ group_data = self.portfolio_datas[strategy_idx].group_data
224
+ if group_order is None:
225
+ group_order = self.portfolio_datas[strategy_idx].group_order
226
+ group_dict = dfg.get_group_dict(group_data=group_data,
227
+ group_order=group_order,
228
+ total_column=total_column)
229
+ tracking_error = {key: {} for key in group_dict.keys()}
230
+ for date, pd_covar in self.covar_dict.items():
231
+ w = weight_diffs.loc[date]
232
+ for key, tickers in group_dict.items():
233
+ w_g = w.loc[tickers]
234
+ pd_covar_g = pd_covar.loc[tickers, tickers]
235
+ tracking_error[key][date] = np.sqrt(w_g @ pd_covar_g @ w_g.T)
236
+ # merge
237
+ tracking_error_pd = {}
238
+ for key in group_dict.keys():
239
+ tracking_error_pd[key] = pd.Series(tracking_error[key], name=key)
240
+ tracking_error = pd.DataFrame.from_dict(tracking_error_pd, orient='columns')
241
+
216
242
  return tracking_error
217
243
 
218
244
  def compute_tracking_error_table(self,
@@ -620,7 +646,7 @@ class MultiPortfolioData:
620
646
  **kwargs)
621
647
  if regime_benchmark is not None:
622
648
  self.add_regime_shadows(ax=ax, regime_benchmark=regime_benchmark, index=diff.index, regime_params=regime_params)
623
-
649
+
624
650
  def get_turnover(self,
625
651
  time_period: TimePeriod = None,
626
652
  turnover_rolling_period: Optional[int] = 12,
@@ -637,7 +663,7 @@ class MultiPortfolioData:
637
663
  if time_period is not None:
638
664
  turnover = time_period.locate(turnover)
639
665
  return turnover
640
-
666
+
641
667
  def plot_turnover(self,
642
668
  regime_benchmark: str = None,
643
669
  time_period: TimePeriod = None,
@@ -648,7 +674,7 @@ class MultiPortfolioData:
648
674
  is_unit_based_traded_volume: bool = True,
649
675
  ax: plt.Subplot = None,
650
676
  **kwargs) -> None:
651
-
677
+
652
678
  turnover = self.get_turnover(turnover_rolling_period=turnover_rolling_period,
653
679
  freq_turnover=freq_turnover,
654
680
  is_unit_based_traded_volume=is_unit_based_traded_volume,
@@ -1007,21 +1033,39 @@ class MultiPortfolioData:
1007
1033
  def plot_tre_time_series(self,
1008
1034
  strategy_idx: int = 0,
1009
1035
  benchmark_idx: int = 1,
1036
+ is_grouped: bool = False,
1037
+ group_data: pd.Series = None,
1038
+ group_order: List[str] = None,
1010
1039
  regime_benchmark: str = None,
1011
1040
  regime_params: BenchmarkReturnsQuantileRegimeSpecs = REGIME_PARAMS,
1012
1041
  time_period: TimePeriod = None,
1013
1042
  title: Optional[str] = 'Tracking error',
1043
+ total_column: Optional[str] = 'Total',
1014
1044
  var_format: str = '{:.2%}',
1045
+ tre_max_clip: Optional[float] = None,
1015
1046
  ax: plt.Subplot = None,
1016
1047
  **kwargs
1017
1048
  ) -> None:
1018
- tre = self.compute_tracking_error_implied_by_covar(strategy_idx=strategy_idx, benchmark_idx=benchmark_idx)
1049
+ tre = self.compute_tracking_error_implied_by_covar(strategy_idx=strategy_idx, benchmark_idx=benchmark_idx,
1050
+ is_grouped=is_grouped, group_data=group_data,
1051
+ group_order=group_order,
1052
+ total_column=total_column)
1053
+ if tre_max_clip is not None:
1054
+ if isinstance(tre, pd.DataFrame): # skip total_column from trimming
1055
+ tre_columns = tre.columns.to_list()
1056
+ if total_column in tre:
1057
+ tre_columns.remove(total_column)
1058
+ tre[tre_columns] = tre[tre_columns].clip(upper=tre_max_clip)
1059
+ else:
1060
+ tre = tre.clip(upper=tre_max_clip)
1061
+
1019
1062
  if time_period is not None:
1020
1063
  tre = time_period.locate(tre)
1021
1064
  pts.plot_time_series(df=tre,
1022
1065
  var_format=var_format,
1023
1066
  legend_stats=pts.LegendStats.AVG_NONNAN_LAST,
1024
1067
  title=title,
1068
+ y_limits=(0.0, None),
1025
1069
  ax=ax,
1026
1070
  **kwargs)
1027
1071
  if regime_benchmark is not None:
@@ -1484,10 +1484,10 @@ class PortfolioData:
1484
1484
  group_data: pd.Series = None,
1485
1485
  group_order: List[str] = None,
1486
1486
  time_period: TimePeriod = None,
1487
- roll_period: Optional[int] = 260,
1487
+ turnover_rolling_period: Optional[int] = 260,
1488
+ freq_turnover: Optional[str] = 'B',
1488
1489
  add_total: bool = True,
1489
1490
  title: str = None,
1490
- freq: Optional[str] = None,
1491
1491
  regime_params: BenchmarkReturnsQuantileRegimeSpecs = None,
1492
1492
  ax: plt.Subplot = None,
1493
1493
  **kwargs
@@ -1497,19 +1497,20 @@ class PortfolioData:
1497
1497
  group_data=group_data,
1498
1498
  group_order=group_order,
1499
1499
  time_period=time_period,
1500
- roll_period=roll_period,
1500
+ roll_period=turnover_rolling_period,
1501
1501
  add_total=add_total,
1502
- freq=freq,
1502
+ freq=freq_turnover,
1503
1503
  **kwargs)
1504
- turnover_title = title or f"{roll_period}-period rolling {freq}-freq Turnover"
1504
+ freq = pd.infer_freq(turnover.index)
1505
+ turnover_title = title or f"{turnover_rolling_period}-period rolling {freq}-freq Turnover"
1505
1506
  qis.plot_time_series(df=turnover,
1506
- var_format='{:,.2%}',
1507
- # y_limits=(0.0, None),
1507
+ var_format='{:,.1%}',
1508
+ y_limits=(0.0, None),
1508
1509
  legend_stats=qis.LegendStats.AVG_NONNAN_LAST,
1509
1510
  title=turnover_title,
1510
1511
  ax=ax,
1511
1512
  **kwargs)
1512
- if regime_benchmark is not None:
1513
+ if regime_benchmark is not None and self.benchmark_prices is not None:
1513
1514
  self.add_regime_shadows(ax=ax, regime_benchmark=regime_benchmark, index=turnover.index,
1514
1515
  regime_params=regime_params)
1515
1516
 
@@ -513,6 +513,7 @@ def weights_tracking_error_report_by_ac_subac(multi_portfolio_data: MultiPortfol
513
513
  perf_params: PerfParams = PERF_PARAMS,
514
514
  regime_params: BenchmarkReturnsQuantileRegimeSpecs = REGIME_PARAMS,
515
515
  add_benchmarks_to_navs: bool = True,
516
+ tre_max_clip: Optional[float] = None,
516
517
  figsize: Tuple[float, float] = (11.7, 8.3),
517
518
  var_format: str = '{:.1%}',
518
519
  add_titles: bool = True,
@@ -665,22 +666,6 @@ def weights_tracking_error_report_by_ac_subac(multi_portfolio_data: MultiPortfol
665
666
  allow_negative=True,
666
667
  **kwargs)
667
668
 
668
- # tracking error
669
- fig, ax = plt.subplots(1, 1, figsize=figsize, tight_layout=True)
670
- figs['tre_time_series'] = fig
671
- if add_titles:
672
- title = 'Tracking Error'
673
- else:
674
- title = None
675
- multi_portfolio_data.plot_tre_time_series(strategy_idx=strategy_idx,
676
- benchmark_idx=benchmark_idx,
677
- regime_benchmark=regime_benchmark,
678
- regime_params=regime_params,
679
- title=title,
680
- ax=ax,
681
- time_period=time_period,
682
- **kwargs)
683
-
684
669
  # brinson by asset class
685
670
  totals_table, active_total, grouped_allocation_return, grouped_selection_return, grouped_interaction_return = \
686
671
  multi_portfolio_data.compute_brinson_attribution(strategy_idx=strategy_idx,
@@ -744,6 +729,42 @@ def weights_tracking_error_report_by_ac_subac(multi_portfolio_data: MultiPortfol
744
729
  figs['brinson_table_subac'] = qis.plot_brinson_totals_table(totals_table=totals_table, **kwargs)
745
730
  dfs['brinson_table_subac'] = totals_table
746
731
 
732
+ # tracking error
733
+ fig, ax = plt.subplots(1, 1, figsize=figsize, tight_layout=True)
734
+ figs['tre_time_series'] = fig
735
+ if add_titles:
736
+ title = 'Tracking Error'
737
+ else:
738
+ title = None
739
+ multi_portfolio_data.plot_tre_time_series(strategy_idx=strategy_idx,
740
+ benchmark_idx=benchmark_idx,
741
+ regime_benchmark=regime_benchmark,
742
+ regime_params=regime_params,
743
+ title=title,
744
+ ax=ax,
745
+ time_period=time_period,
746
+ **kwargs)
747
+
748
+ # group tracking error
749
+ fig, ax = plt.subplots(1, 1, figsize=figsize, tight_layout=True)
750
+ figs['tre_group_time_series'] = fig
751
+ if add_titles:
752
+ title = 'Asset Class Tracking Error'
753
+ else:
754
+ title = None
755
+ multi_portfolio_data.plot_tre_time_series(strategy_idx=strategy_idx,
756
+ benchmark_idx=benchmark_idx,
757
+ is_grouped=True,
758
+ group_data=ac_group_data,
759
+ group_order=ac_group_order,
760
+ regime_benchmark=regime_benchmark,
761
+ regime_params=regime_params,
762
+ tre_max_clip=tre_max_clip,
763
+ title=title,
764
+ ax=ax,
765
+ time_period=time_period,
766
+ **kwargs)
767
+
747
768
  # turnover
748
769
  fig, ax = plt.subplots(1, 1, figsize=figsize, tight_layout=True)
749
770
  figs['joint_turnover'] = fig
@@ -751,9 +772,9 @@ def weights_tracking_error_report_by_ac_subac(multi_portfolio_data: MultiPortfol
751
772
  time_period=time_period,
752
773
  regime_benchmark=regime_benchmark,
753
774
  regime_params=regime_params,
754
- #turnover_rolling_period=260,
755
- #freq_turnover=None,
756
775
  **kwargs)
776
+ if not add_titles:
777
+ ax.title.set_visible(False)
757
778
  # group turnover
758
779
  fig, ax = plt.subplots(1, 1, figsize=figsize, tight_layout=True)
759
780
  figs['group_turnover'] = fig
@@ -765,10 +786,12 @@ def weights_tracking_error_report_by_ac_subac(multi_portfolio_data: MultiPortfol
765
786
  group_data=turnover_groups,
766
787
  group_order=turnover_order,
767
788
  add_total=False,
768
- #turnover_rolling_period=260,
769
- #freq_turnover=None,
770
789
  **kwargs)
771
-
790
+ if regime_benchmark is not None:
791
+ multi_portfolio_data.add_regime_shadows(ax=ax, regime_benchmark=regime_benchmark,
792
+ index=grouped_selection_return.index, regime_params=regime_params)
793
+ if not add_titles:
794
+ ax.title.set_visible(False)
772
795
  return figs, dfs
773
796
 
774
797
 
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes