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.
- {qis-3.1.4 → qis-3.1.5}/PKG-INFO +1 -1
- {qis-3.1.4 → qis-3.1.5}/pyproject.toml +1 -1
- {qis-3.1.4 → qis-3.1.5}/qis/examples/factsheets/strategy_benchmark.py +8 -7
- {qis-3.1.4 → qis-3.1.5}/qis/perfstats/config.py +1 -0
- {qis-3.1.4 → qis-3.1.5}/qis/perfstats/perf_stats.py +9 -5
- {qis-3.1.4 → qis-3.1.5}/qis/plots/derived/perf_table.py +3 -4
- {qis-3.1.4 → qis-3.1.5}/qis/portfolio/multi_portfolio_data.py +2 -2
- {qis-3.1.4 → qis-3.1.5}/qis/portfolio/portfolio_data.py +12 -7
- {qis-3.1.4 → qis-3.1.5}/qis/portfolio/reports/config.py +4 -2
- {qis-3.1.4 → qis-3.1.5}/qis/settings.yaml +0 -2
- {qis-3.1.4 → qis-3.1.5}/qis/utils/ols.py +9 -6
- {qis-3.1.4 → qis-3.1.5}/LICENSE.txt +0 -0
- {qis-3.1.4 → qis-3.1.5}/README.md +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/__init__.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/examples/best_returns.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/examples/bond_futures_portfolio.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/examples/bootstrap_analysis.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/examples/boxplot_conditional_returns.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/examples/btc_asset_corr.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/examples/constant_notional.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/examples/constant_weight_portfolios.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/examples/core/perf_bbg_prices.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/examples/core/price_plots.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/examples/core/us_election.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/examples/credit_spreads.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/examples/credit_trackers.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/examples/europe_futures.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/examples/factsheets/multi_assets.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/examples/factsheets/multi_strategy.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/examples/factsheets/pyblogs_reports.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/examples/factsheets/strategy.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/examples/generate_option_rolls.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/examples/interpolation_infrequent_returns.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/examples/leveraged_strategies.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/examples/long_short.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/examples/momentum_indices.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/examples/ohlc_vol_analysis.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/examples/overnight_returns.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/examples/perf_external_assets.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/examples/perp_pricing.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/examples/readme_performances.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/examples/risk_return_frontier.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/examples/rolling_performance.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/examples/seasonality.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/examples/sharpe_vs_sortino.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/examples/simulate_quant_strats.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/examples/test_ewm.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/examples/test_scatter.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/examples/try_pybloqs.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/examples/universe_corrs.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/examples/vix_beta_to_equities_bonds.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/examples/vix_conditional_returns.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/examples/vix_spy_by_year.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/examples/vix_tenor_analysis.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/examples/vol_without_weekends.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/file_utils.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/local_path.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/models/README.md +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/models/__init__.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/models/linear/__init__.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/models/linear/auto_corr.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/models/linear/corr_cov_matrix.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/models/linear/ewm.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/models/linear/ewm_convolution.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/models/linear/ewm_factors.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/models/linear/ewm_winsor_outliers.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/models/linear/pca.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/models/linear/plot_correlations.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/models/linear/ra_returns.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/models/stats/__init__.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/models/stats/bootstrap.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/models/stats/ohlc_vol.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/models/stats/rolling_stats.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/models/stats/test_bootstrap.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/perfstats/README.md +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/perfstats/__init__.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/perfstats/cond_regression.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/perfstats/desc_table.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/perfstats/fx_ops.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/perfstats/regime_classifier.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/perfstats/returns.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/perfstats/timeseries_bfill.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/plots/README.md +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/plots/__init__.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/plots/bars.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/plots/boxplot.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/plots/contour.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/plots/derived/__init__.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/plots/derived/data_timeseries.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/plots/derived/desc_table.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/plots/derived/drawdowns.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/plots/derived/prices.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/plots/derived/regime_class_table.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/plots/derived/regime_data.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/plots/derived/regime_pdf.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/plots/derived/regime_scatter.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/plots/derived/returns_heatmap.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/plots/derived/returns_scatter.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/plots/errorbar.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/plots/heatmap.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/plots/histogram.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/plots/histplot2d.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/plots/lineplot.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/plots/pie.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/plots/qqplot.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/plots/reports/__init__.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/plots/reports/econ_data_single.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/plots/reports/gantt_data_history.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/plots/reports/price_history.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/plots/reports/utils.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/plots/scatter.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/plots/stackplot.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/plots/table.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/plots/time_series.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/plots/utils.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/portfolio/README.md +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/portfolio/__init__.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/portfolio/backtester.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/portfolio/ewm_portfolio_risk.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/portfolio/reports/__init__.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/portfolio/reports/brinson_attribution.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/portfolio/reports/multi_assets_factsheet.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/portfolio/reports/multi_strategy_factseet_pybloqs.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/portfolio/reports/multi_strategy_factsheet.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/portfolio/reports/strategy_benchmark_factsheet.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/portfolio/reports/strategy_benchmark_factsheet_pybloqs.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/portfolio/reports/strategy_factsheet.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/portfolio/reports/strategy_signal_factsheet.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/portfolio/strats/__init__.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/portfolio/strats/quant_strats_delta1.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/portfolio/strats/seasonal_strats.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/sql_engine.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/test_data.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/utils/README.md +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/utils/__init__.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/utils/dates.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/utils/df_agg.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/utils/df_cut.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/utils/df_freq.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/utils/df_groups.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/utils/df_melt.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/utils/df_ops.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/utils/df_str.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/utils/df_to_scores.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/utils/df_to_weights.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/utils/generic.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/utils/np_ops.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/utils/sampling.py +0 -0
- {qis-3.1.4 → qis-3.1.5}/qis/utils/struct_ops.py +0 -0
{qis-3.1.4 → qis-3.1.5}/PKG-INFO
RENAMED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: qis
|
3
|
-
Version: 3.1.
|
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
|
@@ -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
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
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.
|
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
|
-
|
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
|
-
|
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.
|
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.
|
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([
|
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
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
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):
|
@@ -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
|
-
|
115
|
-
|
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
|
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
|