qis 3.0.5__tar.gz → 3.0.7__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 (150) hide show
  1. {qis-3.0.5 → qis-3.0.7}/PKG-INFO +1 -1
  2. {qis-3.0.5 → qis-3.0.7}/pyproject.toml +1 -5
  3. {qis-3.0.5 → qis-3.0.7}/qis/examples/core/price_plots.py +20 -20
  4. {qis-3.0.5 → qis-3.0.7}/qis/examples/factsheets/strategy_benchmark.py +16 -4
  5. {qis-3.0.5 → qis-3.0.7}/qis/examples/perf_external_assets.py +1 -1
  6. {qis-3.0.5 → qis-3.0.7}/qis/examples/try_pybloqs.py +9 -9
  7. {qis-3.0.5 → qis-3.0.7}/qis/examples/vix_conditional_returns.py +1 -1
  8. {qis-3.0.5 → qis-3.0.7}/qis/file_utils.py +12 -8
  9. {qis-3.0.5 → qis-3.0.7}/qis/models/linear/plot_correlations.py +8 -8
  10. {qis-3.0.5 → qis-3.0.7}/qis/plots/derived/prices.py +13 -13
  11. {qis-3.0.5 → qis-3.0.7}/qis/plots/derived/regime_scatter.py +9 -9
  12. {qis-3.0.5 → qis-3.0.7}/qis/portfolio/__init__.py +1 -0
  13. {qis-3.0.5 → qis-3.0.7}/qis/portfolio/multi_portfolio_data.py +38 -32
  14. {qis-3.0.5 → qis-3.0.7}/qis/portfolio/portfolio_data.py +4 -2
  15. {qis-3.0.5 → qis-3.0.7}/qis/portfolio/reports/brinson_attribution.py +34 -22
  16. {qis-3.0.5 → qis-3.0.7}/qis/portfolio/reports/multi_assets_factsheet.py +3 -3
  17. {qis-3.0.5 → qis-3.0.7}/qis/portfolio/reports/multi_strategy_factseet_pybloqs.py +3 -3
  18. {qis-3.0.5 → qis-3.0.7}/qis/portfolio/reports/multi_strategy_factsheet.py +3 -3
  19. {qis-3.0.5 → qis-3.0.7}/qis/portfolio/reports/strategy_benchmark_factsheet.py +241 -113
  20. {qis-3.0.5 → qis-3.0.7}/LICENSE.txt +0 -0
  21. {qis-3.0.5 → qis-3.0.7}/README.md +0 -0
  22. {qis-3.0.5 → qis-3.0.7}/qis/__init__.py +0 -0
  23. {qis-3.0.5 → qis-3.0.7}/qis/examples/best_returns.py +0 -0
  24. {qis-3.0.5 → qis-3.0.7}/qis/examples/bond_futures_portfolio.py +0 -0
  25. {qis-3.0.5 → qis-3.0.7}/qis/examples/bootstrap_analysis.py +0 -0
  26. {qis-3.0.5 → qis-3.0.7}/qis/examples/boxplot_conditional_returns.py +0 -0
  27. {qis-3.0.5 → qis-3.0.7}/qis/examples/btc_asset_corr.py +0 -0
  28. {qis-3.0.5 → qis-3.0.7}/qis/examples/constant_notional.py +0 -0
  29. {qis-3.0.5 → qis-3.0.7}/qis/examples/constant_weight_portfolios.py +0 -0
  30. {qis-3.0.5 → qis-3.0.7}/qis/examples/core/perf_bbg_prices.py +0 -0
  31. {qis-3.0.5 → qis-3.0.7}/qis/examples/core/us_election.py +0 -0
  32. {qis-3.0.5 → qis-3.0.7}/qis/examples/credit_spreads.py +0 -0
  33. {qis-3.0.5 → qis-3.0.7}/qis/examples/credit_trackers.py +0 -0
  34. {qis-3.0.5 → qis-3.0.7}/qis/examples/europe_futures.py +0 -0
  35. {qis-3.0.5 → qis-3.0.7}/qis/examples/factsheets/multi_assets.py +0 -0
  36. {qis-3.0.5 → qis-3.0.7}/qis/examples/factsheets/multi_strategy.py +0 -0
  37. {qis-3.0.5 → qis-3.0.7}/qis/examples/factsheets/pyblogs_reports.py +0 -0
  38. {qis-3.0.5 → qis-3.0.7}/qis/examples/factsheets/strategy.py +0 -0
  39. {qis-3.0.5 → qis-3.0.7}/qis/examples/generate_option_rolls.py +0 -0
  40. {qis-3.0.5 → qis-3.0.7}/qis/examples/interpolation_infrequent_returns.py +0 -0
  41. {qis-3.0.5 → qis-3.0.7}/qis/examples/leveraged_strategies.py +0 -0
  42. {qis-3.0.5 → qis-3.0.7}/qis/examples/long_short.py +0 -0
  43. {qis-3.0.5 → qis-3.0.7}/qis/examples/momentum_indices.py +0 -0
  44. {qis-3.0.5 → qis-3.0.7}/qis/examples/oakmark_analysis.py +0 -0
  45. {qis-3.0.5 → qis-3.0.7}/qis/examples/ohlc_vol_analysis.py +0 -0
  46. {qis-3.0.5 → qis-3.0.7}/qis/examples/overnight_returns.py +0 -0
  47. {qis-3.0.5 → qis-3.0.7}/qis/examples/perp_pricing.py +0 -0
  48. {qis-3.0.5 → qis-3.0.7}/qis/examples/readme_performances.py +0 -0
  49. {qis-3.0.5 → qis-3.0.7}/qis/examples/risk_return_frontier.py +0 -0
  50. {qis-3.0.5 → qis-3.0.7}/qis/examples/rolling_performance.py +0 -0
  51. {qis-3.0.5 → qis-3.0.7}/qis/examples/seasonality.py +0 -0
  52. {qis-3.0.5 → qis-3.0.7}/qis/examples/sharpe_vs_sortino.py +0 -0
  53. {qis-3.0.5 → qis-3.0.7}/qis/examples/simulate_quant_strats.py +0 -0
  54. {qis-3.0.5 → qis-3.0.7}/qis/examples/test_ewm.py +0 -0
  55. {qis-3.0.5 → qis-3.0.7}/qis/examples/test_scatter.py +0 -0
  56. {qis-3.0.5 → qis-3.0.7}/qis/examples/universe_corrs.py +0 -0
  57. {qis-3.0.5 → qis-3.0.7}/qis/examples/vix_beta_to_equities_bonds.py +0 -0
  58. {qis-3.0.5 → qis-3.0.7}/qis/examples/vix_spy_by_year.py +0 -0
  59. {qis-3.0.5 → qis-3.0.7}/qis/examples/vix_tenor_analysis.py +0 -0
  60. {qis-3.0.5 → qis-3.0.7}/qis/examples/vol_without_weekends.py +0 -0
  61. {qis-3.0.5 → qis-3.0.7}/qis/local_path.py +0 -0
  62. {qis-3.0.5 → qis-3.0.7}/qis/models/README.md +0 -0
  63. {qis-3.0.5 → qis-3.0.7}/qis/models/__init__.py +0 -0
  64. {qis-3.0.5 → qis-3.0.7}/qis/models/linear/__init__.py +0 -0
  65. {qis-3.0.5 → qis-3.0.7}/qis/models/linear/auto_corr.py +0 -0
  66. {qis-3.0.5 → qis-3.0.7}/qis/models/linear/corr_cov_matrix.py +0 -0
  67. {qis-3.0.5 → qis-3.0.7}/qis/models/linear/ewm.py +0 -0
  68. {qis-3.0.5 → qis-3.0.7}/qis/models/linear/ewm_convolution.py +0 -0
  69. {qis-3.0.5 → qis-3.0.7}/qis/models/linear/ewm_factors.py +0 -0
  70. {qis-3.0.5 → qis-3.0.7}/qis/models/linear/ewm_winsor_outliers.py +0 -0
  71. {qis-3.0.5 → qis-3.0.7}/qis/models/linear/pca.py +0 -0
  72. {qis-3.0.5 → qis-3.0.7}/qis/models/linear/ra_returns.py +0 -0
  73. {qis-3.0.5 → qis-3.0.7}/qis/models/stats/__init__.py +0 -0
  74. {qis-3.0.5 → qis-3.0.7}/qis/models/stats/bootstrap.py +0 -0
  75. {qis-3.0.5 → qis-3.0.7}/qis/models/stats/ohlc_vol.py +0 -0
  76. {qis-3.0.5 → qis-3.0.7}/qis/models/stats/rolling_stats.py +0 -0
  77. {qis-3.0.5 → qis-3.0.7}/qis/models/stats/test_bootstrap.py +0 -0
  78. {qis-3.0.5 → qis-3.0.7}/qis/perfstats/README.md +0 -0
  79. {qis-3.0.5 → qis-3.0.7}/qis/perfstats/__init__.py +0 -0
  80. {qis-3.0.5 → qis-3.0.7}/qis/perfstats/cond_regression.py +0 -0
  81. {qis-3.0.5 → qis-3.0.7}/qis/perfstats/config.py +0 -0
  82. {qis-3.0.5 → qis-3.0.7}/qis/perfstats/desc_table.py +0 -0
  83. {qis-3.0.5 → qis-3.0.7}/qis/perfstats/fx_ops.py +0 -0
  84. {qis-3.0.5 → qis-3.0.7}/qis/perfstats/perf_stats.py +0 -0
  85. {qis-3.0.5 → qis-3.0.7}/qis/perfstats/regime_classifier.py +0 -0
  86. {qis-3.0.5 → qis-3.0.7}/qis/perfstats/returns.py +0 -0
  87. {qis-3.0.5 → qis-3.0.7}/qis/perfstats/timeseries_bfill.py +0 -0
  88. {qis-3.0.5 → qis-3.0.7}/qis/plots/README.md +0 -0
  89. {qis-3.0.5 → qis-3.0.7}/qis/plots/__init__.py +0 -0
  90. {qis-3.0.5 → qis-3.0.7}/qis/plots/bars.py +0 -0
  91. {qis-3.0.5 → qis-3.0.7}/qis/plots/boxplot.py +0 -0
  92. {qis-3.0.5 → qis-3.0.7}/qis/plots/contour.py +0 -0
  93. {qis-3.0.5 → qis-3.0.7}/qis/plots/derived/__init__.py +0 -0
  94. {qis-3.0.5 → qis-3.0.7}/qis/plots/derived/data_timeseries.py +0 -0
  95. {qis-3.0.5 → qis-3.0.7}/qis/plots/derived/desc_table.py +0 -0
  96. {qis-3.0.5 → qis-3.0.7}/qis/plots/derived/drawdowns.py +0 -0
  97. {qis-3.0.5 → qis-3.0.7}/qis/plots/derived/perf_table.py +0 -0
  98. {qis-3.0.5 → qis-3.0.7}/qis/plots/derived/regime_class_table.py +0 -0
  99. {qis-3.0.5 → qis-3.0.7}/qis/plots/derived/regime_data.py +0 -0
  100. {qis-3.0.5 → qis-3.0.7}/qis/plots/derived/regime_pdf.py +0 -0
  101. {qis-3.0.5 → qis-3.0.7}/qis/plots/derived/returns_heatmap.py +0 -0
  102. {qis-3.0.5 → qis-3.0.7}/qis/plots/derived/returns_scatter.py +0 -0
  103. {qis-3.0.5 → qis-3.0.7}/qis/plots/errorbar.py +0 -0
  104. {qis-3.0.5 → qis-3.0.7}/qis/plots/heatmap.py +0 -0
  105. {qis-3.0.5 → qis-3.0.7}/qis/plots/histogram.py +0 -0
  106. {qis-3.0.5 → qis-3.0.7}/qis/plots/histplot2d.py +0 -0
  107. {qis-3.0.5 → qis-3.0.7}/qis/plots/lineplot.py +0 -0
  108. {qis-3.0.5 → qis-3.0.7}/qis/plots/pie.py +0 -0
  109. {qis-3.0.5 → qis-3.0.7}/qis/plots/qqplot.py +0 -0
  110. {qis-3.0.5 → qis-3.0.7}/qis/plots/reports/__init__.py +0 -0
  111. {qis-3.0.5 → qis-3.0.7}/qis/plots/reports/econ_data_single.py +0 -0
  112. {qis-3.0.5 → qis-3.0.7}/qis/plots/reports/gantt_data_history.py +0 -0
  113. {qis-3.0.5 → qis-3.0.7}/qis/plots/reports/price_history.py +0 -0
  114. {qis-3.0.5 → qis-3.0.7}/qis/plots/reports/utils.py +0 -0
  115. {qis-3.0.5 → qis-3.0.7}/qis/plots/scatter.py +0 -0
  116. {qis-3.0.5 → qis-3.0.7}/qis/plots/stackplot.py +0 -0
  117. {qis-3.0.5 → qis-3.0.7}/qis/plots/table.py +0 -0
  118. {qis-3.0.5 → qis-3.0.7}/qis/plots/time_series.py +0 -0
  119. {qis-3.0.5 → qis-3.0.7}/qis/plots/utils.py +0 -0
  120. {qis-3.0.5 → qis-3.0.7}/qis/portfolio/README.md +0 -0
  121. {qis-3.0.5 → qis-3.0.7}/qis/portfolio/backtester.py +0 -0
  122. {qis-3.0.5 → qis-3.0.7}/qis/portfolio/ewm_portfolio_risk.py +0 -0
  123. {qis-3.0.5 → qis-3.0.7}/qis/portfolio/reports/__init__.py +0 -0
  124. {qis-3.0.5 → qis-3.0.7}/qis/portfolio/reports/config.py +0 -0
  125. {qis-3.0.5 → qis-3.0.7}/qis/portfolio/reports/strategy_benchmark_factsheet_pybloqs.py +0 -0
  126. {qis-3.0.5 → qis-3.0.7}/qis/portfolio/reports/strategy_factsheet.py +0 -0
  127. {qis-3.0.5 → qis-3.0.7}/qis/portfolio/reports/strategy_signal_factsheet.py +0 -0
  128. {qis-3.0.5 → qis-3.0.7}/qis/portfolio/strats/__init__.py +0 -0
  129. {qis-3.0.5 → qis-3.0.7}/qis/portfolio/strats/quant_strats_delta1.py +0 -0
  130. {qis-3.0.5 → qis-3.0.7}/qis/portfolio/strats/seasonal_strats.py +0 -0
  131. {qis-3.0.5 → qis-3.0.7}/qis/settings.yaml +0 -0
  132. {qis-3.0.5 → qis-3.0.7}/qis/sql_engine.py +0 -0
  133. {qis-3.0.5 → qis-3.0.7}/qis/test_data.py +0 -0
  134. {qis-3.0.5 → qis-3.0.7}/qis/utils/README.md +0 -0
  135. {qis-3.0.5 → qis-3.0.7}/qis/utils/__init__.py +0 -0
  136. {qis-3.0.5 → qis-3.0.7}/qis/utils/dates.py +0 -0
  137. {qis-3.0.5 → qis-3.0.7}/qis/utils/df_agg.py +0 -0
  138. {qis-3.0.5 → qis-3.0.7}/qis/utils/df_cut.py +0 -0
  139. {qis-3.0.5 → qis-3.0.7}/qis/utils/df_freq.py +0 -0
  140. {qis-3.0.5 → qis-3.0.7}/qis/utils/df_groups.py +0 -0
  141. {qis-3.0.5 → qis-3.0.7}/qis/utils/df_melt.py +0 -0
  142. {qis-3.0.5 → qis-3.0.7}/qis/utils/df_ops.py +0 -0
  143. {qis-3.0.5 → qis-3.0.7}/qis/utils/df_str.py +0 -0
  144. {qis-3.0.5 → qis-3.0.7}/qis/utils/df_to_scores.py +0 -0
  145. {qis-3.0.5 → qis-3.0.7}/qis/utils/df_to_weights.py +0 -0
  146. {qis-3.0.5 → qis-3.0.7}/qis/utils/generic.py +0 -0
  147. {qis-3.0.5 → qis-3.0.7}/qis/utils/np_ops.py +0 -0
  148. {qis-3.0.5 → qis-3.0.7}/qis/utils/ols.py +0 -0
  149. {qis-3.0.5 → qis-3.0.7}/qis/utils/sampling.py +0 -0
  150. {qis-3.0.5 → qis-3.0.7}/qis/utils/struct_ops.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: qis
