qis 3.1.4__tar.gz → 3.1.5__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.1.4 → qis-3.1.5}/PKG-INFO +1 -1
  2. {qis-3.1.4 → qis-3.1.5}/pyproject.toml +1 -1
  3. {qis-3.1.4 → qis-3.1.5}/qis/examples/factsheets/strategy_benchmark.py +8 -7
  4. {qis-3.1.4 → qis-3.1.5}/qis/perfstats/config.py +1 -0
  5. {qis-3.1.4 → qis-3.1.5}/qis/perfstats/perf_stats.py +9 -5
  6. {qis-3.1.4 → qis-3.1.5}/qis/plots/derived/perf_table.py +3 -4
  7. {qis-3.1.4 → qis-3.1.5}/qis/portfolio/multi_portfolio_data.py +2 -2
  8. {qis-3.1.4 → qis-3.1.5}/qis/portfolio/portfolio_data.py +12 -7
  9. {qis-3.1.4 → qis-3.1.5}/qis/portfolio/reports/config.py +4 -2
  10. {qis-3.1.4 → qis-3.1.5}/qis/settings.yaml +0 -2
  11. {qis-3.1.4 → qis-3.1.5}/qis/utils/ols.py +9 -6
  12. {qis-3.1.4 → qis-3.1.5}/LICENSE.txt +0 -0
  13. {qis-3.1.4 → qis-3.1.5}/README.md +0 -0
  14. {qis-3.1.4 → qis-3.1.5}/qis/__init__.py +0 -0
  15. {qis-3.1.4 → qis-3.1.5}/qis/examples/best_returns.py +0 -0
  16. {qis-3.1.4 → qis-3.1.5}/qis/examples/bond_futures_portfolio.py +0 -0
  17. {qis-3.1.4 → qis-3.1.5}/qis/examples/bootstrap_analysis.py +0 -0
  18. {qis-3.1.4 → qis-3.1.5}/qis/examples/boxplot_conditional_returns.py +0 -0
  19. {qis-3.1.4 → qis-3.1.5}/qis/examples/btc_asset_corr.py +0 -0
  20. {qis-3.1.4 → qis-3.1.5}/qis/examples/constant_notional.py +0 -0
  21. {qis-3.1.4 → qis-3.1.5}/qis/examples/constant_weight_portfolios.py +0 -0
  22. {qis-3.1.4 → qis-3.1.5}/qis/examples/core/perf_bbg_prices.py +0 -0
  23. {qis-3.1.4 → qis-3.1.5}/qis/examples/core/price_plots.py +0 -0
  24. {qis-3.1.4 → qis-3.1.5}/qis/examples/core/us_election.py +0 -0
  25. {qis-3.1.4 → qis-3.1.5}/qis/examples/credit_spreads.py +0 -0
  26. {qis-3.1.4 → qis-3.1.5}/qis/examples/credit_trackers.py +0 -0
  27. {qis-3.1.4 → qis-3.1.5}/qis/examples/europe_futures.py +0 -0
  28. {qis-3.1.4 → qis-3.1.5}/qis/examples/factsheets/multi_assets.py +0 -0
  29. {qis-3.1.4 → qis-3.1.5}/qis/examples/factsheets/multi_strategy.py +0 -0
  30. {qis-3.1.4 → qis-3.1.5}/qis/examples/factsheets/pyblogs_reports.py +0 -0
  31. {qis-3.1.4 → qis-3.1.5}/qis/examples/factsheets/strategy.py +0 -0
  32. {qis-3.1.4 → qis-3.1.5}/qis/examples/generate_option_rolls.py +0 -0
  33. {qis-3.1.4 → qis-3.1.5}/qis/examples/interpolation_infrequent_returns.py +0 -0
  34. {qis-3.1.4 → qis-3.1.5}/qis/examples/leveraged_strategies.py +0 -0
  35. {qis-3.1.4 → qis-3.1.5}/qis/examples/long_short.py +0 -0
  36. {qis-3.1.4 → qis-3.1.5}/qis/examples/momentum_indices.py +0 -0
  37. {qis-3.1.4 → qis-3.1.5}/qis/examples/ohlc_vol_analysis.py +0 -0
  38. {qis-3.1.4 → qis-3.1.5}/qis/examples/overnight_returns.py +0 -0
  39. {qis-3.1.4 → qis-3.1.5}/qis/examples/perf_external_assets.py +0 -0
  40. {qis-3.1.4 → qis-3.1.5}/qis/examples/perp_pricing.py +0 -0
  41. {qis-3.1.4 → qis-3.1.5}/qis/examples/readme_performances.py +0 -0
  42. {qis-3.1.4 → qis-3.1.5}/qis/examples/risk_return_frontier.py +0 -0
  43. {qis-3.1.4 → qis-3.1.5}/qis/examples/rolling_performance.py +0 -0
  44. {qis-3.1.4 → qis-3.1.5}/qis/examples/seasonality.py +0 -0
  45. {qis-3.1.4 → qis-3.1.5}/qis/examples/sharpe_vs_sortino.py +0 -0
  46. {qis-3.1.4 → qis-3.1.5}/qis/examples/simulate_quant_strats.py +0 -0
  47. {qis-3.1.4 → qis-3.1.5}/qis/examples/test_ewm.py +0 -0
  48. {qis-3.1.4 → qis-3.1.5}/qis/examples/test_scatter.py +0 -0
  49. {qis-3.1.4 → qis-3.1.5}/qis/examples/try_pybloqs.py +0 -0
  50. {qis-3.1.4 → qis-3.1.5}/qis/examples/universe_corrs.py +0 -0
  51. {qis-3.1.4 → qis-3.1.5}/qis/examples/vix_beta_to_equities_bonds.py +0 -0
  52. {qis-3.1.4 → qis-3.1.5}/qis/examples/vix_conditional_returns.py +0 -0
  53. {qis-3.1.4 → qis-3.1.5}/qis/examples/vix_spy_by_year.py +0 -0
  54. {qis-3.1.4 → qis-3.1.5}/qis/examples/vix_tenor_analysis.py +0 -0
  55. {qis-3.1.4 → qis-3.1.5}/qis/examples/vol_without_weekends.py +0 -0
  56. {qis-3.1.4 → qis-3.1.5}/qis/file_utils.py +0 -0
  57. {qis-3.1.4 → qis-3.1.5}/qis/local_path.py +0 -0
  58. {qis-3.1.4 → qis-3.1.5}/qis/models/README.md +0 -0
  59. {qis-3.1.4 → qis-3.1.5}/qis/models/__init__.py +0 -0
  60. {qis-3.1.4 → qis-3.1.5}/qis/models/linear/__init__.py +0 -0
  61. {qis-3.1.4 → qis-3.1.5}/qis/models/linear/auto_corr.py +0 -0
  62. {qis-3.1.4 → qis-3.1.5}/qis/models/linear/corr_cov_matrix.py +0 -0
  63. {qis-3.1.4 → qis-3.1.5}/qis/models/linear/ewm.py +0 -0
  64. {qis-3.1.4 → qis-3.1.5}/qis/models/linear/ewm_convolution.py +0 -0
  65. {qis-3.1.4 → qis-3.1.5}/qis/models/linear/ewm_factors.py +0 -0
  66. {qis-3.1.4 → qis-3.1.5}/qis/models/linear/ewm_winsor_outliers.py +0 -0
  67. {qis-3.1.4 → qis-3.1.5}/qis/models/linear/pca.py +0 -0
  68. {qis-3.1.4 → qis-3.1.5}/qis/models/linear/plot_correlations.py +0 -0
  69. {qis-3.1.4 → qis-3.1.5}/qis/models/linear/ra_returns.py +0 -0
  70. {qis-3.1.4 → qis-3.1.5}/qis/models/stats/__init__.py +0 -0
  71. {qis-3.1.4 → qis-3.1.5}/qis/models/stats/bootstrap.py +0 -0
  72. {qis-3.1.4 → qis-3.1.5}/qis/models/stats/ohlc_vol.py +0 -0
  73. {qis-3.1.4 → qis-3.1.5}/qis/models/stats/rolling_stats.py +0 -0
  74. {qis-3.1.4 → qis-3.1.5}/qis/models/stats/test_bootstrap.py +0 -0
  75. {qis-3.1.4 → qis-3.1.5}/qis/perfstats/README.md +0 -0
  76. {qis-3.1.4 → qis-3.1.5}/qis/perfstats/__init__.py +0 -0
  77. {qis-3.1.4 → qis-3.1.5}/qis/perfstats/cond_regression.py +0 -0
  78. {qis-3.1.4 → qis-3.1.5}/qis/perfstats/desc_table.py +0 -0
  79. {qis-3.1.4 → qis-3.1.5}/qis/perfstats/fx_ops.py +0 -0
  80. {qis-3.1.4 → qis-3.1.5}/qis/perfstats/regime_classifier.py +0 -0
  81. {qis-3.1.4 → qis-3.1.5}/qis/perfstats/returns.py +0 -0
  82. {qis-3.1.4 → qis-3.1.5}/qis/perfstats/timeseries_bfill.py +0 -0
  83. {qis-3.1.4 → qis-3.1.5}/qis/plots/README.md +0 -0
  84. {qis-3.1.4 → qis-3.1.5}/qis/plots/__init__.py +0 -0
  85. {qis-3.1.4 → qis-3.1.5}/qis/plots/bars.py +0 -0
  86. {qis-3.1.4 → qis-3.1.5}/qis/plots/boxplot.py +0 -0
  87. {qis-3.1.4 → qis-3.1.5}/qis/plots/contour.py +0 -0
  88. {qis-3.1.4 → qis-3.1.5}/qis/plots/derived/__init__.py +0 -0
  89. {qis-3.1.4 → qis-3.1.5}/qis/plots/derived/data_timeseries.py +0 -0
  90. {qis-3.1.4 → qis-3.1.5}/qis/plots/derived/desc_table.py +0 -0
  91. {qis-3.1.4 → qis-3.1.5}/qis/plots/derived/drawdowns.py +0 -0
  92. {qis-3.1.4 → qis-3.1.5}/qis/plots/derived/prices.py +0 -0
  93. {qis-3.1.4 → qis-3.1.5}/qis/plots/derived/regime_class_table.py +0 -0
  94. {qis-3.1.4 → qis-3.1.5}/qis/plots/derived/regime_data.py +0 -0
  95. {qis-3.1.4 → qis-3.1.5}/qis/plots/derived/regime_pdf.py +0 -0
  96. {qis-3.1.4 → qis-3.1.5}/qis/plots/derived/regime_scatter.py +0 -0
  97. {qis-3.1.4 → qis-3.1.5}/qis/plots/derived/returns_heatmap.py +0 -0
  98. {qis-3.1.4 → qis-3.1.5}/qis/plots/derived/returns_scatter.py +0 -0
  99. {qis-3.1.4 → qis-3.1.5}/qis/plots/errorbar.py +0 -0
  100. {qis-3.1.4 → qis-3.1.5}/qis/plots/heatmap.py +0 -0
  101. {qis-3.1.4 → qis-3.1.5}/qis/plots/histogram.py +0 -0
  102. {qis-3.1.4 → qis-3.1.5}/qis/plots/histplot2d.py +0 -0
  103. {qis-3.1.4 → qis-3.1.5}/qis/plots/lineplot.py +0 -0
  104. {qis-3.1.4 → qis-3.1.5}/qis/plots/pie.py +0 -0
  105. {qis-3.1.4 → qis-3.1.5}/qis/plots/qqplot.py +0 -0
  106. {qis-3.1.4 → qis-3.1.5}/qis/plots/reports/__init__.py +0 -0
  107. {qis-3.1.4 → qis-3.1.5}/qis/plots/reports/econ_data_single.py +0 -0
  108. {qis-3.1.4 → qis-3.1.5}/qis/plots/reports/gantt_data_history.py +0 -0
  109. {qis-3.1.4 → qis-3.1.5}/qis/plots/reports/price_history.py +0 -0
  110. {qis-3.1.4 → qis-3.1.5}/qis/plots/reports/utils.py +0 -0
  111. {qis-3.1.4 → qis-3.1.5}/qis/plots/scatter.py +0 -0
  112. {qis-3.1.4 → qis-3.1.5}/qis/plots/stackplot.py +0 -0
  113. {qis-3.1.4 → qis-3.1.5}/qis/plots/table.py +0 -0
  114. {qis-3.1.4 → qis-3.1.5}/qis/plots/time_series.py +0 -0
  115. {qis-3.1.4 → qis-3.1.5}/qis/plots/utils.py +0 -0
  116. {qis-3.1.4 → qis-3.1.5}/qis/portfolio/README.md +0 -0
  117. {qis-3.1.4 → qis-3.1.5}/qis/portfolio/__init__.py +0 -0
  118. {qis-3.1.4 → qis-3.1.5}/qis/portfolio/backtester.py +0 -0
  119. {qis-3.1.4 → qis-3.1.5}/qis/portfolio/ewm_portfolio_risk.py +0 -0
  120. {qis-3.1.4 → qis-3.1.5}/qis/portfolio/reports/__init__.py +0 -0
  121. {qis-3.1.4 → qis-3.1.5}/qis/portfolio/reports/brinson_attribution.py +0 -0
  122. {qis-3.1.4 → qis-3.1.5}/qis/portfolio/reports/multi_assets_factsheet.py +0 -0
  123. {qis-3.1.4 → qis-3.1.5}/qis/portfolio/reports/multi_strategy_factseet_pybloqs.py +0 -0
  124. {qis-3.1.4 → qis-3.1.5}/qis/portfolio/reports/multi_strategy_factsheet.py +0 -0
  125. {qis-3.1.4 → qis-3.1.5}/qis/portfolio/reports/strategy_benchmark_factsheet.py +0 -0
  126. {qis-3.1.4 → qis-3.1.5}/qis/portfolio/reports/strategy_benchmark_factsheet_pybloqs.py +0 -0
  127. {qis-3.1.4 → qis-3.1.5}/qis/portfolio/reports/strategy_factsheet.py +0 -0
  128. {qis-3.1.4 → qis-3.1.5}/qis/portfolio/reports/strategy_signal_factsheet.py +0 -0
  129. {qis-3.1.4 → qis-3.1.5}/qis/portfolio/strats/__init__.py +0 -0
  130. {qis-3.1.4 → qis-3.1.5}/qis/portfolio/strats/quant_strats_delta1.py +0 -0
  131. {qis-3.1.4 → qis-3.1.5}/qis/portfolio/strats/seasonal_strats.py +0 -0
  132. {qis-3.1.4 → qis-3.1.5}/qis/sql_engine.py +0 -0
  133. {qis-3.1.4 → qis-3.1.5}/qis/test_data.py +0 -0
  134. {qis-3.1.4 → qis-3.1.5}/qis/utils/README.md +0 -0
  135. {qis-3.1.4 → qis-3.1.5}/qis/utils/__init__.py +0 -0
  136. {qis-3.1.4 → qis-3.1.5}/qis/utils/dates.py +0 -0
  137. {qis-3.1.4 → qis-3.1.5}/qis/utils/df_agg.py +0 -0
  138. {qis-3.1.4 → qis-3.1.5}/qis/utils/df_cut.py +0 -0
  139. {qis-3.1.4 → qis-3.1.5}/qis/utils/df_freq.py +0 -0
  140. {qis-3.1.4 → qis-3.1.5}/qis/utils/df_groups.py +0 -0
  141. {qis-3.1.4 → qis-3.1.5}/qis/utils/df_melt.py +0 -0
  142. {qis-3.1.4 → qis-3.1.5}/qis/utils/df_ops.py +0 -0
  143. {qis-3.1.4 → qis-3.1.5}/qis/utils/df_str.py +0 -0
  144. {qis-3.1.4 → qis-3.1.5}/qis/utils/df_to_scores.py +0 -0
  145. {qis-3.1.4 → qis-3.1.5}/qis/utils/df_to_weights.py +0 -0
  146. {qis-3.1.4 → qis-3.1.5}/qis/utils/generic.py +0 -0
  147. {qis-3.1.4 → qis-3.1.5}/qis/utils/np_ops.py +0 -0
  148. {qis-3.1.4 → qis-3.1.5}/qis/utils/sampling.py +0 -0
  149. {qis-3.1.4 → qis-3.1.5}/qis/utils/struct_ops.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: qis
