qis 3.2.2__tar.gz → 3.2.4__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 (149) hide show
  1. {qis-3.2.2 → qis-3.2.4}/PKG-INFO +1 -1
  2. {qis-3.2.2 → qis-3.2.4}/pyproject.toml +1 -1
  3. {qis-3.2.2 → qis-3.2.4}/qis/examples/core/perf_bbg_prices.py +34 -5
  4. {qis-3.2.2 → qis-3.2.4}/qis/models/__init__.py +2 -2
  5. {qis-3.2.2 → qis-3.2.4}/qis/models/linear/ewm.py +37 -13
  6. {qis-3.2.2 → qis-3.2.4}/qis/models/linear/ewm_factors.py +21 -1
  7. {qis-3.2.2 → qis-3.2.4}/qis/plots/derived/perf_table.py +1 -3
  8. {qis-3.2.2 → qis-3.2.4}/qis/plots/derived/returns_heatmap.py +1 -1
  9. {qis-3.2.2 → qis-3.2.4}/qis/portfolio/multi_portfolio_data.py +2 -1
  10. {qis-3.2.2 → qis-3.2.4}/qis/portfolio/portfolio_data.py +15 -2
  11. {qis-3.2.2 → qis-3.2.4}/qis/portfolio/reports/config.py +3 -3
  12. {qis-3.2.2 → qis-3.2.4}/qis/portfolio/reports/multi_assets_factsheet.py +41 -14
  13. {qis-3.2.2 → qis-3.2.4}/qis/portfolio/reports/multi_strategy_factseet_pybloqs.py +17 -16
  14. {qis-3.2.2 → qis-3.2.4}/qis/portfolio/reports/strategy_benchmark_factsheet.py +2 -0
  15. {qis-3.2.2 → qis-3.2.4}/qis/portfolio/reports/strategy_factsheet.py +3 -4
  16. {qis-3.2.2 → qis-3.2.4}/qis/settings.yaml +0 -1
  17. {qis-3.2.2 → qis-3.2.4}/LICENSE.txt +0 -0
  18. {qis-3.2.2 → qis-3.2.4}/README.md +0 -0
  19. {qis-3.2.2 → qis-3.2.4}/qis/__init__.py +0 -0
  20. {qis-3.2.2 → qis-3.2.4}/qis/examples/best_returns.py +0 -0
  21. {qis-3.2.2 → qis-3.2.4}/qis/examples/bond_futures_portfolio.py +0 -0
  22. {qis-3.2.2 → qis-3.2.4}/qis/examples/bootstrap_analysis.py +0 -0
  23. {qis-3.2.2 → qis-3.2.4}/qis/examples/boxplot_conditional_returns.py +0 -0
  24. {qis-3.2.2 → qis-3.2.4}/qis/examples/btc_asset_corr.py +0 -0
  25. {qis-3.2.2 → qis-3.2.4}/qis/examples/constant_notional.py +0 -0
  26. {qis-3.2.2 → qis-3.2.4}/qis/examples/constant_weight_portfolios.py +0 -0
  27. {qis-3.2.2 → qis-3.2.4}/qis/examples/core/price_plots.py +0 -0
  28. {qis-3.2.2 → qis-3.2.4}/qis/examples/core/us_election.py +0 -0
  29. {qis-3.2.2 → qis-3.2.4}/qis/examples/credit_spreads.py +0 -0
  30. {qis-3.2.2 → qis-3.2.4}/qis/examples/credit_trackers.py +0 -0
  31. {qis-3.2.2 → qis-3.2.4}/qis/examples/europe_futures.py +0 -0
  32. {qis-3.2.2 → qis-3.2.4}/qis/examples/factsheets/multi_assets.py +0 -0
  33. {qis-3.2.2 → qis-3.2.4}/qis/examples/factsheets/multi_strategy.py +0 -0
  34. {qis-3.2.2 → qis-3.2.4}/qis/examples/factsheets/pyblogs_reports.py +0 -0
  35. {qis-3.2.2 → qis-3.2.4}/qis/examples/factsheets/strategy.py +0 -0
  36. {qis-3.2.2 → qis-3.2.4}/qis/examples/factsheets/strategy_benchmark.py +0 -0
  37. {qis-3.2.2 → qis-3.2.4}/qis/examples/generate_option_rolls.py +0 -0
  38. {qis-3.2.2 → qis-3.2.4}/qis/examples/interpolation_infrequent_returns.py +0 -0
  39. {qis-3.2.2 → qis-3.2.4}/qis/examples/leveraged_strategies.py +0 -0
  40. {qis-3.2.2 → qis-3.2.4}/qis/examples/long_short.py +0 -0
  41. {qis-3.2.2 → qis-3.2.4}/qis/examples/momentum_indices.py +0 -0
  42. {qis-3.2.2 → qis-3.2.4}/qis/examples/ohlc_vol_analysis.py +0 -0
  43. {qis-3.2.2 → qis-3.2.4}/qis/examples/overnight_returns.py +0 -0
  44. {qis-3.2.2 → qis-3.2.4}/qis/examples/perf_external_assets.py +0 -0
  45. {qis-3.2.2 → qis-3.2.4}/qis/examples/perp_pricing.py +0 -0
  46. {qis-3.2.2 → qis-3.2.4}/qis/examples/readme_performances.py +0 -0
  47. {qis-3.2.2 → qis-3.2.4}/qis/examples/risk_return_frontier.py +0 -0
  48. {qis-3.2.2 → qis-3.2.4}/qis/examples/rolling_performance.py +0 -0
  49. {qis-3.2.2 → qis-3.2.4}/qis/examples/seasonality.py +0 -0
  50. {qis-3.2.2 → qis-3.2.4}/qis/examples/sharpe_vs_sortino.py +0 -0
  51. {qis-3.2.2 → qis-3.2.4}/qis/examples/simulate_quant_strats.py +0 -0
  52. {qis-3.2.2 → qis-3.2.4}/qis/examples/test_ewm.py +0 -0
  53. {qis-3.2.2 → qis-3.2.4}/qis/examples/test_scatter.py +0 -0
  54. {qis-3.2.2 → qis-3.2.4}/qis/examples/try_pybloqs.py +0 -0
  55. {qis-3.2.2 → qis-3.2.4}/qis/examples/universe_corrs.py +0 -0
  56. {qis-3.2.2 → qis-3.2.4}/qis/examples/vix_beta_to_equities_bonds.py +0 -0
  57. {qis-3.2.2 → qis-3.2.4}/qis/examples/vix_conditional_returns.py +0 -0
  58. {qis-3.2.2 → qis-3.2.4}/qis/examples/vix_spy_by_year.py +0 -0
  59. {qis-3.2.2 → qis-3.2.4}/qis/examples/vix_tenor_analysis.py +0 -0
  60. {qis-3.2.2 → qis-3.2.4}/qis/examples/vol_without_weekends.py +0 -0
  61. {qis-3.2.2 → qis-3.2.4}/qis/file_utils.py +0 -0
  62. {qis-3.2.2 → qis-3.2.4}/qis/local_path.py +0 -0
  63. {qis-3.2.2 → qis-3.2.4}/qis/models/README.md +0 -0
  64. {qis-3.2.2 → qis-3.2.4}/qis/models/linear/__init__.py +0 -0
  65. {qis-3.2.2 → qis-3.2.4}/qis/models/linear/auto_corr.py +0 -0
  66. {qis-3.2.2 → qis-3.2.4}/qis/models/linear/corr_cov_matrix.py +0 -0
  67. {qis-3.2.2 → qis-3.2.4}/qis/models/linear/ewm_convolution.py +0 -0
  68. {qis-3.2.2 → qis-3.2.4}/qis/models/linear/ewm_winsor_outliers.py +0 -0
  69. {qis-3.2.2 → qis-3.2.4}/qis/models/linear/pca.py +0 -0
  70. {qis-3.2.2 → qis-3.2.4}/qis/models/linear/plot_correlations.py +0 -0
  71. {qis-3.2.2 → qis-3.2.4}/qis/models/linear/ra_returns.py +0 -0
  72. {qis-3.2.2 → qis-3.2.4}/qis/models/stats/__init__.py +0 -0
  73. {qis-3.2.2 → qis-3.2.4}/qis/models/stats/bootstrap.py +0 -0
  74. {qis-3.2.2 → qis-3.2.4}/qis/models/stats/ohlc_vol.py +0 -0
  75. {qis-3.2.2 → qis-3.2.4}/qis/models/stats/rolling_stats.py +0 -0
  76. {qis-3.2.2 → qis-3.2.4}/qis/models/stats/test_bootstrap.py +0 -0
  77. {qis-3.2.2 → qis-3.2.4}/qis/perfstats/README.md +0 -0
  78. {qis-3.2.2 → qis-3.2.4}/qis/perfstats/__init__.py +0 -0
  79. {qis-3.2.2 → qis-3.2.4}/qis/perfstats/cond_regression.py +0 -0
  80. {qis-3.2.2 → qis-3.2.4}/qis/perfstats/config.py +0 -0
  81. {qis-3.2.2 → qis-3.2.4}/qis/perfstats/desc_table.py +0 -0
  82. {qis-3.2.2 → qis-3.2.4}/qis/perfstats/fx_ops.py +0 -0
  83. {qis-3.2.2 → qis-3.2.4}/qis/perfstats/perf_stats.py +0 -0
  84. {qis-3.2.2 → qis-3.2.4}/qis/perfstats/regime_classifier.py +0 -0
  85. {qis-3.2.2 → qis-3.2.4}/qis/perfstats/returns.py +0 -0
  86. {qis-3.2.2 → qis-3.2.4}/qis/perfstats/timeseries_bfill.py +0 -0
  87. {qis-3.2.2 → qis-3.2.4}/qis/plots/README.md +0 -0
  88. {qis-3.2.2 → qis-3.2.4}/qis/plots/__init__.py +0 -0
  89. {qis-3.2.2 → qis-3.2.4}/qis/plots/bars.py +0 -0
  90. {qis-3.2.2 → qis-3.2.4}/qis/plots/boxplot.py +0 -0
  91. {qis-3.2.2 → qis-3.2.4}/qis/plots/contour.py +0 -0
  92. {qis-3.2.2 → qis-3.2.4}/qis/plots/derived/__init__.py +0 -0
  93. {qis-3.2.2 → qis-3.2.4}/qis/plots/derived/data_timeseries.py +0 -0
  94. {qis-3.2.2 → qis-3.2.4}/qis/plots/derived/desc_table.py +0 -0
  95. {qis-3.2.2 → qis-3.2.4}/qis/plots/derived/drawdowns.py +0 -0
  96. {qis-3.2.2 → qis-3.2.4}/qis/plots/derived/prices.py +0 -0
  97. {qis-3.2.2 → qis-3.2.4}/qis/plots/derived/regime_class_table.py +0 -0
  98. {qis-3.2.2 → qis-3.2.4}/qis/plots/derived/regime_data.py +0 -0
  99. {qis-3.2.2 → qis-3.2.4}/qis/plots/derived/regime_pdf.py +0 -0
  100. {qis-3.2.2 → qis-3.2.4}/qis/plots/derived/regime_scatter.py +0 -0
  101. {qis-3.2.2 → qis-3.2.4}/qis/plots/derived/returns_scatter.py +0 -0
  102. {qis-3.2.2 → qis-3.2.4}/qis/plots/errorbar.py +0 -0
  103. {qis-3.2.2 → qis-3.2.4}/qis/plots/heatmap.py +0 -0
  104. {qis-3.2.2 → qis-3.2.4}/qis/plots/histogram.py +0 -0
  105. {qis-3.2.2 → qis-3.2.4}/qis/plots/histplot2d.py +0 -0
  106. {qis-3.2.2 → qis-3.2.4}/qis/plots/lineplot.py +0 -0
  107. {qis-3.2.2 → qis-3.2.4}/qis/plots/pie.py +0 -0
  108. {qis-3.2.2 → qis-3.2.4}/qis/plots/qqplot.py +0 -0
  109. {qis-3.2.2 → qis-3.2.4}/qis/plots/reports/__init__.py +0 -0
  110. {qis-3.2.2 → qis-3.2.4}/qis/plots/reports/econ_data_single.py +0 -0
  111. {qis-3.2.2 → qis-3.2.4}/qis/plots/reports/gantt_data_history.py +0 -0
  112. {qis-3.2.2 → qis-3.2.4}/qis/plots/reports/price_history.py +0 -0
  113. {qis-3.2.2 → qis-3.2.4}/qis/plots/reports/utils.py +0 -0
  114. {qis-3.2.2 → qis-3.2.4}/qis/plots/scatter.py +0 -0
  115. {qis-3.2.2 → qis-3.2.4}/qis/plots/stackplot.py +0 -0
  116. {qis-3.2.2 → qis-3.2.4}/qis/plots/table.py +0 -0
  117. {qis-3.2.2 → qis-3.2.4}/qis/plots/time_series.py +0 -0
  118. {qis-3.2.2 → qis-3.2.4}/qis/plots/utils.py +0 -0
  119. {qis-3.2.2 → qis-3.2.4}/qis/portfolio/README.md +0 -0
  120. {qis-3.2.2 → qis-3.2.4}/qis/portfolio/__init__.py +0 -0
  121. {qis-3.2.2 → qis-3.2.4}/qis/portfolio/backtester.py +0 -0
  122. {qis-3.2.2 → qis-3.2.4}/qis/portfolio/ewm_portfolio_risk.py +0 -0
  123. {qis-3.2.2 → qis-3.2.4}/qis/portfolio/reports/__init__.py +0 -0
  124. {qis-3.2.2 → qis-3.2.4}/qis/portfolio/reports/brinson_attribution.py +0 -0
  125. {qis-3.2.2 → qis-3.2.4}/qis/portfolio/reports/multi_strategy_factsheet.py +0 -0
  126. {qis-3.2.2 → qis-3.2.4}/qis/portfolio/reports/strategy_benchmark_factsheet_pybloqs.py +0 -0
  127. {qis-3.2.2 → qis-3.2.4}/qis/portfolio/reports/strategy_signal_factsheet.py +0 -0
  128. {qis-3.2.2 → qis-3.2.4}/qis/portfolio/strats/__init__.py +0 -0
  129. {qis-3.2.2 → qis-3.2.4}/qis/portfolio/strats/quant_strats_delta1.py +0 -0
  130. {qis-3.2.2 → qis-3.2.4}/qis/portfolio/strats/seasonal_strats.py +0 -0
  131. {qis-3.2.2 → qis-3.2.4}/qis/sql_engine.py +0 -0
  132. {qis-3.2.2 → qis-3.2.4}/qis/test_data.py +0 -0
  133. {qis-3.2.2 → qis-3.2.4}/qis/utils/README.md +0 -0
  134. {qis-3.2.2 → qis-3.2.4}/qis/utils/__init__.py +0 -0
  135. {qis-3.2.2 → qis-3.2.4}/qis/utils/dates.py +0 -0
  136. {qis-3.2.2 → qis-3.2.4}/qis/utils/df_agg.py +0 -0
  137. {qis-3.2.2 → qis-3.2.4}/qis/utils/df_cut.py +0 -0
  138. {qis-3.2.2 → qis-3.2.4}/qis/utils/df_freq.py +0 -0
  139. {qis-3.2.2 → qis-3.2.4}/qis/utils/df_groups.py +0 -0
  140. {qis-3.2.2 → qis-3.2.4}/qis/utils/df_melt.py +0 -0
  141. {qis-3.2.2 → qis-3.2.4}/qis/utils/df_ops.py +0 -0
  142. {qis-3.2.2 → qis-3.2.4}/qis/utils/df_str.py +0 -0
  143. {qis-3.2.2 → qis-3.2.4}/qis/utils/df_to_scores.py +0 -0
  144. {qis-3.2.2 → qis-3.2.4}/qis/utils/df_to_weights.py +0 -0
  145. {qis-3.2.2 → qis-3.2.4}/qis/utils/generic.py +0 -0
  146. {qis-3.2.2 → qis-3.2.4}/qis/utils/np_ops.py +0 -0
  147. {qis-3.2.2 → qis-3.2.4}/qis/utils/ols.py +0 -0
  148. {qis-3.2.2 → qis-3.2.4}/qis/utils/sampling.py +0 -0
  149. {qis-3.2.2 → qis-3.2.4}/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.2