3
- Version: 3.0.5
3
+ Version: 3.0.7
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.0.5"
3
+ version = "3.0.7"
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>"]
@@ -50,10 +50,6 @@ pyarrow = ">=10.0.1"
50
50
  fsspec = ">=2022.11.0"
51
51
  yfinance = ">=0.1.38"
52
52
 
53
- #[build-system]
54
- #requires = ["poetry-core>=1.0.0"]
55
- #
56
-
57
53
  [build-system]
58
54
  requires = ["poetry-core>=1.0.0", "hatchling==1.27.0", "hatch-vcs"]
59
55
  #build-backend = "hatchling.build"
@@ -28,7 +28,7 @@ RA_TABLE_COLUMNS = (PerfStat.START_DATE,
28
28
 
29
29
 
30
30
  def generate_performances(prices: pd.DataFrame,
31
- regime_benchmark_str: str,
31
+ regime_benchmark: str,
32
32
  perf_params: qis.PerfParams = None,
33
33
  perf_columns: List[PerfStat] = RA_TABLE_COLUMNS,
34
34
  heatmap_freq: str = 'YE',
@@ -43,7 +43,7 @@ def generate_performances(prices: pd.DataFrame,
43
43
  fig, ax = plt.subplots(1, 1, figsize=(12, 4), tight_layout=True)
44
44
 
45
45
  qis.plot_ra_perf_table_benchmark(prices=prices,
46
- benchmark=regime_benchmark_str,
46
+ benchmark=regime_benchmark,
47
47
  perf_params=perf_params,
48
48
  perf_columns=perf_columns,
49
49
  title=f"Risk-adjusted performance: {qis.get_time_period_label(prices, date_separator='-')}",
@@ -61,7 +61,7 @@ def generate_performances(prices: pd.DataFrame,
61
61
  with sns.axes_style("darkgrid"):
62
62
  fig, ax = plt.subplots(1, 1, figsize=(8, 6))
63
63
  qis.plot_prices(prices=prices,
64
- regime_benchmark_str=regime_benchmark_str,
64
+ regime_benchmark=regime_benchmark,
65
65
  perf_params=perf_params,
66
66
  title=f"Time series of $1 invested: {qis.get_time_period_label(prices, date_separator='-')}",
67
67
  ax=ax,
@@ -69,7 +69,7 @@ def generate_performances(prices: pd.DataFrame,
69
69
 
70
70
  fig, axs = plt.subplots(2, 1, figsize=(7, 7))
71
71
  qis.plot_prices_with_dd(prices=prices,
72
- regime_benchmark_str=regime_benchmark_str,
72
+ regime_benchmark=regime_benchmark,
73
73
  perf_params=perf_params,
74
74
  title=f"Time series of $1 invested: {qis.get_time_period_label(prices, date_separator='-')}",
75
75
  axs=axs,
@@ -77,7 +77,7 @@ def generate_performances(prices: pd.DataFrame,
77
77
 
78
78
  fig, ax = plt.subplots(1, 1, figsize=(8, 6))
79
79
  qis.plot_scatter_regression(prices=prices,
80
- regime_benchmark_str=regime_benchmark_str,
80
+ regime_benchmark=regime_benchmark,
81
81
  regime_params=qis.BenchmarkReturnsQuantileRegimeSpecs(freq=perf_params.freq_reg),
82
82
  perf_params=perf_params,
83
83
  title=f"Regime Conditional Regression: {qis.get_time_period_label(prices, date_separator='-')}",
@@ -99,30 +99,30 @@ def run_unit_test(unit_test: UnitTests):
99
99
  ust_3m_rate = yf.download('^IRX', start=None, end=None)['Close'].dropna() / 100.0
100
100
 
101
101
  if unit_test == UnitTests.ETF_DATA:
102
- regime_benchmark_str = 'SPY'
103
- tickers = [regime_benchmark_str, 'QQQ', 'EEM', 'TLT', 'IEF', 'LQD', 'HYG', 'SHY', 'GLD']
102
+ regime_benchmark = 'SPY'
103
+ tickers = [regime_benchmark, 'QQQ', 'EEM', 'TLT', 'IEF', 'LQD', 'HYG', 'SHY', 'GLD']
104
104
 
105
105
  elif unit_test == UnitTests.CRYPTO_DATA:
106
- regime_benchmark_str = 'BTC-USD'
107
- tickers = [regime_benchmark_str, 'ETH-USD', 'SOL-USD']
108
- regime_benchmark_str = 'BTC-USD'
109
- tickers = [regime_benchmark_str, 'SPY', 'TLT', 'ETH-USD', 'SOL-USD']
106
+ regime_benchmark = 'BTC-USD'
107
+ tickers = [regime_benchmark, 'ETH-USD', 'SOL-USD']
108
+ regime_benchmark = 'BTC-USD'
109
+ tickers = [regime_benchmark, 'SPY', 'TLT', 'ETH-USD', 'SOL-USD']
110
110
 
111
111
  elif unit_test == UnitTests.TF_ETF:
112
- regime_benchmark_str = 'SPY'
113
- tickers = [regime_benchmark_str, 'DBMF', 'WTMF', 'CTA']
112
+ regime_benchmark = 'SPY'
113
+ tickers = [regime_benchmark, 'DBMF', 'WTMF', 'CTA']
114
114
 
115
115
  elif unit_test == UnitTests.ETFS:
116
- regime_benchmark_str = 'AOR'
117
- tickers = [regime_benchmark_str, 'SPY', 'PEX', 'PSP', 'GSG', 'COMT', 'REET', 'REZ']
116
+ regime_benchmark = 'AOR'
117
+ tickers = [regime_benchmark, 'SPY', 'PEX', 'PSP', 'GSG', 'COMT', 'REET', 'REZ']
118
118
 
119
119
  elif unit_test == UnitTests.COMMODITY_ETFS:
120
- regime_benchmark_str = 'AOR'
121
- tickers = [regime_benchmark_str, 'SPY', 'GLD', 'GSG', 'COMT', 'PDBC']
120
+ regime_benchmark = 'AOR'
121
+ tickers = [regime_benchmark, 'SPY', 'GLD', 'GSG', 'COMT', 'PDBC']
122
122
 
123
123
  elif unit_test == UnitTests.VOL_ETFS:
124
- regime_benchmark_str = 'SPY'
125
- tickers = [regime_benchmark_str, 'SVOL']
124
+ regime_benchmark = 'SPY'
125
+ tickers = [regime_benchmark, 'SVOL']
126
126
 
127
127
  else:
128
128
  raise NotImplementedError
@@ -146,7 +146,7 @@ def run_unit_test(unit_test: UnitTests):
146
146
  prices = time_period.locate(prices)
147
147
 
148
148
  generate_performances(prices=prices,
149
- regime_benchmark_str=regime_benchmark_str,
149
+ regime_benchmark=regime_benchmark,
150
150
  **kwargs)
151
151
 
152
152
  plt.show()
@@ -17,7 +17,7 @@ from qis.portfolio.reports.config import fetch_default_report_kwargs
17
17
  from qis.portfolio.reports.strategy_benchmark_factsheet import (generate_strategy_benchmark_factsheet_plt,
18
18
  generate_strategy_benchmark_active_perf_plt,
19
19
  generate_performance_attribution_report,
20
- weights_tracking_error_report)
20
+ weights_tracking_error_report_by_ac_subac)
21
21
 
22
22
 
23
23
  def fetch_universe_data() -> Tuple[pd.DataFrame, pd.DataFrame, pd.Series]:
@@ -34,7 +34,11 @@ def fetch_universe_data() -> Tuple[pd.DataFrame, pd.DataFrame, pd.Series]:
34
34
  GLD='Gold')
35
35
  tickers = list(universe_data.keys())
36
36
  group_data = pd.Series(universe_data) # for portfolio reporting
37
- prices = yf.download(tickers=tickers, start=None, end=None, ignore_tz=True)['Close'][tickers]
37
+ # prices = yf.download(tickers=tickers, start=None, end=None, ignore_tz=True)['Close'][tickers]
38
+ from qis.test_data import load_etf_data
39
+ prices = load_etf_data()[tickers]
40
+ print(prices)
41
+
38
42
  prices = prices.asfreq('B', method='ffill')
39
43
  benchmark_prices = prices[['SPY', 'TLT']]
40
44
  return prices, benchmark_prices, group_data
@@ -87,6 +91,8 @@ def run_unit_test(unit_test: UnitTests):
87
91
  # time period for portfolio reporting
88
92
  time_period = qis.TimePeriod('31Dec2006', '10Jan2025')
89
93
  prices, benchmark_prices, group_data = fetch_universe_data()
94
+
95
+
90
96
  multi_portfolio_data = generate_volparity_multiportfolio(prices=prices,
91
97
  benchmark_prices=benchmark_prices,
92
98
  group_data=group_data,
@@ -137,8 +143,14 @@ def run_unit_test(unit_test: UnitTests):
137
143
  rebalancing_freq='ME',
138
144
  span=52)
139
145
  multi_portfolio_data.covar_dict = covar_dict
140
- weights_tracking_error_report(multi_portfolio_data=multi_portfolio_data,
141
- time_period=time_period)
146
+ ac_group_data = multi_portfolio_data.portfolio_datas[0].group_data
147
+ asset_tickers = multi_portfolio_data.portfolio_datas[0].weights.columns
148
+ sub_ac_group_data = pd.Series(asset_tickers, index=asset_tickers)
149
+
150
+ weights_tracking_error_report_by_ac_subac(multi_portfolio_data=multi_portfolio_data,
151
+ ac_group_data=ac_group_data,
152
+ sub_ac_group_data=sub_ac_group_data,
153
+ time_period=time_period)
142
154
 
143
155
  plt.show()
144
156
 
@@ -29,7 +29,7 @@ perf_params = qis.PerfParams(freq='ME', freq_reg='W-WED', alpha_an_factor=52.0,
29
29
  with sns.axes_style("darkgrid"):
30
30
  fig1, axs = plt.subplots(2, 1, figsize=(10, 7))
31
31
  qis.plot_prices_with_dd(prices=prices,
32
- regime_benchmark_str=benchmark,
32
+ regime_benchmark=benchmark,
33
33
  x_date_freq='QE',
34
34
  framealpha=0.9,
35
35
  perf_params=perf_params,
@@ -37,7 +37,7 @@ RA_TABLE_COLUMNS = [#PerfStat.START_DATE,
37
37
 
38
38
 
39
39
  def generate_performances(prices: pd.DataFrame,
40
- regime_benchmark_str: str,
40
+ regime_benchmark: str,
41
41
  perf_params: qis.PerfParams = None,
42
42
  heatmap_freq: str = 'YE',
43
43
  **kwargs
@@ -78,7 +78,7 @@ def generate_performances(prices: pd.DataFrame,
78
78
  with sns.axes_style("darkgrid"):
79
79
  fig3, ax = plt.subplots(1, 1, figsize=(8, 6))
80
80
  qis.plot_prices(prices=prices,
81
- regime_benchmark_str=regime_benchmark_str,
81
+ regime_benchmark=regime_benchmark,
82
82
  perf_params=perf_params,
83
83
  title=f"Time series of $1 invested: {qis.get_time_period_label(prices, date_separator='-')}",
84
84
  ax=ax,
@@ -86,7 +86,7 @@ def generate_performances(prices: pd.DataFrame,
86
86
 
87
87
  fig4, axs = plt.subplots(2, 1, figsize=(7, 7))
88
88
  qis.plot_prices_with_dd(prices=prices,
89
- regime_benchmark_str=regime_benchmark_str,
89
+ regime_benchmark=regime_benchmark,
90
90
  perf_params=perf_params,
91
91
  title=f"Time series of $1 invested: {qis.get_time_period_label(prices, date_separator='-')}",
92
92
  axs=axs,
@@ -94,7 +94,7 @@ def generate_performances(prices: pd.DataFrame,
94
94
 
95
95
  fig5, ax = plt.subplots(1, 1, figsize=(8, 6))
96
96
  qis.plot_scatter_regression(prices=prices,
97
- regime_benchmark_str=regime_benchmark_str,
97
+ regime_benchmark=regime_benchmark,
98
98
  regime_params=qis.BenchmarkReturnsQuantileRegimeSpecs(freq=perf_params.freq_reg),
99
99
  perf_params=perf_params,
100
100
  title=f"Regime Conditional Regression: {qis.get_time_period_label(prices, date_separator='-')}",
@@ -134,12 +134,12 @@ def run_unit_test(unit_test: UnitTests):
134
134
  ust_3m_rate = yf.download('^IRX', start=None, end=None)['Close'].dropna() / 100.0
135
135
 
136
136
  if unit_test == UnitTests.ETF_DATA:
137
- regime_benchmark_str = 'SPY'
138
- tickers = [regime_benchmark_str, 'QQQ', 'EEM', 'TLT', 'IEF', 'LQD', 'HYG', 'SHY', 'GLD']
137
+ regime_benchmark = 'SPY'
138
+ tickers = [regime_benchmark, 'QQQ', 'EEM', 'TLT', 'IEF', 'LQD', 'HYG', 'SHY', 'GLD']
139
139
 
140
140
  elif unit_test == UnitTests.CRYPTO_DATA:
141
- regime_benchmark_str = 'BTC-USD'
142
- tickers = [regime_benchmark_str, 'ETH-USD', 'SOL-USD']
141
+ regime_benchmark = 'BTC-USD'
142
+ tickers = [regime_benchmark, 'ETH-USD', 'SOL-USD']
143
143
 
144
144
  else:
145
145
  raise NotImplementedError
@@ -160,7 +160,7 @@ def run_unit_test(unit_test: UnitTests):
160
160
  prices = time_period.locate(prices)
161
161
 
162
162
  generate_performances(prices=prices,
163
- regime_benchmark_str=regime_benchmark_str,
163
+ regime_benchmark=regime_benchmark,
164
164
  **kwargs)
165
165
 
166
166
  plt.show()
@@ -35,7 +35,7 @@ monthly_df = pd.concat([monthly_return, predictor_1, monthly_benchmark_vol_1, vi
35
35
  with sns.axes_style("darkgrid"):
36
36
  fig1, axs = plt.subplots(2, 3, figsize=(18, 9))
37
37
  qis.plot_prices_with_dd(prices=prices[[benchmark_name, strategy_name]],
38
- regime_benchmark_str=benchmark_name,
38
+ regime_benchmark=benchmark_name,
39
39
  perf_stats_labels=[PerfStat.PA_RETURN, PerfStat.VOL, PerfStat.SHARPE_RF0, PerfStat.MAX_DD],
40
40
  title=f"Performances of ShortVix (SPVXSPI Index) and SPX (SPXT Index)",
41
41
  x_date_freq='YE',
@@ -231,17 +231,21 @@ def save_df_to_excel(data: Union[pd.DataFrame, List[pd.DataFrame], Dict[str, pd.
231
231
  if sheet_names is None:
232
232
  sheet_names = [f"Sheet {n+1}" for n, _ in enumerate(data)]
233
233
  for df, name in zip(data, sheet_names):
234
- df = delocalize_df(df)
235
- if transpose:
236
- df = df.T
237
- df.to_excel(excel_writer=excel_writer, sheet_name=name)
234
+ if df is not None:
235
+ df = delocalize_df(df)
236
+ if transpose:
237
+ df = df.T
238
+ df.to_excel(excel_writer=excel_writer, sheet_name=name)
238
239
  elif isinstance(data, dict): # publish with sheet names
239
240
  for key, df in data.items():
240
- df = delocalize_df(df)
241
- if transpose:
242
- df = df.T
243
- df.to_excel(excel_writer=excel_writer, sheet_name=key)
241
+ if df is not None:
242
+ df = delocalize_df(df)
243
+ if transpose:
244
+ df = df.T
245
+ df.to_excel(excel_writer=excel_writer, sheet_name=key)
244
246
  else:
247
+ if data is None:
248
+ raise ValueError(f"None data")
245
249
  if transpose:
246
250
  data = data.T
247
251
  data = delocalize_df(data)
@@ -97,7 +97,7 @@ def plot_returns_corr_matrix_time_series(prices: pd.DataFrame,
97
97
  var_format: str = '{:.0%}',
98
98
  legend_stats: pts.LegendStats = pts.LegendStats.AVG_LAST,
99
99
  trend_line: put.TrendLine = put.TrendLine.AVERAGE,
100
- regime_benchmark_str: str = None,
100
+ regime_benchmark: str = None,
101
101
  regime_params: BenchmarkReturnsQuantileRegimeSpecs = None,
102
102
  perf_params: PerfParams = None,
103
103
  ax: plt.Subplot = None,
@@ -124,16 +124,16 @@ def plot_returns_corr_matrix_time_series(prices: pd.DataFrame,
124
124
  var_format=var_format,
125
125
  ax=ax,
126
126
  **kwargs)
127
- if regime_benchmark_str is not None:
128
- if regime_benchmark_str in prices.columns:
129
- pivot_prices = prices[regime_benchmark_str].reindex(index=corr_pandas.index, method='ffill')
127
+ if regime_benchmark is not None:
128
+ if regime_benchmark in prices.columns:
129
+ pivot_prices = prices[regime_benchmark].reindex(index=corr_pandas.index, method='ffill')
130
130
  else:
131
- raise KeyError(f"{regime_benchmark_str} not in {prices.columns}")
131
+ raise KeyError(f"{regime_benchmark} not in {prices.columns}")
132
132
 
133
- if regime_benchmark_str is not None and regime_params is not None:
133
+ if regime_benchmark is not None and regime_params is not None:
134
134
  add_bnb_regime_shadows(ax=ax,
135
135
  pivot_prices=pivot_prices,
136
- benchmark=regime_benchmark_str,
136
+ benchmark=regime_benchmark,
137
137
  regime_params=regime_params,
138
138
  perf_params=perf_params)
139
139
 
@@ -154,7 +154,7 @@ def run_unit_test(unit_test: UnitTests):
154
154
 
155
155
  elif unit_test == UnitTests.CORR_MATRIX:
156
156
  fig, ax = plt.subplots(1, 1, figsize=(10, 10), constrained_layout=True)
157
- plot_returns_corr_matrix_time_series(prices=prices, regime_benchmark_str='SPY', ax=ax)
157
+ plot_returns_corr_matrix_time_series(prices=prices, regime_benchmark='SPY', ax=ax)
158
158
 
159
159
  elif unit_test == UnitTests.EWMA_CORR:
160
160
  plot_returns_ewm_corr_table(prices=prices.iloc[:, :5])
@@ -64,7 +64,7 @@ def get_performance_labels_for_stats(prices: Union[pd.DataFrame, pd.Series],
64
64
  def plot_prices(prices: Union[pd.DataFrame, pd.Series],
65
65
  perf_stats_labels: List[PerfStat] = (PerfStat.PA_RETURN, PerfStat.VOL, PerfStat.SHARPE_RF0, ),
66
66
  perf_params: PerfParams = None,
67
- regime_benchmark_str: str = None, # to add regimes
67
+ regime_benchmark: str = None, # to add regimes
68
68
  pivot_prices: pd.Series = None,
69
69
  regime_params: BenchmarkReturnsQuantileRegimeSpecs = BenchmarkReturnsQuantileRegimeSpecs(),
70
70
  var_format: str = '{:,.1f}',
@@ -110,11 +110,11 @@ def plot_prices(prices: Union[pd.DataFrame, pd.Series],
110
110
  ax=ax,
111
111
  **kwargs)
112
112
 
113
- if regime_benchmark_str is not None and regime_params is not None:
113
+ if regime_benchmark is not None and regime_params is not None:
114
114
  add_bnb_regime_shadows(ax=ax,
115
115
  data_df=prices,
116
116
  pivot_prices=pivot_prices,
117
- benchmark=regime_benchmark_str,
117
+ benchmark=regime_benchmark,
118
118
  regime_params=regime_params)
119
119
  return fig
120
120
 
@@ -123,7 +123,7 @@ def plot_prices_with_dd(prices: Union[pd.DataFrame, pd.Series],
123
123
  perf_stats_labels: List[PerfStat] = (PerfStat.PA_RETURN, PerfStat.VOL,
124
124
  PerfStat.SHARPE_RF0),
125
125
  perf_params: PerfParams = None,
126
- regime_benchmark_str: str = None, # to add regimes
126
+ regime_benchmark: str = None, # to add regimes
127
127
  pivot_prices: pd.Series = None,
128
128
  regime_params: BenchmarkReturnsQuantileRegimeSpecs = BenchmarkReturnsQuantileRegimeSpecs(),
129
129
  var_format: str = '{:,.1f}',
@@ -174,12 +174,12 @@ def plot_prices_with_dd(prices: Union[pd.DataFrame, pd.Series],
174
174
  if remove_xticklabels_ax1:
175
175
  axs[0].set_xticklabels('')
176
176
 
177
- if (regime_benchmark_str is not None or pivot_prices is not None) and regime_params is not None:
177
+ if (regime_benchmark is not None or pivot_prices is not None) and regime_params is not None:
178
178
  for ax in axs:
179
179
  add_bnb_regime_shadows(ax=ax,
180
180
  data_df=prices,
181
181
  pivot_prices=pivot_prices,
182
- benchmark=regime_benchmark_str,
182
+ benchmark=regime_benchmark,
183
183
  regime_params=regime_params,
184
184
  perf_params=perf_params)
185
185
  return fig
@@ -190,7 +190,7 @@ def plot_prices_with_fundamentals(prices: Union[pd.DataFrame, pd.Series],
190
190
  mcap: Union[pd.DataFrame, pd.Series],
191
191
  perf_stats_labels: List[PerfStat] = (PerfStat.PA_RETURN, PerfStat.VOL, PerfStat.SHARPE_RF0, ),
192
192
  perf_params: PerfParams = None,
193
- regime_benchmark_str: str = None, # to add regimes
193
+ regime_benchmark: str = None, # to add regimes
194
194
  pivot_prices: pd.Series = None,
195
195
  regime_params: BenchmarkReturnsQuantileRegimeSpecs = BenchmarkReturnsQuantileRegimeSpecs(),
196
196
  trend_line: put.TrendLine = put.TrendLine.AVERAGE,
@@ -242,12 +242,12 @@ def plot_prices_with_fundamentals(prices: Union[pd.DataFrame, pd.Series],
242
242
  axs[0].set_xticklabels('')
243
243
  axs[1].set_xticklabels('')
244
244
 
245
- if regime_benchmark_str is not None and regime_params is not None:
245
+ if regime_benchmark is not None and regime_params is not None:
246
246
  for ax in axs:
247
247
  add_bnb_regime_shadows(ax=ax,
248
248
  data_df=prices,
249
249
  pivot_prices=pivot_prices,
250
- benchmark=regime_benchmark_str,
250
+ benchmark=regime_benchmark,
251
251
  regime_params=regime_params,
252
252
  perf_params=perf_params)
253
253
  return fig
@@ -313,7 +313,7 @@ def plot_rolling_perf_stat(prices: Union[pd.Series, pd.DataFrame],
313
313
  roll_freq: str = None,
314
314
  legend_stats: pts.LegendStats = pts.LegendStats.AVG_LAST,
315
315
  title: Optional[str] = None,
316
- regime_benchmark_str: str = None,
316
+ regime_benchmark: str = None,
317
317
  pivot_prices: pd.Series = None,
318
318
  regime_params: BenchmarkReturnsQuantileRegimeSpecs = BenchmarkReturnsQuantileRegimeSpecs(),
319
319
  perf_params: PerfParams = None,
@@ -337,11 +337,11 @@ def plot_rolling_perf_stat(prices: Union[pd.Series, pd.DataFrame],
337
337
  ax=ax,
338
338
  **sop.update_kwargs(kwargs, dict(var_format=rolling_perf_stat.value[1])))
339
339
 
340
- if regime_benchmark_str is not None and regime_params is not None:
340
+ if regime_benchmark is not None and regime_params is not None:
341
341
  add_bnb_regime_shadows(ax=ax,
342
342
  data_df=prices.reindex(index=df.index, method='ffill'),
343
343
  pivot_prices=pivot_prices,
344
- benchmark=regime_benchmark_str,
344
+ benchmark=regime_benchmark,
345
345
  regime_params=regime_params,
346
346
  perf_params=perf_params)
347
347
 
@@ -373,7 +373,7 @@ def run_unit_test(unit_test: UnitTests):
373
373
  elif unit_test == UnitTests.PRICE_WITH_DD:
374
374
  perf_params = PerfParams(freq='ME')
375
375
  plot_prices_with_dd(prices=prices,
376
- regime_benchmark_str=prices.columns[0],
376
+ regime_benchmark=prices.columns[0],
377
377
  perf_params=perf_params)
378
378
 
379
379
  plt.show()
@@ -16,7 +16,7 @@ from qis.perfstats.regime_classifier import BenchmarkReturnsQuantileRegimeSpecs,
16
16
 
17
17
 
18
18
  def plot_scatter_regression(prices: pd.DataFrame,
19
- regime_benchmark_str: str,
19
+ regime_benchmark: str,
20
20
  regime_params: BenchmarkReturnsQuantileRegimeSpecs = BenchmarkReturnsQuantileRegimeSpecs(),
21
21
  drop_benchmark: bool = True,
22
22
  x_var_format: str = '{:.0%}',
@@ -41,7 +41,7 @@ def plot_scatter_regression(prices: pd.DataFrame,
41
41
 
42
42
  regmodel_out_dict = {}
43
43
  estimated_params = cre.estimate_cond_regression(prices=prices,
44
- benchmark=regime_benchmark_str,
44
+ benchmark=regime_benchmark,
45
45
  drop_benchmark=drop_benchmark,
46
46
  regime_params=regime_params,
47
47
  is_print_summary=is_print_summary,
@@ -52,8 +52,8 @@ def plot_scatter_regression(prices: pd.DataFrame,
52
52
  lines = []
53
53
  for (asset, pandas_out), marker, color_ in zip(regmodel_out_dict.items(), markers, colors):
54
54
 
55
- pandas_out = pandas_out.sort_values(regime_benchmark_str) # sort for line plot
56
- sns.scatterplot(x=regime_benchmark_str,
55
+ pandas_out = pandas_out.sort_values(regime_benchmark) # sort for line plot
56
+ sns.scatterplot(x=regime_benchmark,
57
57
  y=asset,
58
58
  hue=pandas_out[BenchmarkReturnsQuantilesRegime.REGIME_COLUMN],
59
59
  data=pandas_out,
@@ -77,7 +77,7 @@ def plot_scatter_regression(prices: pd.DataFrame,
77
77
  line_marker = marker
78
78
  lines.append((asset, {'color': color_, 'linestyle': '-', 'marker': line_marker}))
79
79
 
80
- sns.lineplot(x=regime_benchmark_str,
80
+ sns.lineplot(x=regime_benchmark,
81
81
  y=cre.PREDICTION,
82
82
  hue=pandas_out[BenchmarkReturnsQuantilesRegime.REGIME_COLUMN],
83
83
  data=pandas_out,
@@ -89,7 +89,7 @@ def plot_scatter_regression(prices: pd.DataFrame,
89
89
  if add_last_date:
90
90
  label_x_y = {}
91
91
  for asset, df in regmodel_out_dict.items():
92
- x = df[regime_benchmark_str].iloc[-1]
92
+ x = df[regime_benchmark].iloc[-1]
93
93
  y = df[asset].iloc[-1]
94
94
  label = f"Last {df.index[-1].strftime('%d-%b-%Y')}: x={x_var_format.format(x)}, y={x_var_format.format(y)}"
95
95
  label_x_y[label] = (x, y)
@@ -104,7 +104,7 @@ def plot_scatter_regression(prices: pd.DataFrame,
104
104
  ax.yaxis.set_major_formatter(FuncFormatter(lambda y, _: y_var_format.format(y)))
105
105
 
106
106
  if xlabel is None:
107
- xlabel = f"x={regime_benchmark_str}"
107
+ xlabel = f"x={regime_benchmark}"
108
108
  if ylabel is None:
109
109
  if len(prices.columns) == 2:
110
110
  ylabel = f"y = {asset}"
@@ -133,14 +133,14 @@ def run_unit_test(unit_test: UnitTests):
133
133
 
134
134
  if unit_test == UnitTests.SCATTER_ALL:
135
135
  plot_scatter_regression(prices=prices,
136
- regime_benchmark_str='SPY',
136
+ regime_benchmark='SPY',
137
137
  regime_params=regime_params,
138
138
  add_last_date=True,
139
139
  is_asset_detailed=False)
140
140
 
141
141
  elif unit_test == UnitTests.SCATTER_1:
142
142
  plot_scatter_regression(prices=prices[['SPY', 'TLT']],
143
- regime_benchmark_str='SPY',
143
+ regime_benchmark='SPY',
144
144
  regime_params=regime_params,
145
145
  add_last_date=True,
146
146
  is_asset_detailed=True)
@@ -27,6 +27,7 @@ from qis.portfolio.reports.config import (FactsheetConfig,
27
27
  ReportingFrequency)
28
28
 
29
29
  from qis.portfolio.reports.brinson_attribution import (compute_brinson_attribution_table,
30
+ plot_brinson_totals_table,
30
31
  plot_brinson_attribution_table)
31
32
 
32
33
  from qis.portfolio.reports.multi_assets_factsheet import (MultiAssetsReport, generate_multi_asset_factsheet)