3
- Version: 3.1.4
3
+ Version: 3.1.5
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.1.4"
3
+ version = "3.1.5"
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>"]
@@ -18,9 +18,10 @@ from qis.portfolio.reports.strategy_benchmark_factsheet import (generate_strateg
18
18
  generate_strategy_benchmark_active_perf_plt,
19
19
  generate_performance_attribution_report,
20
20
  weights_tracking_error_report_by_ac_subac)
21
+ from qis.test_data import load_etf_data
21
22
 
22
23
 
23
- def fetch_universe_data() -> Tuple[pd.DataFrame, pd.DataFrame, pd.Series]:
24
+ def fetch_universe_data(live_prices: bool = True) -> Tuple[pd.DataFrame, pd.DataFrame, pd.Series]:
24
25
  """
25
26
  define custom universe with asset class grouping
26
27
  """
@@ -34,10 +35,11 @@ def fetch_universe_data() -> Tuple[pd.DataFrame, pd.DataFrame, pd.Series]:
34
35
  GLD='Gold')
35
36
  tickers = list(universe_data.keys())
36
37
  group_data = pd.Series(universe_data) # for portfolio reporting
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)
38
+ if live_prices:
39
+ prices = yf.download(tickers=tickers, start=None, end=None, ignore_tz=True)['Close'][tickers]
40
+ else:
41
+ prices = load_etf_data()[tickers]
42
+ print(prices)
41
43
 