3
+ Version: 3.2.4
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.2"
3
+ version = "3.2.4"
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>"]
@@ -22,15 +22,44 @@ def run_report():
22
22
  'BNPXOV3U Index': 'BNP 3M Long DHhedged Puts'
23
23
  }
24
24
 
25
+ benchmark = 'SPTR Index'
26
+ tickers = {
27
+ benchmark: benchmark,
28
+ 'BNPIV1EE Index': 'BNP Europe 1Y Volatility',
29
+ 'BNPIV1UE Index': 'BNP US 1Y Volatility',
30
+ 'BNPXVO3A Index': 'BNP VOLA 3 Index',
31
+ 'AIJPVT1U Index': 'JPM Volatility Trend Following',
32
+ 'JPOSLVUS Index': 'JPM US Long Variance',
33
+ 'JPOSPRU2 Index': 'JPM US Put Ratio',
34
+ 'JPOSTUDN Index': 'JPM US Equity Tail Hedge',
35
+ 'JPRC85BE Index': 'JPM Dynamic 85% Rolling Collar EU',
36
+ 'JPRC85BU Index': 'JPM Dynamic 85% Rolling Collar US',
37
+ 'JPUSVXCR Index': 'JPM US Volatility Call Ratio'
38
+ }
39
+
40
+ benchmark = 'HYG US Equity'
41
+ tickers = {
42
+ benchmark: benchmark,
43
+ 'NMVVR1EL Index': 'IRVING1 EUR',
44
+ 'NMVVR1UL Index': 'IRVING1 USD',
45
+ 'NMVVR1L Index': 'IRVING1',
46
+ 'BNPXLVRE Index': 'BNP Long Rates Vol EUR',
47
+ 'BNPXLVRU Index': 'BNP Long Rates Vol USD',
48
+ 'BXIIULSV Index': 'Barclays Long Rates Vol',
49
+ 'BXIIUGNT Index': 'Barclays Gamma Neutral Vol',
50
+ 'BXIIUENT Index': 'Barclays Triangle Vol'
51
+ }
52
+
25
53
  prices = fetch_field_timeseries_per_tickers(tickers=tickers, freq='B', field='PX_LAST').ffill()
