goal-based-allocation 0.2.0__tar.gz → 0.3.0__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.
- {goal_based_allocation-0.2.0/goal_based_allocation.egg-info → goal_based_allocation-0.3.0}/PKG-INFO +82 -64
- goal_based_allocation-0.2.0/PKG-INFO → goal_based_allocation-0.3.0/README.md +469 -489
- {goal_based_allocation-0.2.0 → goal_based_allocation-0.3.0}/pyproject.toml +15 -5
- {goal_based_allocation-0.2.0 → goal_based_allocation-0.3.0/src}/goal_based_allocation/__init__.py +15 -1
- {goal_based_allocation-0.2.0 → goal_based_allocation-0.3.0/src}/goal_based_allocation/vanilla_option_pricer.py +10 -3
- goal_based_allocation-0.3.0/src/goal_based_allocation/variance_swap.py +617 -0
- goal_based_allocation-0.2.0/README.md → goal_based_allocation-0.3.0/src/goal_based_allocation.egg-info/PKG-INFO +507 -457
- goal_based_allocation-0.3.0/src/goal_based_allocation.egg-info/SOURCES.txt +25 -0
- {goal_based_allocation-0.2.0 → goal_based_allocation-0.3.0/src}/goal_based_allocation.egg-info/requires.txt +5 -0
- goal_based_allocation-0.3.0/tests/test_docs.py +37 -0
- goal_based_allocation-0.3.0/tests/test_metadata.py +32 -0
- goal_based_allocation-0.3.0/tests/test_quickstart.py +20 -0
- goal_based_allocation-0.3.0/tests/test_repository_layout.py +54 -0
- goal_based_allocation-0.3.0/tests/test_variance_swap.py +233 -0
- goal_based_allocation-0.2.0/goal_based_allocation.egg-info/SOURCES.txt +0 -19
- {goal_based_allocation-0.2.0 → goal_based_allocation-0.3.0}/LICENSE +0 -0
- {goal_based_allocation-0.2.0 → goal_based_allocation-0.3.0}/setup.cfg +0 -0
- {goal_based_allocation-0.2.0 → goal_based_allocation-0.3.0/src}/goal_based_allocation/client_solver.py +0 -0
- {goal_based_allocation-0.2.0 → goal_based_allocation-0.3.0/src}/goal_based_allocation/laplace_inversion.py +0 -0
- {goal_based_allocation-0.2.0 → goal_based_allocation-0.3.0/src}/goal_based_allocation/mandate_utils.py +0 -0
- {goal_based_allocation-0.2.0 → goal_based_allocation-0.3.0/src}/goal_based_allocation/opportunity_set.py +0 -0
- {goal_based_allocation-0.2.0 → goal_based_allocation-0.3.0/src}/goal_based_allocation/regime_switch_paper.py +0 -0
- {goal_based_allocation-0.2.0 → goal_based_allocation-0.3.0/src}/goal_based_allocation/riccati_solver.py +0 -0
- {goal_based_allocation-0.2.0 → goal_based_allocation-0.3.0/src}/goal_based_allocation.egg-info/dependency_links.txt +0 -0
- {goal_based_allocation-0.2.0 → goal_based_allocation-0.3.0/src}/goal_based_allocation.egg-info/top_level.txt +0 -0
- {goal_based_allocation-0.2.0 → goal_based_allocation-0.3.0}/tests/test_framework.py +0 -0
- {goal_based_allocation-0.2.0 → goal_based_allocation-0.3.0}/tests/test_reference_crosschecks.py +0 -0
- {goal_based_allocation-0.2.0 → goal_based_allocation-0.3.0}/tests/test_vanilla_option_pricer.py +0 -0
{goal_based_allocation-0.2.0/goal_based_allocation.egg-info → goal_based_allocation-0.3.0}/PKG-INFO
RENAMED
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: goal-based-allocation
|
|
3
|
-
Version: 0.
|
|
4
|
-
Summary:
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: Analytical dynamic mean-variance allocation and terminal-wealth risk under regime-switching jump-diffusions
|
|
5
5
|
Author: Artur Sepp
|
|
6
|
-
License: MIT
|
|
6
|
+
License-Expression: MIT
|
|
7
7
|
Project-URL: Homepage, https://github.com/ArturSepp/GoalBasedAllocation
|
|
8
8
|
Project-URL: Repository, https://github.com/ArturSepp/GoalBasedAllocation
|
|
9
9
|
Project-URL: Issues, https://github.com/ArturSepp/GoalBasedAllocation/issues
|
|
10
|
-
|
|
10
|
+
Project-URL: Documentation, https://artursepp.github.io/GoalBasedAllocation/
|
|
11
|
+
Project-URL: Changelog, https://github.com/ArturSepp/GoalBasedAllocation/blob/main/CHANGELOG.md
|
|
12
|
+
Project-URL: Paper, https://papers.ssrn.com/sol3/papers.cfm?abstract_id=6534579
|
|
13
|
+
Keywords: portfolio-optimization,mean-variance,regime-switching,jump-diffusion,goal-based-investing,laplace-transform,option-pricing,quantitative-finance,asset-allocation,wealth-management,absorbing-barrier
|
|
11
14
|
Classifier: Development Status :: 4 - Beta
|
|
12
15
|
Classifier: Intended Audience :: Financial and Insurance Industry
|
|
13
16
|
Classifier: Intended Audience :: Science/Research
|
|
14
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
15
17
|
Classifier: Programming Language :: Python :: 3
|
|
16
18
|
Classifier: Programming Language :: Python :: 3.10
|
|
17
19
|
Classifier: Programming Language :: Python :: 3.11
|
|
@@ -28,37 +30,30 @@ Provides-Extra: dev
|
|
|
28
30
|
Requires-Dist: pytest; extra == "dev"
|
|
29
31
|
Requires-Dist: black; extra == "dev"
|
|
30
32
|
Requires-Dist: ruff; extra == "dev"
|
|
33
|
+
Provides-Extra: docs
|
|
34
|
+
Requires-Dist: sphinx>=7; extra == "docs"
|
|
35
|
+
Requires-Dist: myst-parser>=2; extra == "docs"
|
|
36
|
+
Requires-Dist: sphinx-sitemap>=2; extra == "docs"
|
|
31
37
|
Dynamic: license-file
|
|
32
38
|
|
|
33
|
-
# GoalBasedAllocation
|
|
39
|
+
# GoalBasedAllocation (`goal-based-allocation`)
|
|
34
40
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
41
|
+
Analytical dynamic mean-variance allocation and terminal-wealth risk under
|
|
42
|
+
regime-switching jump-diffusions in Python for quantitative researchers and
|
|
43
|
+
wealth-management model developers.
|
|
38
44
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
<img src="https://img.shields.io/pypi/v/goal-based-allocation.svg" alt="PyPI">
|
|
48
|
-
</a>
|
|
49
|
-
<a href="https://pypi.org/project/goal-based-allocation/">
|
|
50
|
-
<img src="https://img.shields.io/pypi/pyversions/goal-based-allocation.svg" alt="Python">
|
|
51
|
-
</a>
|
|
52
|
-
<a href="https://pepy.tech/project/goal-based-allocation">
|
|
53
|
-
<img src="https://pepy.tech/badge/goal-based-allocation" alt="Downloads">
|
|
54
|
-
</a>
|
|
55
|
-
</p>
|
|
45
|
+
[](https://pypi.org/project/goal-based-allocation/)
|
|
46
|
+
[](https://pypi.org/project/goal-based-allocation/)
|
|
47
|
+
[](LICENSE)
|
|
48
|
+
[](https://github.com/ArturSepp/GoalBasedAllocation/actions/workflows/tests.yml)
|
|
49
|
+
[](https://pepy.tech/project/goal-based-allocation)
|
|
50
|
+
[](https://pepy.tech/project/goal-based-allocation)
|
|
51
|
+
|
|
52
|
+
**Documentation:** [artursepp.github.io/GoalBasedAllocation](https://artursepp.github.io/GoalBasedAllocation/)
|
|
56
53
|
|
|
57
|
-
|
|
54
|
+
**Paper:** companion code to Sepp, A. (2026), *Dynamic Mean-Variance Portfolio Allocation under Regime-Switching Jump-Diffusions with Absorbing Barriers and Distribution Matching* — [SSRN 6534579](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=6534579). See [Citation](#citation) for BibTeX.
|
|
58
55
|
|
|
59
|
-
|
|
60
|
-
> Jump-Diffusions with Absorbing Barriers and Distribution Matching.**
|
|
61
|
-
> [SSRN: https://papers.ssrn.com/sol3/papers.cfm?abstract_id=6534579](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=6534579)
|
|
56
|
+
---
|
|
62
57
|
|
|
63
58
|
## Overview
|
|
64
59
|
|
|
@@ -66,12 +61,18 @@ This package provides a **fully analytical Laplace-transform framework** for dyn
|
|
|
66
61
|
mean-variance (MV) portfolio allocation under a two-state regime-switching model
|
|
67
62
|
with exponential jumps at regime transitions and an absorbing wealth floor.
|
|
68
63
|
|
|
64
|
+
It models two regimes and multi-asset mandates aggregated to one effective risky
|
|
65
|
+
asset. It is not a discrete constrained multi-asset optimiser, trading engine, or
|
|
66
|
+
production portfolio-management system; use
|
|
67
|
+
[`optimalportfolios`](https://github.com/ArturSepp/OptimalPortfolios) for rolling
|
|
68
|
+
multi-asset construction, constraints, transaction costs, and backtesting.
|
|
69
|
+
|
|
69
70
|
The MV-optimal strategy takes the form
|
|
70
71
|
|
|
71
|
-
$$\omega
|
|
72
|
+
$$\omega^{\ast}(t) = |\omega^{\ast}_a| \cdot \left(\frac{\Pi^{\ast}(t)}{\Pi_t} - 1\right)$$
|
|
72
73
|
|
|
73
|
-
where $\Pi
|
|
74
|
-
and $|\omega
|
|
74
|
+
where $\Pi^{\ast}(t)$ is the target wealth trajectory derived from the Riccati ODE system,
|
|
75
|
+
and $|\omega^{\ast}_a|$ is the regime-dependent allocation intensity. This produces an
|
|
75
76
|
**endogenous de-risking glide path**: early in the horizon the funding gap is large
|
|
76
77
|
and allocation is aggressive; as the portfolio approaches the target, allocation
|
|
77
78
|
moderates automatically.
|
|
@@ -101,6 +102,12 @@ simulation is needed for pricing; MC is used only for validation.
|
|
|
101
102
|
- Monte Carlo simulator for validation of all analytical results
|
|
102
103
|
- Integration tests and all paper figures reproducible from a single command
|
|
103
104
|
|
|
105
|
+
## When to use it — and when not
|
|
106
|
+
|
|
107
|
+
Use `goal-based-allocation` to design goal-based mandates under regime switching: survival and shortfall probabilities against a wealth floor, MV-optimal allocation intensities and glide paths, terminal wealth distributions, investment opportunity sets for client advice, and regime-switching vanilla option pricing on the same Laplace engine — all analytically, with Monte Carlo reserved for validation.
|
|
108
|
+
|
|
109
|
+
The model is deliberately parsimonious: two regimes, exponential jumps at transitions, and multi-asset mandates reduced to a single effective asset via portfolio aggregation. For discrete rolling multi-asset optimisation with weight constraints and transaction costs, use [`optimalportfolios`](https://github.com/ArturSepp/OptimalPortfolios).
|
|
110
|
+
|
|
104
111
|
## Model
|
|
105
112
|
|
|
106
113
|
The portfolio wealth $\Pi_t$ follows a regime-switching jump-diffusion
|
|
@@ -114,7 +121,7 @@ with two states: **growth** ($i=1$) and **stress** ($i=2$).
|
|
|
114
121
|
| $\mu^{[i]} = \bar{\mu}^{[i]} - \lambda \alpha^{[i]}$ | Diffusion drift | `mu_bar` |
|
|
115
122
|
| $r_h = \max(r, c)$ | Hurdle rate | `r_h` |
|
|
116
123
|
| $r_c = r_h - c = \max(0, r-c)$ | Net floor growth rate | `r_c` |
|
|
117
|
-
| $\omega
|
|
124
|
+
| $\omega^{\ast}_a = -\tilde{a}^{[i]}/\Sigma^{[i]}$ | Risky allocation coefficient | `w_a` |
|
|
118
125
|
|
|
119
126
|
### Process specification
|
|
120
127
|
|
|
@@ -123,7 +130,7 @@ with two states: **growth** ($i=1$) and **stress** ($i=2$).
|
|
|
123
130
|
| Diffusion | Regime-dependent drift $\mu^{[i]}$ and volatility $\sigma^{[i]}$ |
|
|
124
131
|
| Jumps | Exponential crash at growth→stress ($\eta^{[1]}$), exponential recovery at stress→growth ($\eta^{[2]}$) |
|
|
125
132
|
| Regime switching | Poisson rates $\lambda^{[12]}$ (crash) and $\lambda^{[21]}$ (recovery) |
|
|
126
|
-
| MV-optimal control | $\omega
|
|
133
|
+
| MV-optimal control | $\omega^{\ast}(t) = \|\omega_a^{\ast}\| \cdot (\Pi^{\ast}(t)/\Pi_t - 1)$, from Riccati system |
|
|
127
134
|
| Absorbing floor | Wealth stopped at $L_t = L_0 \cdot e^{r_c t}$, converting to cash |
|
|
128
135
|
|
|
129
136
|
### Asset class parameters
|
|
@@ -148,9 +155,9 @@ $w_{\text{eq}} = g(1-w)$, $w_{\text{pe}} = (1-g)(1-w)$.
|
|
|
148
155
|
| Balanced | 35/43/22 | 11.1 / 16.7% | 4.34 / 0.70% | 0.233 |
|
|
149
156
|
| Growth | 0/67/33 | 15.8 / 23.8% | 5.33 / 0.00% | 0.334 |
|
|
150
157
|
|
|
151
|
-
### MV-optimal results ($c=0\%$, $\omega
|
|
158
|
+
### MV-optimal results ($c=0\%$, $\omega^{\ast}(0)=1$, $q_{dd}=2$)
|
|
152
159
|
|
|
153
|
-
| Mandate | $r_{\text{impl}}$ | $\Pi
|
|
160
|
+
| Mandate | $r_{\text{impl}}$ | $\Pi^{\ast}_T$ | $\mathbb{E}[\Pi_T]$ | Std | Survival | $r^{\text{BH}}_{\text{impl}}$ | $\text{Std}^{\text{BH}}$ |
|
|
154
161
|
|---|---|---|---|---|---|---|---|
|
|
155
162
|
| Income | 2.39% | 240 | 127 | 24.7 | 85.5% | 2.46% | 30.4 |
|
|
156
163
|
| Conservative | 2.92% | 200 | 134 | 33.7 | 83.2% | 3.33% | 48.3 |
|
|
@@ -181,20 +188,21 @@ Requires Python >= 3.10 with NumPy >= 1.24, SciPy >= 1.10, and Matplotlib >= 3.7
|
|
|
181
188
|
|
|
182
189
|
```
|
|
183
190
|
GoalBasedAllocation/
|
|
184
|
-
├──
|
|
185
|
-
│
|
|
186
|
-
│
|
|
187
|
-
│
|
|
188
|
-
│
|
|
189
|
-
│
|
|
190
|
-
│
|
|
191
|
-
│
|
|
191
|
+
├── src/
|
|
192
|
+
│ └── goal_based_allocation/ # Core library
|
|
193
|
+
│ ├── regime_switch_paper.py # Density, survival, overshoot, BH moments
|
|
194
|
+
│ ├── riccati_solver.py # Riccati ODE system + MC simulator
|
|
195
|
+
│ ├── laplace_inversion.py # Abate-Whitt & Stehfest numerical inversion
|
|
196
|
+
│ ├── client_solver.py # Effective asset construction, portfolio eta quadrature
|
|
197
|
+
│ ├── mandate_utils.py # Portfolio mandate construction from assets
|
|
198
|
+
│ ├── opportunity_set.py # Investment opportunity set & advisor framework
|
|
199
|
+
│ └── vanilla_option_pricer.py # Regime-switching vanilla option pricing
|
|
192
200
|
├── examples/ # Minimal, self-contained illustrations
|
|
193
201
|
│ ├── wealth_process_simulation.py
|
|
194
202
|
│ ├── terminal_wealth_distribution.py
|
|
195
203
|
│ ├── investment_opportunity_set.py
|
|
196
204
|
│ └── regime_switch_smile.py # Vol smile + Fourier/MC reference pricers
|
|
197
|
-
├──
|
|
205
|
+
├── papers/
|
|
198
206
|
│ └── goal_based_allocation_2026/ # Self-contained paper: LaTeX, PDF, figures
|
|
199
207
|
│ ├── goal_based_allocation_2026.tex
|
|
200
208
|
│ ├── generate_paper_figures.py # All 10 figures + integration tests
|
|
@@ -333,13 +341,17 @@ Fourier and Monte Carlo cross-checks.
|
|
|
333
341
|
|
|
334
342
|
## Reproducing Paper Results
|
|
335
343
|
|
|
336
|
-
|
|
344
|
+
The `papers/` projects are available from a GitHub clone and are intentionally not
|
|
345
|
+
included in PyPI distributions. From a clone, the main paper's integration tests and
|
|
346
|
+
figures can be reproduced with the commands below. The current `--test` mode runs the
|
|
347
|
+
tests and then generates all figures; use `--outdir` to keep verification output away
|
|
348
|
+
from tracked figures.
|
|
337
349
|
|
|
338
350
|
```bash
|
|
339
|
-
cd
|
|
351
|
+
cd papers/goal_based_allocation_2026
|
|
340
352
|
|
|
341
|
-
# Run integration
|
|
342
|
-
python generate_paper_figures.py --test
|
|
353
|
+
# Run 9 integration assertions, then generate figures into a temporary directory
|
|
354
|
+
python generate_paper_figures.py --test --outdir my_verification_figures/
|
|
343
355
|
|
|
344
356
|
# Generate all figures only (writes to ./figures/)
|
|
345
357
|
python generate_paper_figures.py
|
|
@@ -383,8 +395,8 @@ The `--test` flag runs 7 tests with 9 assertions covering:
|
|
|
383
395
|
### Selected figures
|
|
384
396
|
|
|
385
397
|
<p align="center">
|
|
386
|
-
<img src="
|
|
387
|
-
<img src="
|
|
398
|
+
<img src="papers/goal_based_allocation_2026/figures/mandate_density_overlay_c0.png" width="48%" />
|
|
399
|
+
<img src="papers/goal_based_allocation_2026/figures/mandate_comparison.png" width="48%" />
|
|
388
400
|
</p>
|
|
389
401
|
|
|
390
402
|
<p align="center">
|
|
@@ -393,8 +405,8 @@ The `--test` flag runs 7 tests with 9 assertions covering:
|
|
|
393
405
|
</p>
|
|
394
406
|
|
|
395
407
|
<p align="center">
|
|
396
|
-
<img src="
|
|
397
|
-
<img src="
|
|
408
|
+
<img src="papers/goal_based_allocation_2026/figures/path_dynamics_balanced.png" width="48%" />
|
|
409
|
+
<img src="papers/goal_based_allocation_2026/figures/opportunity_set_c0.png" width="48%" />
|
|
398
410
|
</p>
|
|
399
411
|
|
|
400
412
|
<p align="center">
|
|
@@ -409,7 +421,7 @@ The analytical framework proceeds in three steps:
|
|
|
409
421
|
**Step 1: Riccati ODE system.** The pre-commitment MV problem reduces to a
|
|
410
422
|
system of coupled Riccati ODEs for the value function coefficients
|
|
411
423
|
in each regime. The solution yields the optimal allocation
|
|
412
|
-
intensity $|\omega
|
|
424
|
+
intensity $|\omega^{\ast}_a|$ and the target wealth trajectory $\Pi^{\ast}(t)$.
|
|
413
425
|
|
|
414
426
|
**Step 2: Gap process.** Under the optimal policy, the log-cushion ratio
|
|
415
427
|
$X_t = \ln(B_t/Z_t)$ is a regime-switching jump-diffusion with an absorbing
|
|
@@ -426,16 +438,22 @@ jump sizes via deterministic numerical integration (`portfolio_eta_quadrature`).
|
|
|
426
438
|
Buy-and-hold benchmark moments are computed exactly via the 2×2 matrix exponential
|
|
427
439
|
of Proposition B.7.
|
|
428
440
|
|
|
429
|
-
##
|
|
441
|
+
## Ecosystem
|
|
430
442
|
|
|
431
|
-
|
|
443
|
+
This package is part of an open-source Python stack for quantitative finance — full catalogue at [github.com/ArturSepp](https://github.com/ArturSepp):
|
|
444
|
+
|
|
445
|
+
| Package | Purpose |
|
|
432
446
|
|---|---|
|
|
433
|
-
| [
|
|
434
|
-
| [
|
|
435
|
-
| [
|
|
436
|
-
| [
|
|
437
|
-
| [
|
|
438
|
-
| [
|
|
447
|
+
| [`qis`](https://github.com/ArturSepp/QuantInvestStrats) | Performance analytics, factsheets, and visualisation |
|
|
448
|
+
| [`optimalportfolios`](https://github.com/ArturSepp/OptimalPortfolios) | Portfolio construction and backtesting |
|
|
449
|
+
| [`factorlasso`](https://github.com/ArturSepp/factorlasso) | Sparse factor models and factor covariance estimation |
|
|
450
|
+
| [`bbg-fetch`](https://github.com/ArturSepp/BloombergFetch) | Bloomberg data fetching |
|
|
451
|
+
| [`trendfollowing`](https://github.com/ArturSepp/TrendFollowingSystems) | Trend-following systems: closed-form theory and replication |
|
|
452
|
+
| [`goal-based-allocation`](https://github.com/ArturSepp/GoalBasedAllocation) *(this package)* | Dynamic MV allocation under regime-switching jump-diffusions |
|
|
453
|
+
| [`stochvolmodels`](https://github.com/ArturSepp/StochVolModels) | Stochastic volatility pricing analytics |
|
|
454
|
+
| [`vanilla-option-pricers`](https://github.com/ArturSepp/VanillaOptionPricers) | Vectorised vanilla option pricers and implied volatility fitters |
|
|
455
|
+
|
|
456
|
+
Dependency links within the stack: `optimalportfolios` builds on `qis` and `factorlasso`; `trendfollowing` builds on `qis`.
|
|
439
457
|
|
|
440
458
|
## Citation
|
|
441
459
|
|
|
@@ -461,7 +479,7 @@ If you use this work in your research, please cite both the paper and the softwa
|
|
|
461
479
|
title = {{GoalBasedAllocation}: A {Python} package for dynamic mean-variance
|
|
462
480
|
portfolio allocation under regime-switching jump-diffusions},
|
|
463
481
|
year = {2026},
|
|
464
|
-
note = {Version 0.
|
|
482
|
+
note = {Version 0.3.0},
|
|
465
483
|
howpublished = {\url{https://github.com/ArturSepp/GoalBasedAllocation}}
|
|
466
484
|
}
|
|
467
485
|
```
|