42
44
  prices = prices.asfreq('B', method='ffill')
43
45
  benchmark_prices = prices[['SPY', 'TLT']]
@@ -92,7 +94,6 @@ def run_unit_test(unit_test: UnitTests):
92
94
  time_period = qis.TimePeriod('31Dec2006', '10Jan2025')
93
95
  prices, benchmark_prices, group_data = fetch_universe_data()
94
96
 
95
-
96
97
  multi_portfolio_data = generate_volparity_multiportfolio(prices=prices,
97
98
  benchmark_prices=benchmark_prices,
98
99
  group_data=group_data,
@@ -157,7 +158,7 @@ def run_unit_test(unit_test: UnitTests):
157
158
 
158
159
  if __name__ == '__main__':
159
160
 
160
- unit_test = UnitTests.TRACKING_ERROR
161
+ unit_test = UnitTests.STRATEGY_BENCHMARK_PLT
161
162
 
162
163
  is_run_all_tests = False
163
164
  if is_run_all_tests:
@@ -114,6 +114,7 @@ class PerfStat(ColVar, Enum):
114
114
  ALPHA_AN = ColVar(name='An Alpha', short_n='Alpha', value_type=ValueType.PERCT)
115
115
  BETA = ColVar(name='Beta', short_n='Beta', value_type=ValueType.FLOAT2)
116
116
  R2 = ColVar(name='R2', short_n='R2', value_type=ValueType.PERCT0)
117
+ ALPHA_PVALUE = ColVar(name='p-Alpha', short_n='p-Alpha', value_type=ValueType.FLOAT2)
117
118
 
118
119
 
119
120
  """
@@ -101,7 +101,8 @@ BENCHMARK_TABLE_COLUMNS = (PerfStat.PA_RETURN,
101
101
  PerfStat.SKEWNESS,
102
102
  PerfStat.ALPHA_AN,
103
103
  PerfStat.BETA,
104
- PerfStat.R2)
104
+ PerfStat.R2,
105
+ PerfStat.ALPHA_PVALUE)
105
106
 
106
107
  BENCHMARK_TABLE_COLUMNS2 = (PerfStat.TOTAL_RETURN,
107
108
  PerfStat.PA_RETURN,
@@ -271,14 +272,14 @@ def compute_ra_perf_table_with_benchmark(prices: pd.DataFrame,
271
272
  if perf_params.rates_data is not None:
272
273
  returns = ret.compute_excess_returns(returns=returns, rates_data=perf_params.rates_data)
273
274
 
274
- alphas, betas, r2 = {}, {}, {}
275
+ alphas, betas, r2, alpha_pvalue = {}, {}, {}, {}
275
276
  for column in returns.columns:
276
277
  joint_data = returns[[benchmark, column]].dropna()
277
278
  if joint_data.empty or len(joint_data.index) < 2:
278
- alphas[column], betas[column], r2[column] = np.nan, np.nan, np.nan
279
+ alphas[column], betas[column], r2[column], alpha_pvalue[column] = np.nan, np.nan, np.nan, np.nan
279
280
  else:
280
- alphas[column], betas[column], r2[column] = ols.estimate_ols_alpha_beta(x=joint_data.iloc[:, 0],
281
- y=joint_data.iloc[:, 1])
281
+ alphas[column], betas[column], r2[column], alpha_pvalue[column] = ols.estimate_ols_alpha_beta(x=joint_data.iloc[:, 0],
282
+ y=joint_data.iloc[:, 1])
282
283
 
283
284
  # get vol and compute risk adjusted performance
284
285
  alpha_an_factor = alpha_an_factor or perf_params.alpha_an_factor
@@ -286,9 +287,12 @@ def compute_ra_perf_table_with_benchmark(prices: pd.DataFrame,
286
287
  ra_perf_table[PerfStat.ALPHA_AN.to_str()] = alpha_an_factor * pd.Series(alphas)
287
288
  ra_perf_table[PerfStat.BETA.to_str()] = pd.Series(betas)
288
289
  ra_perf_table[PerfStat.R2.to_str()] = pd.Series(r2)
290
+ ra_perf_table[PerfStat.ALPHA_PVALUE.to_str()] = pd.Series(alpha_pvalue)
289
291
 
290
292
  if drop_benchmark:
291
293
  ra_perf_table = ra_perf_table.drop([benchmark], axis=0)
294
+ else: # set p-value of benchmark alpha to 1
295
+ ra_perf_table.loc[benchmark, PerfStat.ALPHA_PVALUE.to_str()] = 1.0
292
296
  return ra_perf_table
293
297
 
294
298
 
@@ -152,7 +152,6 @@ def plot_ra_perf_table_benchmark(prices: pd.DataFrame,
152
152
  df_to_add = df_to_add.fillna('')
153
153
  ra_perf_table = pd.concat([ra_perf_table, df_to_add], axis=1)
154
154
 
155
-
156
155
  fig = ptb.plot_df_table(df=ra_perf_table,
157
156
  transpose=transpose,
158
157
  special_columns_colors=special_columns_colors,
@@ -415,7 +414,7 @@ def plot_best_worst_returns(price: pd.Series,
415
414
  class UnitTests(Enum):
416
415
  PLOT_RA_PERF_TABLE = 1
417
416
  PLOT_RA_PERF_SCATTER = 2
418
- PLOT_RA_PERF_TABLE_BENCHMARKS = 3
417
+ PLOT_RA_PERF_TABLE_BENCHMARK = 3
419
418
  PLOT_DESC_FREQ_TABLE = 4
420
419
  PLOT_SHARPE_BARPLOT = 5
421
420
  PLOT_SHARPE_BY_DATES = 6
@@ -444,7 +443,7 @@ def run_unit_test(unit_test: UnitTests):
444
443
  plot_ra_perf_scatter(prices=prices,
445
444
  perf_params=perf_params)
446
445
 
447
- elif unit_test == UnitTests.PLOT_RA_PERF_TABLE_BENCHMARKS:
446
+ elif unit_test == UnitTests.PLOT_RA_PERF_TABLE_BENCHMARK:
448
447
  perf_params = PerfParams(freq='ME')
449
448
  plot_ra_perf_table_benchmark(prices=prices,
450
449
  benchmark='SPY',
@@ -483,7 +482,7 @@ def run_unit_test(unit_test: UnitTests):
483
482
 
484
483
  if __name__ == '__main__':
485
484
 
486
- unit_test = UnitTests.PLOT_TOP_BOTTOM_RETURNS
485
+ unit_test = UnitTests.PLOT_RA_PERF_TABLE_BENCHMARK
487
486
 
488
487
  is_run_all_tests = False
489
488
  if is_run_all_tests:
@@ -497,7 +497,7 @@ class MultiPortfolioData:
497
497
  navs_ = portfolio.get_portfolio_nav(time_period=time_period) # navs include costs while group navs are cost free
498
498
  ac_prices_ = portfolio.get_group_navs(time_period=time_period, is_add_group_total=False)
499
499
  strategy_prices.append(navs_)
500
- if add_ac:
500
+ if add_ac and ac_prices_ is not None:
501
501
  ac_prices_.columns = [f"{portfolio_name}-{x}" for x in ac_prices_.columns]
502
502
  ac_prices.append(ac_prices_)
503
503
  rows_edge_lines.append(sum(rows_edge_lines)+len(ac_prices_.columns))
@@ -505,7 +505,7 @@ class MultiPortfolioData:
505
505
 
506
506
  benchmark_price = benchmark_price.reindex(index=strategy_prices.index, method='ffill')
507
507
  if benchmark_price.name not in strategy_prices.columns:
508
- prices = pd.concat([benchmark_price, strategy_prices], axis=1)
508
+ prices = pd.concat([strategy_prices, benchmark_price], axis=1)
509
509
  else:
510
510
  prices = strategy_prices
511
511
  if add_ac: # otherwise tables look too bad
@@ -215,7 +215,7 @@ class PortfolioData:
215
215
  time_period: TimePeriod = None,
216
216
  constant_trade_level: bool = False,
217
217
  is_add_group_total: bool = False
218
- ) -> pd.DataFrame:
218
+ ) -> Optional[pd.DataFrame]:
219
219
  """
220
220
  group total will exclude transaction costs so it is not equal to portfolio nav
221
221
  """
@@ -223,12 +223,17 @@ class PortfolioData:
223
223
  total_column = str(self.nav.name)
224
224
  else:
225
225
  total_column = None
226
- grouped_pnl = dfg.agg_df_by_groups_ax1(df=self.get_instruments_pnl(time_period=time_period),
227
- group_data=self.group_data,
228
- agg_func=np.nansum,
229
- total_column=total_column,
230
- group_order=self.group_order)
231
- group_navs = ret.returns_to_nav(returns=grouped_pnl, constant_trade_level=constant_trade_level)
226
+ df = self.get_instruments_pnl(time_period=time_period)
227
+ if df.empty:
228
+ print(f"instruments p&l is not available for time_period={time_period.to_str()}")
229
+ group_navs = None
230
+ else:
231
+ grouped_pnl = dfg.agg_df_by_groups_ax1(df=df,
232
+ group_data=self.group_data,
233
+ agg_func=np.nansum,
234
+ total_column=total_column,
235
+ group_order=self.group_order)
236
+ group_navs = ret.returns_to_nav(returns=grouped_pnl, constant_trade_level=constant_trade_level)
232
237
  return group_navs
233
238
 
234
239
  def get_total_nav_with_group_navs(self, time_period: TimePeriod = None) -> pd.DataFrame:
@@ -21,7 +21,8 @@ PERF_COLUMNS_RF0 = (PerfStat.TOTAL_RETURN,
21
21
  PerfStat.SKEWNESS,
22
22
  PerfStat.ALPHA_AN,
23
23
  PerfStat.BETA,
24
- PerfStat.R2)
24
+ PerfStat.R2,
25
+ PerfStat.ALPHA_PVALUE)
25
26
 
26
27
 
27
28
  PERF_COLUMNS = (PerfStat.TOTAL_RETURN,
@@ -34,7 +35,8 @@ PERF_COLUMNS = (PerfStat.TOTAL_RETURN,
34
35
  PerfStat.SKEWNESS,
35
36
  PerfStat.ALPHA_AN,
36
37
  PerfStat.BETA,
37
- PerfStat.R2)
38
+ PerfStat.R2,
39
+ PerfStat.ALPHA_PVALUE)
38
40
 
39
41
 
40
42
  class ReportingFrequency(Enum):
@@ -3,7 +3,6 @@
3
3
  # remove from git tracking:
4
4
  # git rm -r --cached setting.yaml
5
5
 
6
-
7
6
  RESOURCE_PATH:
8
7
  "..\\"
9
8
 
@@ -18,4 +17,3 @@ OUTPUT_PATH:
18
17
 
19
18
  AWS_POSTGRES:
20
19
  ""
21
-
@@ -71,27 +71,30 @@ def estimate_ols_alpha_beta(x: Union[np.ndarray, pd.Series, pd.DataFrame],
71
71
  y: Union[np.ndarray, pd.Series],
72
72
  order: int = 1,
73
73
  fit_intercept: bool = True
74
- ) -> Tuple[float, float, float]:
74
+ ) -> Tuple[float, float, float, float]:
75
75
  try:
76
76
  reg_model = fit_ols(x=x, y=y, order=order, fit_intercept=fit_intercept)
77
77
  except:
78
78
  warnings.warn(f"problem with x={x}, y={y}")
79
- return 0.0, 0.0, 0.0
79
+ return 0.0, 0.0, 0.0, 0.0
80
80
  if fit_intercept:
81
81
  if isinstance(reg_model.params, pd.Series):
82
82
  alpha = reg_model.params.iloc[0]
83
83
  beta = reg_model.params.iloc[1]
84
+ alpha_pvalue = reg_model.pvalues.iloc[0]
84
85
  else:
85
86
  alpha = reg_model.params[0]
86
87
  beta = reg_model.params[1]
88
+ alpha_pvalue = reg_model.pvalues[0]
87
89
  else:
88
90
  alpha = 0.0
91
+ alpha_pvalue = 0.0
89
92
  if isinstance(reg_model.params, pd.Series):
90
93
  beta = reg_model.params.iloc[0]
91
94
  else:
92
95
  beta = reg_model.params[0]
93
96
  r2 = reg_model.rsquared
94
- return alpha, beta, r2
97
+ return alpha, beta, r2, alpha_pvalue
95
98
 
96
99
 
97
100
  def estimate_alpha_beta_paired_dfs(x: pd.DataFrame,
@@ -110,9 +113,9 @@ def estimate_alpha_beta_paired_dfs(x: pd.DataFrame,
110
113
  ncols = len(x.columns)
111
114
  alphas, betas = np.zeros(ncols), np.zeros(ncols)
112
115
  for idx in np.arange(ncols):
113
- alphas[idx], betas[idx], _ = estimate_ols_alpha_beta(x=x_np[:, idx],
114
- y=y_np[:, idx],
115
- fit_intercept=fit_intercept)
116
+ alphas[idx], betas[idx], _, _ = estimate_ols_alpha_beta(x=x_np[:, idx],
117
+ y=y_np[:, idx],
118
+ fit_intercept=fit_intercept)
116
119
  alphas = pd.Series(alphas, index=x.columns)
117
120
  betas = pd.Series(betas, index=x.columns)
118
121
  return alphas, betas
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