26
54
  print(prices)
27
- qis.save_df_to_csv(df=prices, file_name='qis_vol_indices', local_path=qis.get_output_path())
55
+ # qis.save_df_to_csv(df=prices, file_name='qis_vol_indices', local_path=qis.get_output_path())
28
56
 
29
- time_period = qis.TimePeriod('31Dec2019', '15Nov2024')
30
- kwargs = qis.fetch_default_report_kwargs(time_period=time_period, add_rates_data=False)
57
+ time_period = qis.TimePeriod('31Dec2024', '07Apr2025')
58
+ #kwargs = qis.fetch_default_report_kwargs(time_period=time_period, add_rates_data=False)
59
+ kwargs = qis.fetch_factsheet_config_kwargs(factsheet_config=qis.FACTSHEET_CONFIG_DAILY_DATA_SHORT_PERIOD)
31
60
 
32
61
  fig = qis.generate_multi_asset_factsheet(prices=prices,
33
- benchmark='SPTR Index',
62
+ benchmark=benchmark,
34
63
  time_period=time_period,
35
64
  **kwargs)
36
65
  qis.save_figs_to_pdf(figs=[fig],
@@ -70,7 +99,7 @@ def run_unit_test(unit_test: UnitTests):
70
99
 
71
100
  if __name__ == '__main__':
72
101
 
73
- unit_test = UnitTests.PRICE
102
+ unit_test = UnitTests.REPORT
74
103
 
75
104
  is_run_all_tests = False
76
105
  if is_run_all_tests:
@@ -56,8 +56,8 @@ from qis.models.linear.ewm_factors import (LinearModel,
56
56
  EwmLinearModel,
57
57
  compute_portfolio_benchmark_betas,
58
58
  compute_portfolio_benchmark_beta_alpha_attribution,
59
- compute_benchmarks_beta_attribution
60
- )
59
+ compute_benchmarks_beta_attribution,
60
+ estimate_linear_model)
61
61
 
