qis 3.0.6__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.
- {qis-3.0.6 → qis-3.0.7}/PKG-INFO +1 -1
- {qis-3.0.6 → qis-3.0.7}/pyproject.toml +1 -1
- {qis-3.0.6 → qis-3.0.7}/qis/examples/core/price_plots.py +20 -20
- {qis-3.0.6 → qis-3.0.7}/qis/examples/factsheets/strategy_benchmark.py +16 -17
- {qis-3.0.6 → qis-3.0.7}/qis/examples/perf_external_assets.py +1 -1
- {qis-3.0.6 → qis-3.0.7}/qis/examples/try_pybloqs.py +9 -9
- {qis-3.0.6 → qis-3.0.7}/qis/examples/vix_conditional_returns.py +1 -1
- {qis-3.0.6 → qis-3.0.7}/qis/models/linear/plot_correlations.py +8 -8
- {qis-3.0.6 → qis-3.0.7}/qis/plots/derived/prices.py +13 -13
- {qis-3.0.6 → qis-3.0.7}/qis/plots/derived/regime_scatter.py +9 -9
- {qis-3.0.6 → qis-3.0.7}/qis/portfolio/__init__.py +1 -0
- {qis-3.0.6 → qis-3.0.7}/qis/portfolio/multi_portfolio_data.py +38 -32
- {qis-3.0.6 → qis-3.0.7}/qis/portfolio/portfolio_data.py +4 -2
- {qis-3.0.6 → qis-3.0.7}/qis/portfolio/reports/brinson_attribution.py +34 -22
- {qis-3.0.6 → qis-3.0.7}/qis/portfolio/reports/multi_assets_factsheet.py +3 -3
- {qis-3.0.6 → qis-3.0.7}/qis/portfolio/reports/multi_strategy_factseet_pybloqs.py +3 -3
- {qis-3.0.6 → qis-3.0.7}/qis/portfolio/reports/multi_strategy_factsheet.py +3 -3
- {qis-3.0.6 → qis-3.0.7}/qis/portfolio/reports/strategy_benchmark_factsheet.py +162 -250
- {qis-3.0.6 → qis-3.0.7}/LICENSE.txt +0 -0
- {qis-3.0.6 → qis-3.0.7}/README.md +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/__init__.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/examples/best_returns.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/examples/bond_futures_portfolio.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/examples/bootstrap_analysis.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/examples/boxplot_conditional_returns.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/examples/btc_asset_corr.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/examples/constant_notional.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/examples/constant_weight_portfolios.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/examples/core/perf_bbg_prices.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/examples/core/us_election.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/examples/credit_spreads.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/examples/credit_trackers.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/examples/europe_futures.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/examples/factsheets/multi_assets.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/examples/factsheets/multi_strategy.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/examples/factsheets/pyblogs_reports.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/examples/factsheets/strategy.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/examples/generate_option_rolls.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/examples/interpolation_infrequent_returns.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/examples/leveraged_strategies.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/examples/long_short.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/examples/momentum_indices.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/examples/oakmark_analysis.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/examples/ohlc_vol_analysis.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/examples/overnight_returns.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/examples/perp_pricing.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/examples/readme_performances.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/examples/risk_return_frontier.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/examples/rolling_performance.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/examples/seasonality.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/examples/sharpe_vs_sortino.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/examples/simulate_quant_strats.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/examples/test_ewm.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/examples/test_scatter.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/examples/universe_corrs.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/examples/vix_beta_to_equities_bonds.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/examples/vix_spy_by_year.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/examples/vix_tenor_analysis.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/examples/vol_without_weekends.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/file_utils.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/local_path.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/models/README.md +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/models/__init__.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/models/linear/__init__.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/models/linear/auto_corr.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/models/linear/corr_cov_matrix.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/models/linear/ewm.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/models/linear/ewm_convolution.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/models/linear/ewm_factors.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/models/linear/ewm_winsor_outliers.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/models/linear/pca.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/models/linear/ra_returns.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/models/stats/__init__.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/models/stats/bootstrap.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/models/stats/ohlc_vol.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/models/stats/rolling_stats.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/models/stats/test_bootstrap.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/perfstats/README.md +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/perfstats/__init__.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/perfstats/cond_regression.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/perfstats/config.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/perfstats/desc_table.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/perfstats/fx_ops.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/perfstats/perf_stats.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/perfstats/regime_classifier.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/perfstats/returns.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/perfstats/timeseries_bfill.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/plots/README.md +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/plots/__init__.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/plots/bars.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/plots/boxplot.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/plots/contour.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/plots/derived/__init__.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/plots/derived/data_timeseries.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/plots/derived/desc_table.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/plots/derived/drawdowns.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/plots/derived/perf_table.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/plots/derived/regime_class_table.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/plots/derived/regime_data.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/plots/derived/regime_pdf.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/plots/derived/returns_heatmap.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/plots/derived/returns_scatter.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/plots/errorbar.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/plots/heatmap.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/plots/histogram.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/plots/histplot2d.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/plots/lineplot.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/plots/pie.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/plots/qqplot.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/plots/reports/__init__.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/plots/reports/econ_data_single.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/plots/reports/gantt_data_history.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/plots/reports/price_history.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/plots/reports/utils.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/plots/scatter.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/plots/stackplot.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/plots/table.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/plots/time_series.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/plots/utils.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/portfolio/README.md +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/portfolio/backtester.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/portfolio/ewm_portfolio_risk.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/portfolio/reports/__init__.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/portfolio/reports/config.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/portfolio/reports/strategy_benchmark_factsheet_pybloqs.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/portfolio/reports/strategy_factsheet.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/portfolio/reports/strategy_signal_factsheet.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/portfolio/strats/__init__.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/portfolio/strats/quant_strats_delta1.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/portfolio/strats/seasonal_strats.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/settings.yaml +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/sql_engine.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/test_data.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/utils/README.md +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/utils/__init__.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/utils/dates.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/utils/df_agg.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/utils/df_cut.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/utils/df_freq.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/utils/df_groups.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/utils/df_melt.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/utils/df_ops.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/utils/df_str.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/utils/df_to_scores.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/utils/df_to_weights.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/utils/generic.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/utils/np_ops.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/utils/ols.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/utils/sampling.py +0 -0
- {qis-3.0.6 → qis-3.0.7}/qis/utils/struct_ops.py +0 -0
{qis-3.0.6 → qis-3.0.7}/PKG-INFO
RENAMED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: qis
|
3
|
-
Version: 3.0.
|
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
|
@@ -28,7 +28,7 @@ RA_TABLE_COLUMNS = (PerfStat.START_DATE,
|
|
28
28
|
|
29
29
|
|
30
30
|
def generate_performances(prices: pd.DataFrame,
|
31
|
-
|
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=
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
103
|
-
tickers = [
|
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
|
-
|
107
|
-
tickers = [
|
108
|
-
|
109
|
-
tickers = [
|
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
|
-
|
113
|
-
tickers = [
|
112
|
+
regime_benchmark = 'SPY'
|
113
|
+
tickers = [regime_benchmark, 'DBMF', 'WTMF', 'CTA']
|
114
114
|
|
115
115
|
elif unit_test == UnitTests.ETFS:
|
116
|
-
|
117
|
-
tickers = [
|
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
|
-
|
121
|
-
tickers = [
|
120
|
+
regime_benchmark = 'AOR'
|
121
|
+
tickers = [regime_benchmark, 'SPY', 'GLD', 'GSG', 'COMT', 'PDBC']
|
122
122
|
|
123
123
|
elif unit_test == UnitTests.VOL_ETFS:
|
124
|
-
|
125
|
-
tickers = [
|
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
|
-
|
149
|
+
regime_benchmark=regime_benchmark,
|
150
150
|
**kwargs)
|
151
151
|
|
152
152
|
plt.show()
|
@@ -17,8 +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
|
-
|
21
|
-
weights_tracking_error_report_cross)
|
20
|
+
weights_tracking_error_report_by_ac_subac)
|
22
21
|
|
23
22
|
|
24
23
|
def fetch_universe_data() -> Tuple[pd.DataFrame, pd.DataFrame, pd.Series]:
|
@@ -35,7 +34,11 @@ def fetch_universe_data() -> Tuple[pd.DataFrame, pd.DataFrame, pd.Series]:
|
|
35
34
|
GLD='Gold')
|
36
35
|
tickers = list(universe_data.keys())
|
37
36
|
group_data = pd.Series(universe_data) # for portfolio reporting
|
38
|
-
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
|
+
|
39
42
|
prices = prices.asfreq('B', method='ffill')
|
40
43
|
benchmark_prices = prices[['SPY', 'TLT']]
|
41
44
|
return prices, benchmark_prices, group_data
|
@@ -80,7 +83,6 @@ class UnitTests(Enum):
|
|
80
83
|
PERFORMANCE_ATTRIBUTION = 2
|
81
84
|
ACTIVE_PERFORMANCE = 3
|
82
85
|
TRACKING_ERROR = 4
|
83
|
-
TRACKING_ERROR_CROSS = 5
|
84
86
|
|
85
87
|
|
86
88
|
@qis.timer
|
@@ -89,6 +91,8 @@ def run_unit_test(unit_test: UnitTests):
|
|
89
91
|
# time period for portfolio reporting
|
90
92
|
time_period = qis.TimePeriod('31Dec2006', '10Jan2025')
|
91
93
|
prices, benchmark_prices, group_data = fetch_universe_data()
|
94
|
+
|
95
|
+
|
92
96
|
multi_portfolio_data = generate_volparity_multiportfolio(prices=prices,
|
93
97
|
benchmark_prices=benchmark_prices,
|
94
98
|
group_data=group_data,
|
@@ -139,26 +143,21 @@ def run_unit_test(unit_test: UnitTests):
|
|
139
143
|
rebalancing_freq='ME',
|
140
144
|
span=52)
|
141
145
|
multi_portfolio_data.covar_dict = covar_dict
|
142
|
-
|
143
|
-
|
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)
|
144
149
|
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
returns_freq='W-WED',
|
150
|
-
rebalancing_freq='ME',
|
151
|
-
span=52)
|
152
|
-
multi_portfolio_data.covar_dict = covar_dict
|
153
|
-
weights_tracking_error_report_cross(multi_portfolio_data=multi_portfolio_data,
|
154
|
-
time_period=time_period)
|
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)
|
155
154
|
|
156
155
|
plt.show()
|
157
156
|
|
158
157
|
|
159
158
|
if __name__ == '__main__':
|
160
159
|
|
161
|
-
unit_test = UnitTests.
|
160
|
+
unit_test = UnitTests.TRACKING_ERROR
|
162
161
|
|
163
162
|
is_run_all_tests = False
|
164
163
|
if is_run_all_tests:
|
@@ -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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
138
|
-
tickers = [
|
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
|
-
|
142
|
-
tickers = [
|
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
|
-
|
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
|
-
|
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',
|
@@ -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
|
-
|
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
|
128
|
-
if
|
129
|
-
pivot_prices = prices[
|
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"{
|
131
|
+
raise KeyError(f"{regime_benchmark} not in {prices.columns}")
|
132
132
|
|
133
|
-
if
|
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=
|
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,
|
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
|
-
|
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
|
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=
|
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
|
-
|
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 (
|
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=
|
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
|
-
|
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
|
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=
|
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
|
-
|
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
|
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=
|
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
|
-
|
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
|
-
|
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=
|
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(
|
56
|
-
sns.scatterplot(x=
|
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=
|
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[
|
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={
|
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
|
-
|
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
|
-
|
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)
|