sf-quant 0.2.2__tar.gz → 0.2.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {sf_quant-0.2.2 → sf_quant-0.2.4}/PKG-INFO +1 -1
- {sf_quant-0.2.2 → sf_quant-0.2.4}/pyproject.toml +1 -1
- {sf_quant-0.2.2 → sf_quant-0.2.4}/src/sf_quant/backtester/dynamic_parallel.py +28 -22
- {sf_quant-0.2.2 → sf_quant-0.2.4}/src/sf_quant/optimizer/optimizers.py +16 -31
- {sf_quant-0.2.2 → sf_quant-0.2.4}/uv.lock +1 -1
- {sf_quant-0.2.2 → sf_quant-0.2.4}/.github/workflows/publish.yml +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/.gitignore +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/.readthedocs.yaml +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/README.md +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/Makefile +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/conf.py +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/index.rst +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/make.bat +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/backtester/sf_quant.backtester.backtest_parallel.rst +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/backtester/sf_quant.backtester.backtest_sequential.rst +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/backtester/sf_quant.backtester.dynamic_backtest_parallel.rst +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/backtester/sf_quant.backtester.dynamic_parallel.rst +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/backtester.rst +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/data/sf_quant.data.construct_covariance_matrix.rst +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/data/sf_quant.data.get_assets_columns.rst +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/data/sf_quant.data.get_crsp_daily_columns.rst +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/data/sf_quant.data.get_crsp_monthly_columns.rst +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/data/sf_quant.data.get_crsp_v2_daily_columns.rst +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/data/sf_quant.data.get_crsp_v2_monthly_columns.rst +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/data/sf_quant.data.get_exposures_columns.rst +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/data/sf_quant.data.get_factor_names.rst +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/data/sf_quant.data.get_factors_columns.rst +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/data/sf_quant.data.get_fama_french_columns.rst +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/data/sf_quant.data.load_assets.rst +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/data/sf_quant.data.load_assets_by_date.rst +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/data/sf_quant.data.load_benchmark.rst +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/data/sf_quant.data.load_benchmark_returns.rst +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/data/sf_quant.data.load_crsp_daily.rst +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/data/sf_quant.data.load_crsp_monthly.rst +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/data/sf_quant.data.load_crsp_v2_daily.rst +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/data/sf_quant.data.load_crsp_v2_monthly.rst +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/data/sf_quant.data.load_exposures.rst +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/data/sf_quant.data.load_factors.rst +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/data/sf_quant.data.load_fama_french.rst +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/data.rst +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/optimizer/sf_quant.optimizer.FullInvestment.rst +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/optimizer/sf_quant.optimizer.LongOnly.rst +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/optimizer/sf_quant.optimizer.NoBuyingOnMargin.rst +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/optimizer/sf_quant.optimizer.UnitBeta.rst +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/optimizer/sf_quant.optimizer.ZeroBeta.rst +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/optimizer/sf_quant.optimizer.ZeroInvestment.rst +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/optimizer/sf_quant.optimizer.dynamic_mve_optimizer.rst +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/optimizer/sf_quant.optimizer.mve_optimizer.rst +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/optimizer.rst +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/performance/sf_quant.performance.generate_alpha_ics.rst +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/performance/sf_quant.performance.generate_drawdown_chart.rst +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/performance/sf_quant.performance.generate_drawdown_from_returns.rst +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/performance/sf_quant.performance.generate_drawdown_summary_table.rst +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/performance/sf_quant.performance.generate_ic_chart.rst +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/performance/sf_quant.performance.generate_leverage_chart.rst +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/performance/sf_quant.performance.generate_leverage_from_weights.rst +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/performance/sf_quant.performance.generate_leverage_summary_table.rst +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/performance/sf_quant.performance.generate_multi_returns_chart.rst +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/performance/sf_quant.performance.generate_multi_returns_from_weights.rst +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/performance/sf_quant.performance.generate_multi_returns_summary_table.rst +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/performance/sf_quant.performance.generate_returns_chart.rst +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/performance/sf_quant.performance.generate_returns_from_weights.rst +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/performance/sf_quant.performance.generate_returns_summary_table.rst +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/performance/sf_quant.performance.get_turnover_stats.rst +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/performance/sf_quant.performance.plot_turnover.rst +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/performance.rst +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/research/sf_quant.research.beta_scale_ports.rst +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/research/sf_quant.research.generate_quantile_ports.rst +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/research/sf_quant.research.get_signal_distribution.rst +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/research/sf_quant.research.get_signal_stats.rst +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/research/sf_quant.research.run_ff_regression.rst +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/research/sf_quant.research.run_quantile_ff_regression.rst +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/research/sf_quant.research.vol_scale_ports.rst +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/research.rst +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/docs/requirements.txt +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/src/sf_quant/__init__.py +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/src/sf_quant/backtester/__init__.py +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/src/sf_quant/backtester/parallel.py +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/src/sf_quant/backtester/sequential.py +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/src/sf_quant/data/__init__.py +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/src/sf_quant/data/_config.py +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/src/sf_quant/data/_factors.py +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/src/sf_quant/data/_tables.py +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/src/sf_quant/data/_views.py +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/src/sf_quant/data/alphas.py +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/src/sf_quant/data/assets.py +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/src/sf_quant/data/benchmark.py +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/src/sf_quant/data/covariance_matrix.py +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/src/sf_quant/data/covariances.py +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/src/sf_quant/data/crsp_daily.py +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/src/sf_quant/data/crsp_monthly.py +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/src/sf_quant/data/crsp_v2_daily.py +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/src/sf_quant/data/crsp_v2_monthly.py +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/src/sf_quant/data/exposures.py +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/src/sf_quant/data/factors.py +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/src/sf_quant/data/fama_french.py +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/src/sf_quant/data/optimal_weights.py +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/src/sf_quant/data/scores.py +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/src/sf_quant/data/signals.py +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/src/sf_quant/optimizer/__init__.py +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/src/sf_quant/optimizer/constraints.py +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/src/sf_quant/performance/__init__.py +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/src/sf_quant/performance/charts.py +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/src/sf_quant/performance/drawdown.py +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/src/sf_quant/performance/ics.py +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/src/sf_quant/performance/leverage.py +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/src/sf_quant/performance/returns.py +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/src/sf_quant/performance/tables.py +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/src/sf_quant/performance/turnover.py +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/src/sf_quant/research/__init__.py +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/src/sf_quant/research/ff_regression.py +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/src/sf_quant/research/quantile_portfolios.py +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/src/sf_quant/research/signal_analysis.py +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/src/sf_quant/schema/__init__.py +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/src/sf_quant/schema/alpha_schema.py +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/src/sf_quant/schema/drawdown_schema.py +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/src/sf_quant/schema/fama_french_schema.py +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/src/sf_quant/schema/ic_schema.py +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/src/sf_quant/schema/leverage_schema.py +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/src/sf_quant/schema/portfolio_schema.py +0 -0
- {sf_quant-0.2.2 → sf_quant-0.2.4}/src/sf_quant/schema/returns_schema.py +0 -0
|
@@ -17,8 +17,8 @@ def _construct_portfolio(
|
|
|
17
17
|
constraints: list[Constraint],
|
|
18
18
|
gamma: float,
|
|
19
19
|
target_active_risk: float | None = None,
|
|
20
|
-
benchmark_df: pl.DataFrame | None = None,
|
|
21
20
|
progress_bar: tqdm_ray.tqdm | None = None,
|
|
21
|
+
active_weights: bool = False
|
|
22
22
|
):
|
|
23
23
|
"""
|
|
24
24
|
Construct a single optimized portfolio for a given date.
|
|
@@ -39,10 +39,11 @@ def _construct_portfolio(
|
|
|
39
39
|
Risk aversion parameter.
|
|
40
40
|
target_active_risk : float, optional
|
|
41
41
|
Target active risk for gamma calibration.
|
|
42
|
-
benchmark_df : pl.DataFrame, optional
|
|
43
|
-
Benchmark weights data with columns 'date', 'barrid', 'benchmark_weight'.
|
|
44
42
|
progress_bar : tqdm_ray.tqdm, optional
|
|
45
43
|
Ray-based progress bar for tracking completion.
|
|
44
|
+
active_weights : bool
|
|
45
|
+
Flag indicating how to treat output weights of optimizer. False (default)
|
|
46
|
+
means that we subtract of benchmark weights before computing active risk.
|
|
46
47
|
|
|
47
48
|
Returns
|
|
48
49
|
-------
|
|
@@ -59,17 +60,14 @@ def _construct_portfolio(
|
|
|
59
60
|
else None
|
|
60
61
|
)
|
|
61
62
|
|
|
62
|
-
benchmark_weights =
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
.fill_null(0.0)
|
|
71
|
-
)
|
|
72
|
-
benchmark_weights = aligned["benchmark_weight"].to_numpy()
|
|
63
|
+
benchmark_weights = (
|
|
64
|
+
subset["benchmark_weight"].to_numpy()
|
|
65
|
+
if "benchmark_weight" in subset.columns
|
|
66
|
+
else None
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
if benchmark_weights is None and active_weights is False:
|
|
70
|
+
raise ValueError("Benchmark weights must be provided if active_weights flag is False (default).")
|
|
73
71
|
|
|
74
72
|
(
|
|
75
73
|
factor_exposures,
|
|
@@ -88,6 +86,7 @@ def _construct_portfolio(
|
|
|
88
86
|
betas=betas,
|
|
89
87
|
target_active_risk=target_active_risk,
|
|
90
88
|
benchmark_weights=benchmark_weights,
|
|
89
|
+
active_weights=active_weights
|
|
91
90
|
)
|
|
92
91
|
|
|
93
92
|
portfolio = portfolio.with_columns(pl.lit(date_).alias("date")).select(
|
|
@@ -106,6 +105,7 @@ def dynamic_backtest_parallel(
|
|
|
106
105
|
initial_gamma: float = 100,
|
|
107
106
|
target_active_risk: float = 0.05,
|
|
108
107
|
n_cpus: int | None = None,
|
|
108
|
+
active_weights: bool = False
|
|
109
109
|
) -> pl.DataFrame:
|
|
110
110
|
"""
|
|
111
111
|
Run a parallelized backtest of portfolio optimization using Ray.
|
|
@@ -137,6 +137,9 @@ def dynamic_backtest_parallel(
|
|
|
137
137
|
n_cpus : int, optional
|
|
138
138
|
Number of CPUs to allocate to Ray. If ``None``, defaults to
|
|
139
139
|
``os.cpu_count()`` but is capped at the number of unique dates.
|
|
140
|
+
active_weights : bool
|
|
141
|
+
Flag indicating how to treat output weights of optimizer. False (default)
|
|
142
|
+
means that we subtract of benchmark weights before computing active risk.
|
|
140
143
|
|
|
141
144
|
Returns
|
|
142
145
|
-------
|
|
@@ -171,23 +174,30 @@ def dynamic_backtest_parallel(
|
|
|
171
174
|
>>> import datetime as dt
|
|
172
175
|
>>> start = dt.date(2024, 1, 1)
|
|
173
176
|
>>> end = dt.date(2024, 1, 10)
|
|
174
|
-
>>>
|
|
177
|
+
>>> benchmark_weights = sfd.load_benchmark(start, end).rename({'weight': 'benchmark_weight'})
|
|
175
178
|
>>> data = (
|
|
176
179
|
... sfd.load_assets(
|
|
177
180
|
... start=start,
|
|
178
181
|
... end=end,
|
|
179
182
|
... in_universe=True,
|
|
180
|
-
... columns=
|
|
183
|
+
... columns=['date', 'barrid']
|
|
181
184
|
... )
|
|
182
185
|
... .with_columns(
|
|
183
186
|
... pl.lit(0).alias('alpha')
|
|
184
187
|
... )
|
|
188
|
+
... .join(
|
|
189
|
+
... other=benchmark_weights,
|
|
190
|
+
... on=['date', 'barrid'],
|
|
191
|
+
... how='left'
|
|
192
|
+
... )
|
|
185
193
|
... )
|
|
186
|
-
>>> constraints = [sfo.FullInvestment()]
|
|
194
|
+
>>> constraints = [sfo.FullInvestment(), sfo.LongOnly()]
|
|
187
195
|
>>> weights = sfb.dynamic_backtest_parallel(
|
|
188
196
|
... data=data,
|
|
189
197
|
... constraints=constraints,
|
|
190
198
|
... initial_gamma=100,
|
|
199
|
+
... target_active_risk=0.05,
|
|
200
|
+
... active_weights=False
|
|
191
201
|
... )
|
|
192
202
|
shape: (5, 5)
|
|
193
203
|
┌────────────┬─────────┬───────────┬───────┬──────────────┐
|
|
@@ -205,10 +215,6 @@ def dynamic_backtest_parallel(
|
|
|
205
215
|
# Get dates
|
|
206
216
|
dates = data["date"].unique().sort().to_list()
|
|
207
217
|
|
|
208
|
-
start_date = dates[0]
|
|
209
|
-
end_date = dates[-1]
|
|
210
|
-
benchmark_df = load_benchmark(start_date, end_date).rename({"weight": "benchmark_weight"})
|
|
211
|
-
|
|
212
218
|
# Set up ray
|
|
213
219
|
n_cpus = n_cpus or os.cpu_count()
|
|
214
220
|
n_cpus = min(len(dates), n_cpus)
|
|
@@ -230,8 +236,8 @@ def dynamic_backtest_parallel(
|
|
|
230
236
|
constraints=constraints,
|
|
231
237
|
gamma=initial_gamma,
|
|
232
238
|
target_active_risk=target_active_risk,
|
|
233
|
-
benchmark_df=benchmark_df,
|
|
234
239
|
progress_bar=progress_bar,
|
|
240
|
+
active_weights=active_weights
|
|
235
241
|
)
|
|
236
242
|
for date_ in dates
|
|
237
243
|
]
|
|
@@ -108,6 +108,7 @@ def dynamic_mve_optimizer(
|
|
|
108
108
|
betas: np.ndarray | None = None,
|
|
109
109
|
target_active_risk: float | None = None,
|
|
110
110
|
benchmark_weights: np.ndarray | None = None,
|
|
111
|
+
active_weights: bool = False
|
|
111
112
|
) -> pl.DataFrame:
|
|
112
113
|
"""
|
|
113
114
|
Mean-variance optimizer with optional active risk calibration.
|
|
@@ -143,6 +144,9 @@ def dynamic_mve_optimizer(
|
|
|
143
144
|
benchmark_weights : np.ndarray, optional
|
|
144
145
|
Benchmark portfolio weights of shape (n_assets,), required if
|
|
145
146
|
``target_active_risk`` is specified.
|
|
147
|
+
active_weights : bool
|
|
148
|
+
Flag indicating how to treat output weights of optimizer. False (default)
|
|
149
|
+
means that we subtract of benchmark weights before computing active risk.
|
|
146
150
|
|
|
147
151
|
Returns
|
|
148
152
|
-------
|
|
@@ -204,6 +208,7 @@ def dynamic_mve_optimizer(
|
|
|
204
208
|
constraints=constructed_constraints,
|
|
205
209
|
target_active_risk=target_active_risk,
|
|
206
210
|
initial_gamma=initial_gamma,
|
|
211
|
+
active_weights=active_weights
|
|
207
212
|
)
|
|
208
213
|
|
|
209
214
|
optimal_weights = _quadratic_program(
|
|
@@ -281,34 +286,6 @@ def _quadratic_program(
|
|
|
281
286
|
|
|
282
287
|
return weights.value
|
|
283
288
|
|
|
284
|
-
def _active_quadratic_program(
|
|
285
|
-
alphas: np.ndarray,
|
|
286
|
-
factor_exposures: np.ndarray,
|
|
287
|
-
factor_covariance: np.ndarray,
|
|
288
|
-
specific_risk: np.ndarray,
|
|
289
|
-
gamma: float,
|
|
290
|
-
constraints: list[cp.Constraint],
|
|
291
|
-
benchmark_weights: np.ndarray,
|
|
292
|
-
) -> np.ndarray:
|
|
293
|
-
n_assets = len(alphas)
|
|
294
|
-
weights = cp.Variable(n_assets)
|
|
295
|
-
constraints = [constraint(weights) for constraint in constraints]
|
|
296
|
-
|
|
297
|
-
portfolio_return = weights.T @ alphas
|
|
298
|
-
|
|
299
|
-
active_w = weights - benchmark_weights
|
|
300
|
-
factor_loadings = factor_exposures.T @ active_w
|
|
301
|
-
factor_variance = cp.quad_form(factor_loadings, factor_covariance)
|
|
302
|
-
specific_variance = cp.sum(cp.multiply(specific_risk, cp.square(active_w)))
|
|
303
|
-
active_variance = factor_variance + specific_variance
|
|
304
|
-
|
|
305
|
-
objective = cp.Maximize(portfolio_return - 0.5 * gamma * active_variance)
|
|
306
|
-
|
|
307
|
-
problem = cp.Problem(objective, constraints)
|
|
308
|
-
problem.solve(solver="OSQP")
|
|
309
|
-
|
|
310
|
-
return weights.value
|
|
311
|
-
|
|
312
289
|
def _calibrate_gamma(
|
|
313
290
|
alphas: np.ndarray,
|
|
314
291
|
factor_exposures: np.ndarray,
|
|
@@ -320,6 +297,7 @@ def _calibrate_gamma(
|
|
|
320
297
|
initial_gamma: float = 100.0,
|
|
321
298
|
error: float = 0.005,
|
|
322
299
|
max_iterations: int = 5,
|
|
300
|
+
active_weights: bool = False
|
|
323
301
|
):
|
|
324
302
|
"""
|
|
325
303
|
Calibrate gamma to hit a target annualized active risk.
|
|
@@ -350,13 +328,15 @@ def _calibrate_gamma(
|
|
|
350
328
|
Convergence tolerance. Default 0.005 (0.5%).
|
|
351
329
|
max_iterations : int
|
|
352
330
|
Maximum number of iterations. Default 5.
|
|
331
|
+
active_weights : bool
|
|
332
|
+
Flag indicating how to treat output weights of optimizer. False (default)
|
|
333
|
+
means that we subtract of benchmark weights before computing active risk.
|
|
353
334
|
|
|
354
335
|
Returns
|
|
355
336
|
-------
|
|
356
337
|
float
|
|
357
338
|
Calibrated gamma.
|
|
358
339
|
"""
|
|
359
|
-
n_assets = len(alphas)
|
|
360
340
|
gamma = initial_gamma
|
|
361
341
|
active_risk = float('inf')
|
|
362
342
|
iterations = 1
|
|
@@ -364,10 +344,15 @@ def _calibrate_gamma(
|
|
|
364
344
|
|
|
365
345
|
while abs(active_risk - target_active_risk) > error and iterations <= max_iterations:
|
|
366
346
|
# Solve the optimization
|
|
367
|
-
weights =
|
|
347
|
+
weights = _quadratic_program(alphas, factor_exposures, factor_covariance, specific_risk, gamma, constraints)
|
|
368
348
|
|
|
349
|
+
# Compute active weights if active_weights flag is False
|
|
350
|
+
if not active_weights:
|
|
351
|
+
active_w = weights - benchmark_weights
|
|
352
|
+
else:
|
|
353
|
+
active_w = weights
|
|
354
|
+
|
|
369
355
|
# Compute active risk using factor model
|
|
370
|
-
active_w = weights - benchmark_weights
|
|
371
356
|
active_factor_loadings = factor_exposures.T @ active_w
|
|
372
357
|
active_factor_var = active_factor_loadings @ factor_covariance @ active_factor_loadings
|
|
373
358
|
active_specific_var = np.sum(specific_risk * np.square(active_w))
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/backtester/sf_quant.backtester.dynamic_parallel.rst
RENAMED
|
File without changes
|
|
File without changes
|
{sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/data/sf_quant.data.construct_covariance_matrix.rst
RENAMED
|
File without changes
|
|
File without changes
|
{sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/data/sf_quant.data.get_crsp_daily_columns.rst
RENAMED
|
File without changes
|
{sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/data/sf_quant.data.get_crsp_monthly_columns.rst
RENAMED
|
File without changes
|
{sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/data/sf_quant.data.get_crsp_v2_daily_columns.rst
RENAMED
|
File without changes
|
{sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/data/sf_quant.data.get_crsp_v2_monthly_columns.rst
RENAMED
|
File without changes
|
{sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/data/sf_quant.data.get_exposures_columns.rst
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/data/sf_quant.data.get_fama_french_columns.rst
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/data/sf_quant.data.load_benchmark_returns.rst
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/data/sf_quant.data.load_crsp_v2_monthly.rst
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/optimizer/sf_quant.optimizer.FullInvestment.rst
RENAMED
|
File without changes
|
|
File without changes
|
{sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/optimizer/sf_quant.optimizer.NoBuyingOnMargin.rst
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/optimizer/sf_quant.optimizer.ZeroInvestment.rst
RENAMED
|
File without changes
|
|
File without changes
|
{sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/optimizer/sf_quant.optimizer.mve_optimizer.rst
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/performance/sf_quant.performance.plot_turnover.rst
RENAMED
|
File without changes
|
|
File without changes
|
{sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/research/sf_quant.research.beta_scale_ports.rst
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/research/sf_quant.research.get_signal_stats.rst
RENAMED
|
File without changes
|
{sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/research/sf_quant.research.run_ff_regression.rst
RENAMED
|
File without changes
|
|
File without changes
|
{sf_quant-0.2.2 → sf_quant-0.2.4}/docs/reference/research/sf_quant.research.vol_scale_ports.rst
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|