62
62
  from qis.models.linear.pca import(
63
63
  compute_eigen_portfolio_weights,
@@ -664,7 +664,7 @@ def compute_ewm_vol(data: Union[pd.DataFrame, pd.Series, np.ndarray],
664
664
 
665
665
 
666
666
  def compute_ewm_newey_west_vol(data: Union[pd.DataFrame, pd.Series, np.ndarray],
667
- num_lags: int = 3,
667
+ num_lags: int = 2,
668
668
  span: Optional[Union[float, np.ndarray]] = None,
669
669
  ewm_lambda: Union[float, np.ndarray] = 0.94,
670
670
  mean_adj_type: MeanAdjType = MeanAdjType.NONE,
@@ -675,7 +675,8 @@ def compute_ewm_newey_west_vol(data: Union[pd.DataFrame, pd.Series, np.ndarray],
675
675
  annualization_factor: Optional[float] = None,
676
676
  warmup_period: Optional[int] = None,
677
677
  nan_backfill: NanBackfill = NanBackfill.FFILL
678
- ) -> Union[pd.DataFrame, pd.Series, np.ndarray]:
678
+ ) -> Tuple[Union[pd.DataFrame, pd.Series, np.ndarray],
679
+ Union[pd.DataFrame, pd.Series, np.ndarray]]:
679
680
  """
680
681
  implementation of newey west vol estimator
681
682
  implementation of ewm recursion for variance/volatility computation
@@ -694,7 +695,6 @@ def compute_ewm_newey_west_vol(data: Union[pd.DataFrame, pd.Series, np.ndarray],
694
695
  nan_backfill=nan_backfill)
695
696
 
696
697
  # initial conditions
697
- a = a
698
698
  if init_value is None:
699
699
  init_value = set_init_dim1(data=a, init_type=init_type)
700
700
 
@@ -703,18 +703,40 @@ def compute_ewm_newey_west_vol(data: Union[pd.DataFrame, pd.Series, np.ndarray],
703
703
  if isinstance(init_value, np.ndarray):
704
704
  init_value = float(init_value)
705
705
 
706
- ewm = ewm_recursion(a=np.square(a), ewm_lambda=ewm_lambda, init_value=init_value, nan_backfill=nan_backfill)
706
+ if span is not None:
707
+ ewm_lambda = 1.0 - 2.0 / (span + 1.0)
708
+ ewm_lambda_1 = 1.0 - ewm_lambda
709
+
710
+ def matrix_recursion(a_m: np.ndarray) -> np.ndarray:
711
+ t = a.shape[0]
712
+ last_covar = np.zeros((a.shape[1], a.shape[1]))
713
+ ewm_m = np.zeros_like(a_m)
714
+ for idx in range(0, t):
715
+ r_ij = np.outer(a[idx], a_m[idx])
716
+ covar = ewm_lambda_1 * r_ij + ewm_lambda * last_covar
717
+ fill_value = last_covar
718
+ last_covar = np.where(np.isfinite(covar), covar, fill_value)
719
+ ewm_m[idx, :] = np.diag(last_covar) + np.diag(np.transpose(last_covar))
720
+ return ewm_m
707
721
 
722
+ ewm0 = ewm_recursion(a=np.square(a), ewm_lambda=ewm_lambda, init_value=init_value, nan_backfill=nan_backfill)
723
+ nw_adjustment = np.zeros_like(ewm0)
708
724
  # compute m recursions
709
- for m in np.arange(1, num_lags):
725
+ for m in np.arange(1, num_lags+1):
710
726
  # lagged value
711
727
  a_m = np.empty_like(a)
712
728
  a_m[m:] = a[:-m]
713
729
  a_m[:m] = np.nan
714
- ewm_m = ewm_recursion(a=a*a_m, ewm_lambda=ewm_lambda, init_value=init_value, nan_backfill=nan_backfill)
715
- ewm += (1.0-m/(num_lags+1))*ewm_m
730
+ # qqq
731
+ ewm_m = matrix_recursion(a_m=a_m)
732
+ nw_adjustment += (1.0-m/(num_lags+1))*ewm_m
733
+
734
+ ewm_nw = ewm0 + nw_adjustment
735
+ nw_ratio = np.divide(ewm_nw, ewm0, where=ewm0 > 0.0)
736
+
716
737
  if warmup_period is not None: # set to nan first nonnan in warmup_period
717
- ewm = npo.set_nans_for_warmup_period(a=ewm, warmup_period=warmup_period)
738
+ ewm_nw = npo.set_nans_for_warmup_period(a=ewm_nw, warmup_period=warmup_period)
739
+ nw_ratio = npo.set_nans_for_warmup_period(a=nw_ratio, warmup_period=warmup_period)
718
740
 
719
741
  if annualize or annualization_factor is not None:
720
742
  if annualization_factor is None:
@@ -723,16 +745,18 @@ def compute_ewm_newey_west_vol(data: Union[pd.DataFrame, pd.Series, np.ndarray],
723
745
  else:
724
746
  warnings.warn(f"in compute_ewm annualization_factor for np array default is 1")
725
747
  annualization_factor = 1.0
726
- ewm = annualization_factor * ewm
748
+ ewm_nw = annualization_factor * ewm_nw
727
749
 
728
750
  if apply_sqrt:
729
- ewm = np.sqrt(ewm)
751
+ ewm_nw = np.sqrt(ewm_nw)
730
752
 
731
753
  if isinstance(data, pd.DataFrame):
732
- ewm = pd.DataFrame(data=ewm, index=data.index, columns=data.columns)
754
+ ewm_nw = pd.DataFrame(data=ewm_nw, index=data.index, columns=data.columns)
755
+ nw_ratio = pd.DataFrame(data=nw_ratio, index=data.index, columns=data.columns)
733
756
  elif isinstance(data, pd.Series):
734
- ewm = pd.Series(data=ewm, index=data.index, name=data.name)
735
- return ewm
757
+ ewm_nw = pd.Series(data=ewm_nw, index=data.index, name=data.name)
758
+ nw_ratio = pd.Series(data=nw_ratio, index=data.index, name=data.name)
759
+ return ewm_nw, nw_ratio
736
760
 
737
761
 
738
762
  def compute_roll_mean(data: Union[pd.DataFrame, pd.Series, np.ndarray],
@@ -10,6 +10,7 @@ from typing import Dict, Optional, Tuple, Literal
10
10
  from enum import Enum
11
11
 
12
12
  # qis
13
+ import qis as qis
13
14
  import qis.utils.df_ops as dfo
14
15
  import qis.perfstats.returns as ret
15
16
  import qis.plots.time_series as pts
@@ -51,7 +52,10 @@ class LinearModel:
51
52
  factor_exposures = pd.DataFrame.from_dict(factor_exposures)
52
53
  return factor_exposures
53
54
 
54
- def get_asset_factor_betas(self, asset: str = None) -> pd.DataFrame:
55
+ def get_asset_factor_betas(self,
56
+ time_period: TimePeriod = None,
57
+ asset: str = None
58
+ ) -> pd.DataFrame:
55
59
  """
56
60
  return df of asset exposures to factors
57
61
  """
@@ -61,6 +65,8 @@ class LinearModel:
61
65
  for factor, factor_exp in self.loadings.items():
62
66
  exps[factor] = factor_exp[asset]
63
67
  exps = pd.DataFrame.from_dict(exps)
68
+ if time_period is not None:
69
+ exps = time_period.locate(exps)
64
70
  return exps
65
71
 
66
72
  def get_asset_factor_attribution(self, asset: str = None, add_total: bool = True) -> pd.DataFrame:
@@ -247,6 +253,18 @@ def compute_benchmarks_beta_attribution(portfolio_nav: pd.Series,
247
253
  return joint_attrib
248
254
 
249
255
 
256
+ def estimate_linear_model(price: pd.Series, hedges: pd.DataFrame,
257
+ freq: str = 'W-WED',
258
+ span: int = 26,
259
+ mean_adj_type: MeanAdjType = MeanAdjType.NONE
260
+ ) -> EwmLinearModel:
261
+ y = qis.to_returns(price.to_frame(), freq=freq, is_log_returns=True, drop_first=True)
262
+ x = qis.to_returns(hedges, freq=freq, is_log_returns=True, drop_first=True)
263
+ ewm_linear_model = EwmLinearModel(x=x.reindex(index=y.index), y=y)
264
+ ewm_linear_model.fit(span=span, is_x_correlated=True, mean_adj_type=mean_adj_type)
265
+ return ewm_linear_model
266
+
267
+
250
268
  class UnitTests(Enum):
251
269
  MODEL = 1
252
270
  ATTRIBUTION = 2
@@ -313,3 +331,5 @@ if __name__ == '__main__':
313
331
  run_unit_test(unit_test=unit_test)
314
332
  else:
315
333
  run_unit_test(unit_test=unit_test)
334
+
335
+
@@ -4,8 +4,6 @@ import pandas as pd
4
4
  import matplotlib.pyplot as plt
5
5
  from typing import List, Tuple, Callable, Optional, Dict, Union
6
6
  from enum import Enum
7
-
8
- import qis
9
7
  # qis
10
8
  import qis.utils.dates as da
11
9
  import qis.utils.df_str as dfs
@@ -106,7 +104,7 @@ def get_ra_perf_benchmark_columns(prices: pd.DataFrame,
106
104
  df[perf_column.to_str(**kwargs)] = dfs.series_to_str(ds=ra_perf_table[perf_column.to_str()],
107
105
  var_format=perf_column.to_format(**kwargs))
108
106
  else:
109
- df[perf_column.to_str(**kwargs)] = ra_perf_table[perf_column.to_str()]
107
+ df[perf_column.to_str()] = ra_perf_table[perf_column.to_str()]
110
108
 
111
109
  if drop_benchmark:
112
110
  df = df.drop(benchmark, axis=0)
@@ -223,7 +223,7 @@ def compute_periodic_returns(prices: pd.DataFrame,
223
223
 
224
224
  if add_total:
225
225
  if freq == 'ME':
226
- total_name = total_name or 'last 12m'
226
+ total_name = total_name or 'YTD'
227
227
  elif freq == 'YE':
228
228
  total_name = total_name or 'Total'
229
229
  else:
@@ -649,7 +649,8 @@ class MultiPortfolioData:
649
649
  ax: plt.Subplot = None,
650
650
  **kwargs) -> None:
651
651
 
652
- turnover = self.get_turnover(turnover_rolling_period=turnover_rolling_period, freq_turnover=freq_turnover,
652
+ turnover = self.get_turnover(turnover_rolling_period=turnover_rolling_period,
653
+ freq_turnover=freq_turnover,
653
654
  is_unit_based_traded_volume=is_unit_based_traded_volume,
654
655
  time_period=time_period)
655
656
  freq = pd.infer_freq(turnover.index)
@@ -339,6 +339,8 @@ class PortfolioData:
339
339
  def get_turnover(self,
340
340
  is_agg: bool = False,
341
341
  is_grouped: bool = False,
342
+ group_data: pd.Series = None,
343
+ group_order: List[str] = None,
342
344
  time_period: TimePeriod = None,
343
345
  roll_period: Optional[int] = 260,
344
346
  is_vol_adjusted: bool = False,
@@ -366,11 +368,15 @@ class PortfolioData:
366
368
  turnover = pd.Series(np.nansum(turnover, axis=1), index=turnover.index, name=self.nav.name)
367
369
  turnover = turnover.reindex(index=self.nav.index)
368
370
  elif is_grouped: # agg by groups
371
+ if group_data is None:
372
+ group_data = self.group_data
373
+ if group_order is None:
374
+ group_order = self.group_order
369
375
  turnover = dfg.agg_df_by_groups_ax1(df=turnover,
370
- group_data=self.group_data,
376
+ group_data=group_data,
371
377
  agg_func=np.nansum,
372
378
  total_column=str(self.nav.name) if add_total else None,
373
- group_order=self.group_order)
379
+ group_order=group_order)
374
380
  else:
375
381
  if add_total:
376
382
  turnover = pd.concat([turnover.sum(axis=1).rename(self.nav.name), turnover], axis=1)
@@ -1495,6 +1501,13 @@ class StrategySignalData:
1495
1501
  data_dict[key] = time_period.locate(df)
1496
1502
  return StrategySignalData(**data_dict)
1497
1503
 
1504
+ def rename_data(self, names_map: Dict[str, str]) -> StrategySignalData:
1505
+ data_dict = asdict(self)
1506
+ for key, df in data_dict.items():
1507
+ if df is not None:
1508
+ data_dict[key] = df.rename(names_map, axis=1)
1509
+ return StrategySignalData(**data_dict)
1510
+
1498
1511
  def get_current_signal_by_groups(self, group_data: pd.Series,
1499
1512
  group_order: List[str] = None
1500
1513
  ) -> Dict[str, pd.DataFrame]:
@@ -82,9 +82,9 @@ class FactsheetConfig(NamedTuple):
82
82
  # create enumerations
83
83
  FACTSHEET_CONFIG_DAILY_DATA_LONG_PERIOD = FactsheetConfig()
84
84
 
85
- FACTSHEET_CONFIG_DAILY_DATA_SHORT_PERIOD = FactsheetConfig(heatmap_freq='YE',
86
- x_date_freq='QE',
87
- freq_regime='ME',
85
+ FACTSHEET_CONFIG_DAILY_DATA_SHORT_PERIOD = FactsheetConfig(heatmap_freq='ME',
86
+ x_date_freq='ME',
87
+ freq_regime='W-WED',
88
88
  freq_reg='W-WED',
89
89
  alpha_an_factor=52
90
90
  )
@@ -47,14 +47,21 @@ class MultiAssetsReport:
47
47
  self.perf_params = perf_params
48
48
  self.regime_params = regime_params
49
49
 
50
- def get_prices(self, benchmark: str = None, time_period: TimePeriod = None) -> pd.DataFrame:
51
- if benchmark is not None and benchmark not in self.prices.columns:
50
+ def get_prices(self,
51
+ benchmark: str = None,
52
+ add_benchmarks_to_navs: bool = False,
53
+ time_period: TimePeriod = None) -> pd.DataFrame:
54
+ if add_benchmarks_to_navs:
55
+ prices = pd.concat([self.benchmark_prices, self.prices], axis=1)
56
+ elif benchmark is not None and benchmark not in self.prices.columns:
52
57
  if isinstance(self.benchmark_prices, pd.Series):
53
58
  prices = pd.concat([self.benchmark_prices, self.prices], axis=1)
54
59
  else:
55
60
  prices = pd.concat([self.benchmark_prices[benchmark], self.prices], axis=1)
56
61
  else:
57
62
  prices = self.prices
63
+ # check in case
64
+ prices = prices.loc[:, ~prices.columns.duplicated(keep='first')]
58
65
  if time_period is not None:
59
66
  prices = time_period.locate(prices)
60
67
  return prices
@@ -63,7 +70,7 @@ class MultiAssetsReport:
63
70
  regime_benchmark: str,
64
71
  data_df: pd.DataFrame,
65
72
  time_period: TimePeriod = None,
66
- regime_params: BenchmarkReturnsQuantileRegimeSpecs = REGIME_PARAMS
73
+ regime_params: BenchmarkReturnsQuantileRegimeSpecs = None
67
74
  ) -> None:
68
75
  if isinstance(self.benchmark_prices, pd.Series):
69
76
  pivot_prices = self.benchmark_prices
@@ -78,10 +85,11 @@ class MultiAssetsReport:
78
85
  data_df=data_df,
79
86
  pivot_prices=pivot_prices,
80
87
  benchmark=regime_benchmark,
81
- regime_params=regime_params)
88
+ regime_params=regime_params or self.regime_params)
82
89
 
83
90
  def plot_ra_perf_table(self,
84
91
  benchmark: str,
92
+ add_benchmarks_to_navs: bool = False,
85
93
  time_period: TimePeriod = None,
86
94
  perf_columns: List[PerfStat] = qis.BENCHMARK_TABLE_COLUMNS,
87
95
  perf_params: PerfParams = None,
@@ -89,8 +97,10 @@ class MultiAssetsReport:
89
97
  ax: plt.Subplot = None,
90
98
  **kwargs
91
99
  ) -> None:
92
- prices = self.get_prices(benchmark, time_period=time_period)
93
- title = title or f"RA performance table for {self.perf_params.freq_vol}-freq returns with beta to {benchmark}: {qis.get_time_period(prices).to_str()}"
100
+ prices = self.get_prices(benchmark=benchmark, add_benchmarks_to_navs=add_benchmarks_to_navs,
101
+ time_period=time_period)
102
+ title = title or f"RA performance table for {self.perf_params.freq_vol}-freq returns with" \
103
+ f" beta to {benchmark}: {qis.get_time_period(prices).to_str()}"
94
104
  #if len(prices.columns) >= 12:
95
105
  # local_kwargs = qis.update_kwargs(kwargs, dict(fontsize=3, pad=10, bbox=(0, -0.4, 1.0, 1.6)))
96
106
  #else:
@@ -153,7 +163,8 @@ class MultiAssetsReport:
153
163
  perf_params: PerfParams = None,
154
164
  ax: plt.Subplot = None,
155
165
  **kwargs) -> None:
156
- prices = self.get_prices(time_period=time_period, benchmark=regime_benchmark)
166
+ prices = self.get_prices(time_period=time_period, benchmark=regime_benchmark,
167
+ add_benchmarks_to_navs=add_benchmarks_to_navs)
157
168
  prices0 = prices
158
169
  if not add_benchmarks_to_navs and regime_benchmark in prices.columns:
159
170
  prices0 = prices0.drop(regime_benchmark, axis=1)
@@ -194,6 +205,7 @@ class MultiAssetsReport:
194
205
  self.add_regime_shadows(ax=ax, regime_benchmark=regime_benchmark, data_df=prices)
195
206
 
196
207
  def plot_annual_returns(self,
208
+ add_benchmarks_to_navs: bool = False,
197
209
  heatmap_freq: str = 'YE',
198
210
  date_format: str = '%Y',
199
211
  time_period: TimePeriod = None,
@@ -205,7 +217,8 @@ class MultiAssetsReport:
205
217
  new_kwargs=dict(fontsize=table_fontsize,
206
218
  square=False,
207
219
  x_rotation=90))
208
- qis.plot_periodic_returns_table(prices=self.get_prices(time_period=time_period),
220
+ qis.plot_periodic_returns_table(prices=self.get_prices(time_period=time_period,
221
+ add_benchmarks_to_navs=add_benchmarks_to_navs),
209
222
  freq=heatmap_freq,
210
223
  ax=ax,
211
224
  title=title or f"{heatmap_freq} Returns",
@@ -214,11 +227,12 @@ class MultiAssetsReport:
214
227
 
215
228
  def plot_corr_table(self,
216
229
  corr_freq: str = 'W-WED',
230
+ add_benchmarks_to_navs: bool = True,
217
231
  time_period: TimePeriod = None,
218
232
  ax: plt.Subplot = None,
219
233
  **kwargs
220
234
  ) -> None:
221
- prices = self.get_prices(time_period=time_period)
235
+ prices = self.get_prices(time_period=time_period, add_benchmarks_to_navs=add_benchmarks_to_navs)
222
236
  if len(prices.columns) == 1: # cannot compute corr
223
237
  return
224
238
  if len(prices.columns) >= 12:
@@ -322,6 +336,7 @@ class MultiAssetsReport:
322
336
  roll_freq=freq_sharpe,
323
337
  legend_stats=legend_stats,
324
338
  regime_benchmark=regime_benchmark,
339
+ regime_params=self.regime_params,
325
340
  ax=ax,
326
341
  **kwargs)
327
342
  return fig
@@ -381,11 +396,12 @@ class MultiAssetsReport:
381
396
  time_period: TimePeriod = None,
382
397
  benchmark: Optional[str] = None,
383
398
  perf_column: PerfStat = PerfStat.SHARPE_RF0,
399
+ add_benchmarks_to_navs: bool = True,
384
400
  title: str = None,
385
401
  ax: plt.Subplot = None,
386
402
  **kwargs
387
403
  ) -> None:
388
- prices = self.get_prices(benchmark=benchmark, time_period=time_period)
404
+ prices = self.get_prices(benchmark=benchmark, add_benchmarks_to_navs=add_benchmarks_to_navs, time_period=time_period)
389
405
  qis.plot_ra_perf_bars(prices=prices,
390
406
  benchmark=benchmark,
391
407
  perf_column=perf_column,
@@ -404,8 +420,10 @@ def generate_multi_asset_factsheet(prices: pd.DataFrame,
404
420
  heatmap_freq: str = 'YE',
405
421
  time_period: TimePeriod = None, # time period for reporting
406
422
  figsize: Tuple[float, float] = (8.3, 11.7), # A4 for portrait
407
- fontsize: int = 3,
423
+ fontsize: int = 4,
408
424
  factsheet_name: str = None,
425
+ performance_bars: Tuple[PerfStat, PerfStat] = (PerfStat.SHARPE_RF0, PerfStat.MAX_DD),
426
+ drop_1y_ra_perf_table: bool = True,
409
427
  **kwargs
410
428
  ) -> plt.Figure:
411
429
  # use passed benchmark
@@ -490,16 +508,22 @@ def generate_multi_asset_factsheet(prices: pd.DataFrame,
490
508
  **kwargs)
491
509
 
492
510
  report.plot_performance_bars(ax=fig.add_subplot(gs[0:2, 2]),
493
- perf_column=PerfStat.SHARPE_RF0, **kwargs)
511
+ add_benchmarks_to_navs=add_benchmarks_to_navs,
512
+ benchmark=benchmark,
513
+ perf_column=performance_bars[0], **kwargs)
494
514
  report.plot_performance_bars(ax=fig.add_subplot(gs[0:2, 3]),
495
- perf_column=PerfStat.MAX_DD, **kwargs)
515
+ add_benchmarks_to_navs=add_benchmarks_to_navs,
516
+ benchmark=benchmark,
517
+ perf_column=performance_bars[1], **kwargs)
496
518
 
497
- if len(prices.columns) >= 8:
519
+ if drop_1y_ra_perf_table or len(prices.columns) >= 8:
498
520
  report.plot_ra_perf_table(benchmark=benchmark,
521
+ add_benchmarks_to_navs=add_benchmarks_to_navs,
499
522
  ax=fig.add_subplot(gs[2:4, 2:]),
500
523
  **kwargs)
501
524
  else: # plot two tables
502
525
  report.plot_ra_perf_table(benchmark=benchmark,
526
+ add_benchmarks_to_navs=add_benchmarks_to_navs,
503
527
  ax=fig.add_subplot(gs[2, 2:]),
504
528
  **kwargs)
505
529
 
@@ -513,14 +537,17 @@ def generate_multi_asset_factsheet(prices: pd.DataFrame,
513
537
  **local_kwargs)
514
538
 
515
539
  report.plot_annual_returns(ax=fig.add_subplot(gs[4:6, 2:]),
540
+ add_benchmarks_to_navs=add_benchmarks_to_navs,
516
541
  heatmap_freq=heatmap_freq,
517
542
  **kwargs)
518
543
 
519
544
  report.plot_corr_table(freq=perf_params.freq,
545
+ add_benchmarks_to_navs=add_benchmarks_to_navs,
520
546
  ax=fig.add_subplot(gs[6:8, 2]),
521
547
  **kwargs)
522
548
  report.plot_corr_table(freq=perf_params.freq,
523
549
  ax=fig.add_subplot(gs[6:8, 3]),
550
+ add_benchmarks_to_navs=add_benchmarks_to_navs,
524
551
  **qis.update_kwargs(kwargs, dict(time_period=time_period1)))
525
552
 
526
553
  report.plot_regime_data(benchmark=benchmark,
@@ -82,22 +82,22 @@ def generate_multi_portfolio_factsheet_with_pyblogs(multi_portfolio_data: MultiP
82
82
  b_ra_perf_table = p.Block([p.Paragraph(f"Risk-adjusted Performance table for {key}", **KWARGS_TITLE),
83
83
  p.Block(table,
84
84
  formatters=[
85
- tf.FmtPercent(n_decimals=2, columns=[PerfStat.TOTAL_RETURN.to_str(**kwargs),
86
- PerfStat.PA_RETURN.to_str(**kwargs),
87
- PerfStat.VOL.to_str(**kwargs),
88
- PerfStat.MAX_DD.to_str(**kwargs),
89
- PerfStat.ALPHA_AN.to_str(**kwargs),
90
- PerfStat.R2.to_str(**kwargs)
85
+ tf.FmtPercent(n_decimals=2, columns=[PerfStat.TOTAL_RETURN.to_str(),
86
+ PerfStat.PA_RETURN.to_str(),
87
+ PerfStat.VOL.to_str(),
88
+ PerfStat.MAX_DD.to_str(),
89
+ PerfStat.ALPHA_AN.to_str(),
90
+ PerfStat.R2.to_str()
91
91
  ], apply_to_header_and_index=False),
92
92
  fmt_highlight_base,
93
93
  fmt_highlight_index,
94
94
  tf.FmtReplaceNaN(value=''),
95
- tf.FmtHeatmap(columns=[PerfStat.PA_RETURN.to_str(**kwargs),
96
- PerfStat.SHARPE_EXCESS.to_str(**kwargs),
97
- PerfStat.ALPHA_AN.to_str(**kwargs),
98
- PerfStat.BETA.to_str(**kwargs)]),
99
- tf.FmtHeatmap(columns=[PerfStat.MAX_DD.to_str(**kwargs),
100
- PerfStat.SKEWNESS.to_str(**kwargs)], max_color=(255,0,255)),
95
+ tf.FmtHeatmap(columns=[PerfStat.PA_RETURN.to_str(),
96
+ PerfStat.SHARPE_EXCESS.to_str(),
97
+ PerfStat.ALPHA_AN.to_str(),
98
+ PerfStat.BETA.to_str()]),
99
+ tf.FmtHeatmap(columns=[PerfStat.MAX_DD.to_str(),
100
+ PerfStat.SKEWNESS.to_str()], max_color=(255,0,255)),
101
101
  tf.FmtAddCellBorder(each=1.0,
102
102
  columns=ra_perf_table.columns.to_list()[:1],
103
103
  color=tf.colors.GREY,
@@ -114,7 +114,7 @@ def generate_multi_portfolio_factsheet_with_pyblogs(multi_portfolio_data: MultiP
114
114
  fig_size = qis.get_df_table_size(df=ra_perf_table)
115
115
  fig_perf_bar, axs = plt.subplots(1, len(perf_columns), figsize=(12, 1.2*fig_size[1]), constrained_layout=True)
116
116
  for idx, perf_column in enumerate(perf_columns):
117
- df = ra_perf_table[perf_column.to_str(**kwargs)].to_frame()
117
+ df = ra_perf_table[perf_column.to_str()].to_frame()
118
118
  colors = qis.compute_heatmap_colors(a=df.to_numpy())
119
119
  qis.plot_vbars(df=df,
120
120
  var_format=perf_column.to_format(**kwargs),
@@ -132,7 +132,8 @@ def generate_multi_portfolio_factsheet_with_pyblogs(multi_portfolio_data: MultiP
132
132
 
133
133
  # 3. regime conditional
134
134
  fig_size = qis.get_df_table_size(df=ra_perf_table)
135
- fig_perf_regime, axs = plt.subplots(1, len(multi_portfolio_data.benchmark_prices.columns), figsize=(12, 1.2*fig_size[1]), constrained_layout=True)
135
+ fig_perf_regime, axs = plt.subplots(1, len(multi_portfolio_data.benchmark_prices.columns),
136
+ figsize=(12, 1.2*fig_size[1]), constrained_layout=True)
136
137
  if len(multi_portfolio_data.benchmark_prices.columns) == 1:
137
138
  axs = [axs]
138
139
  for idx, benchmark in enumerate(multi_portfolio_data.benchmark_prices.columns):
@@ -195,7 +196,7 @@ def generate_multi_portfolio_factsheet_with_pyblogs(multi_portfolio_data: MultiP
195
196
  x_limits = (np.nanmin(xy[param_name]), np.nanmax(xy[param_name]))
196
197
 
197
198
  fig_scatter1, ax = plt.subplots(1, 1, figsize=(14, 4.5), constrained_layout=True)
198
- qis.plot_scatter(df=xy, x=param_name, y=PerfStat.SHARPE_EXCESS.to_str(**kwargs), hue=hue_name,
199
+ qis.plot_scatter(df=xy, x=param_name, y=PerfStat.SHARPE_EXCESS.to_str(), hue=hue_name,
199
200
  title=f"Sharpe",
200
201
  var_format='{:.2f}',
201
202
  x_limits=x_limits,
@@ -207,7 +208,7 @@ def generate_multi_portfolio_factsheet_with_pyblogs(multi_portfolio_data: MultiP
207
208
  blocks.append(b_fig_scatter1)
208
209
 
209
210
  fig_scatter2, ax = plt.subplots(1, 1, figsize=(14, 4.5), constrained_layout=True)
210
- qis.plot_scatter(df=xy, x=param_name, y=PerfStat.MAX_DD.to_str(**kwargs), hue=hue_name,
211
+ qis.plot_scatter(df=xy, x=param_name, y=PerfStat.MAX_DD.to_str(), hue=hue_name,
211
212
  title=f"Max DD",
212
213
  var_format='{:.2%}',
213
214
  x_limits=x_limits,
@@ -507,6 +507,8 @@ def weights_tracking_error_report_by_ac_subac(multi_portfolio_data: MultiPortfol
507
507
  ac_group_order: List[str] = None,
508
508
  sub_ac_group_data: pd.Series = None,
509
509
  sub_ac_group_order: List[str] = None,
510
+ turnover_groups: pd.Series = None,
511
+ turnover_order: List[str] = None,
510
512
  time_period: TimePeriod = None,
511
513
  perf_params: PerfParams = PERF_PARAMS,
512
514
  regime_params: BenchmarkReturnsQuantileRegimeSpecs = REGIME_PARAMS,
@@ -40,8 +40,8 @@ def generate_strategy_factsheet(portfolio_data: PortfolioData,
40
40
  fontsize: int = 4,
41
41
  weight_change_sample_size: int = 20,
42
42
  weight_report_time_period: TimePeriod = None,
43
- add_current_position_var_risk_sheet: bool = True,
44
- add_weights_turnover_sheet: bool = True,
43
+ add_current_position_var_risk_sheet: bool = False,
44
+ add_weights_turnover_sheet: bool = False,
45
45
  add_grouped_exposures: bool = False,
46
46
  add_grouped_cum_pnl: bool = False,
47
47
  add_weight_change_report: bool = False,
@@ -608,8 +608,7 @@ def generate_strategy_factsheet(portfolio_data: PortfolioData,
608
608
 
609
609
  fig = qis.generate_price_history_report(prices=portfolio_data.prices,
610
610
  **qis.update_kwargs(kwargs, dict(fontsize=4, figsize=figsize,
611
- perf_columns=perf_columns,
612
- df_to_add=df_to_add)))
611
+ perf_columns=perf_columns)))
613
612
  fig.suptitle('Program Instrument Universe', fontweight="bold", fontsize=8, color='blue')
614
613
  figs.append(fig)
615
614
 
@@ -18,4 +18,3 @@ OUTPUT_PATH:
18
18
 
19
19
  AWS_POSTGRES:
20
20
  ""
21
-
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
File without changes
File without changes