fundedness 0.2.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.
- fundedness-0.2.0/.github/workflows/docs.yml +36 -0
- fundedness-0.2.0/.github/workflows/publish.yml +28 -0
- fundedness-0.2.0/.gitignore +106 -0
- fundedness-0.2.0/CLAUDE.md +98 -0
- fundedness-0.2.0/PKG-INFO +265 -0
- fundedness-0.2.0/README.md +211 -0
- fundedness-0.2.0/api/__init__.py +1 -0
- fundedness-0.2.0/api/main.py +54 -0
- fundedness-0.2.0/api/routes/__init__.py +1 -0
- fundedness-0.2.0/api/routes/cefr.py +201 -0
- fundedness-0.2.0/api/routes/compare.py +154 -0
- fundedness-0.2.0/api/routes/simulate.py +145 -0
- fundedness-0.2.0/background_information.md +927 -0
- fundedness-0.2.0/docs/api/core.md +15 -0
- fundedness-0.2.0/docs/api/merton.md +91 -0
- fundedness-0.2.0/docs/api/models.md +39 -0
- fundedness-0.2.0/docs/api/viz.md +23 -0
- fundedness-0.2.0/docs/api/withdrawals.md +29 -0
- fundedness-0.2.0/docs/examples/tutorials.md +112 -0
- fundedness-0.2.0/docs/getting-started/installation.md +81 -0
- fundedness-0.2.0/docs/getting-started/quickstart.md +94 -0
- fundedness-0.2.0/docs/guide/cefr.md +102 -0
- fundedness-0.2.0/docs/guide/simulations.md +120 -0
- fundedness-0.2.0/docs/guide/utility-optimization.md +200 -0
- fundedness-0.2.0/docs/guide/visualizations.md +144 -0
- fundedness-0.2.0/docs/guide/withdrawals.md +149 -0
- fundedness-0.2.0/docs/index.md +75 -0
- fundedness-0.2.0/examples/01_cefr_basics.ipynb +298 -0
- fundedness-0.2.0/examples/02_time_distribution.ipynb +341 -0
- fundedness-0.2.0/examples/03_withdrawal_comparison.ipynb +353 -0
- fundedness-0.2.0/fundedness/__init__.py +71 -0
- fundedness-0.2.0/fundedness/allocation/__init__.py +20 -0
- fundedness-0.2.0/fundedness/allocation/base.py +32 -0
- fundedness-0.2.0/fundedness/allocation/constant.py +25 -0
- fundedness-0.2.0/fundedness/allocation/glidepath.py +111 -0
- fundedness-0.2.0/fundedness/allocation/merton_optimal.py +220 -0
- fundedness-0.2.0/fundedness/cefr.py +241 -0
- fundedness-0.2.0/fundedness/liabilities.py +221 -0
- fundedness-0.2.0/fundedness/liquidity.py +49 -0
- fundedness-0.2.0/fundedness/merton.py +289 -0
- fundedness-0.2.0/fundedness/models/__init__.py +35 -0
- fundedness-0.2.0/fundedness/models/assets.py +148 -0
- fundedness-0.2.0/fundedness/models/household.py +153 -0
- fundedness-0.2.0/fundedness/models/liabilities.py +99 -0
- fundedness-0.2.0/fundedness/models/market.py +188 -0
- fundedness-0.2.0/fundedness/models/simulation.py +80 -0
- fundedness-0.2.0/fundedness/models/tax.py +125 -0
- fundedness-0.2.0/fundedness/models/utility.py +154 -0
- fundedness-0.2.0/fundedness/optimize.py +473 -0
- fundedness-0.2.0/fundedness/policies.py +204 -0
- fundedness-0.2.0/fundedness/risk.py +72 -0
- fundedness-0.2.0/fundedness/simulate.py +559 -0
- fundedness-0.2.0/fundedness/viz/__init__.py +33 -0
- fundedness-0.2.0/fundedness/viz/colors.py +110 -0
- fundedness-0.2.0/fundedness/viz/comparison.py +294 -0
- fundedness-0.2.0/fundedness/viz/fan_chart.py +193 -0
- fundedness-0.2.0/fundedness/viz/histogram.py +225 -0
- fundedness-0.2.0/fundedness/viz/optimal.py +542 -0
- fundedness-0.2.0/fundedness/viz/survival.py +230 -0
- fundedness-0.2.0/fundedness/viz/tornado.py +236 -0
- fundedness-0.2.0/fundedness/viz/waterfall.py +203 -0
- fundedness-0.2.0/fundedness/withdrawals/__init__.py +27 -0
- fundedness-0.2.0/fundedness/withdrawals/base.py +116 -0
- fundedness-0.2.0/fundedness/withdrawals/comparison.py +230 -0
- fundedness-0.2.0/fundedness/withdrawals/fixed_swr.py +174 -0
- fundedness-0.2.0/fundedness/withdrawals/guardrails.py +136 -0
- fundedness-0.2.0/fundedness/withdrawals/merton_optimal.py +286 -0
- fundedness-0.2.0/fundedness/withdrawals/rmd_style.py +203 -0
- fundedness-0.2.0/fundedness/withdrawals/vpw.py +136 -0
- fundedness-0.2.0/mkdocs.yml +51 -0
- fundedness-0.2.0/pyproject.toml +96 -0
- fundedness-0.2.0/requirements.txt +7 -0
- fundedness-0.2.0/streamlit_app/__init__.py +1 -0
- fundedness-0.2.0/streamlit_app/app.py +104 -0
- fundedness-0.2.0/streamlit_app/components/__init__.py +1 -0
- fundedness-0.2.0/streamlit_app/components/asset_editor.py +124 -0
- fundedness-0.2.0/streamlit_app/components/liability_editor.py +117 -0
- fundedness-0.2.0/streamlit_app/components/metrics_display.py +144 -0
- fundedness-0.2.0/streamlit_app/pages/0_Inputs.py +242 -0
- fundedness-0.2.0/streamlit_app/pages/1_CEFR_Dashboard.py +112 -0
- fundedness-0.2.0/streamlit_app/pages/2_Time_Runway.py +219 -0
- fundedness-0.2.0/streamlit_app/pages/3_Withdrawal_Lab.py +225 -0
- fundedness-0.2.0/streamlit_app/pages/4_Sensitivity.py +305 -0
- fundedness-0.2.0/streamlit_app/pages/5_Utility_Optimization.py +440 -0
- fundedness-0.2.0/streamlit_app/utils/__init__.py +21 -0
- fundedness-0.2.0/streamlit_app/utils/session_state.py +160 -0
- fundedness-0.2.0/tests/__init__.py +1 -0
- fundedness-0.2.0/tests/conftest.py +119 -0
- fundedness-0.2.0/tests/test_api.py +179 -0
- fundedness-0.2.0/tests/test_cefr.py +294 -0
- fundedness-0.2.0/tests/test_liabilities.py +239 -0
- fundedness-0.2.0/tests/test_merton.py +311 -0
- fundedness-0.2.0/tests/test_optimize.py +336 -0
- fundedness-0.2.0/tests/test_simulate.py +242 -0
- fundedness-0.2.0/tests/test_withdrawals.py +275 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
name: Deploy Documentation
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
pages: write
|
|
11
|
+
id-token: write
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
build:
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v4
|
|
18
|
+
- uses: actions/setup-python@v5
|
|
19
|
+
with:
|
|
20
|
+
python-version: '3.11'
|
|
21
|
+
- run: pip install mkdocs mkdocs-material mkdocstrings[python]
|
|
22
|
+
- run: pip install -e .
|
|
23
|
+
- run: mkdocs build
|
|
24
|
+
- uses: actions/upload-pages-artifact@v3
|
|
25
|
+
with:
|
|
26
|
+
path: site
|
|
27
|
+
|
|
28
|
+
deploy:
|
|
29
|
+
needs: build
|
|
30
|
+
runs-on: ubuntu-latest
|
|
31
|
+
environment:
|
|
32
|
+
name: github-pages
|
|
33
|
+
url: ${{ steps.deployment.outputs.page_url }}
|
|
34
|
+
steps:
|
|
35
|
+
- uses: actions/deploy-pages@v4
|
|
36
|
+
id: deployment
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
workflow_dispatch: # Allow manual trigger
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
publish:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
steps:
|
|
12
|
+
- uses: actions/checkout@v4
|
|
13
|
+
|
|
14
|
+
- uses: actions/setup-python@v5
|
|
15
|
+
with:
|
|
16
|
+
python-version: '3.11'
|
|
17
|
+
|
|
18
|
+
- name: Install build tools
|
|
19
|
+
run: pip install build twine
|
|
20
|
+
|
|
21
|
+
- name: Build package
|
|
22
|
+
run: python -m build
|
|
23
|
+
|
|
24
|
+
- name: Publish to PyPI
|
|
25
|
+
env:
|
|
26
|
+
TWINE_USERNAME: __token__
|
|
27
|
+
TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}
|
|
28
|
+
run: twine upload dist/*
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
build/
|
|
12
|
+
develop-eggs/
|
|
13
|
+
dist/
|
|
14
|
+
downloads/
|
|
15
|
+
eggs/
|
|
16
|
+
.eggs/
|
|
17
|
+
lib/
|
|
18
|
+
lib64/
|
|
19
|
+
parts/
|
|
20
|
+
sdist/
|
|
21
|
+
var/
|
|
22
|
+
wheels/
|
|
23
|
+
share/python-wheels/
|
|
24
|
+
*.egg-info/
|
|
25
|
+
.installed.cfg
|
|
26
|
+
*.egg
|
|
27
|
+
MANIFEST
|
|
28
|
+
|
|
29
|
+
# PyInstaller
|
|
30
|
+
*.manifest
|
|
31
|
+
*.spec
|
|
32
|
+
|
|
33
|
+
# Installer logs
|
|
34
|
+
pip-log.txt
|
|
35
|
+
pip-delete-this-directory.txt
|
|
36
|
+
|
|
37
|
+
# Unit test / coverage reports
|
|
38
|
+
htmlcov/
|
|
39
|
+
.tox/
|
|
40
|
+
.nox/
|
|
41
|
+
.coverage
|
|
42
|
+
.coverage.*
|
|
43
|
+
.cache
|
|
44
|
+
nosetests.xml
|
|
45
|
+
coverage.xml
|
|
46
|
+
*.cover
|
|
47
|
+
*.py,cover
|
|
48
|
+
.hypothesis/
|
|
49
|
+
.pytest_cache/
|
|
50
|
+
|
|
51
|
+
# Translations
|
|
52
|
+
*.mo
|
|
53
|
+
*.pot
|
|
54
|
+
|
|
55
|
+
# Jupyter Notebook
|
|
56
|
+
.ipynb_checkpoints
|
|
57
|
+
|
|
58
|
+
# IPython
|
|
59
|
+
profile_default/
|
|
60
|
+
ipython_config.py
|
|
61
|
+
|
|
62
|
+
# pyenv
|
|
63
|
+
.python-version
|
|
64
|
+
|
|
65
|
+
# Environments
|
|
66
|
+
.env
|
|
67
|
+
.venv
|
|
68
|
+
env/
|
|
69
|
+
venv/
|
|
70
|
+
ENV/
|
|
71
|
+
env.bak/
|
|
72
|
+
venv.bak/
|
|
73
|
+
|
|
74
|
+
# Spyder project settings
|
|
75
|
+
.spyderproject
|
|
76
|
+
.spyproject
|
|
77
|
+
|
|
78
|
+
# Rope project settings
|
|
79
|
+
.ropeproject
|
|
80
|
+
|
|
81
|
+
# mkdocs documentation
|
|
82
|
+
/site
|
|
83
|
+
|
|
84
|
+
# mypy
|
|
85
|
+
.mypy_cache/
|
|
86
|
+
.dmypy.json
|
|
87
|
+
dmypy.json
|
|
88
|
+
|
|
89
|
+
# Pyre type checker
|
|
90
|
+
.pyre/
|
|
91
|
+
|
|
92
|
+
# IDE
|
|
93
|
+
.idea/
|
|
94
|
+
.vscode/
|
|
95
|
+
*.swp
|
|
96
|
+
*.swo
|
|
97
|
+
*~
|
|
98
|
+
|
|
99
|
+
# OS
|
|
100
|
+
.DS_Store
|
|
101
|
+
Thumbs.db
|
|
102
|
+
|
|
103
|
+
# Project specific
|
|
104
|
+
*.log
|
|
105
|
+
secrets.yaml
|
|
106
|
+
config.local.yaml
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## Project Overview
|
|
6
|
+
|
|
7
|
+
This is a Python financial planning toolkit that implements:
|
|
8
|
+
- **CEFR (Certainty-Equivalent Funded Ratio)**: A fundedness metric that applies after-tax, liquidity, and risk haircuts to assets
|
|
9
|
+
- **Victor-style lifetime utility optimization**: Spending and asset allocation policies that maximize expected lifetime utility
|
|
10
|
+
- **Withdrawal Strategy Lab**: Comparison framework for withdrawal strategies (fixed SWR, guardrails, VPW, RMD-style)
|
|
11
|
+
|
|
12
|
+
The project includes both a Python package (`fundedness/`) and a Streamlit web application (`streamlit_app/`).
|
|
13
|
+
|
|
14
|
+
## Development Status
|
|
15
|
+
|
|
16
|
+
This project is in the **specification/planning phase**. The `background_information.md` file contains the complete design spec. No implementation code exists yet.
|
|
17
|
+
|
|
18
|
+
## Planned Commands
|
|
19
|
+
|
|
20
|
+
Once implemented, the project will use:
|
|
21
|
+
- **Package manager**: pip
|
|
22
|
+
- **Testing**: pytest (with property tests for monotonicity)
|
|
23
|
+
- **Docs**: MkDocs
|
|
24
|
+
- **CLI**: `fundedness cefr config.yaml`, `fundedness simulate config.yaml`, `fundedness policy-search config.yaml`
|
|
25
|
+
- **Streamlit**: `streamlit run streamlit_app/app.py`
|
|
26
|
+
|
|
27
|
+
## Architecture
|
|
28
|
+
|
|
29
|
+
### Core Package Structure (`fundedness/`)
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
fundedness/
|
|
33
|
+
├── cefr.py # CEFR ratio calculation with haircut breakdowns
|
|
34
|
+
├── liabilities.py # Liability PV calculations with schedules
|
|
35
|
+
├── taxes.py # Tax modeling by account type
|
|
36
|
+
├── liquidity.py # Liquidity factor adjustments
|
|
37
|
+
├── risk.py # Reliability/concentration haircuts
|
|
38
|
+
├── markets.py # Return/covariance/inflation assumptions
|
|
39
|
+
├── simulate.py # Monte Carlo engine (time-to-floor, time-to-ruin)
|
|
40
|
+
├── utility.py # CRRA utility with subsistence floor
|
|
41
|
+
├── policies.py # Spending/allocation policy interface
|
|
42
|
+
├── optimize.py # Parametric policy search (v0.4+)
|
|
43
|
+
├── withdrawals/ # Withdrawal strategy implementations
|
|
44
|
+
├── allocation/ # Glidepath strategies (constant, rising equity, bucket)
|
|
45
|
+
└── tax/strategy.py # Tax-aware withdrawal sequencing
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Data Models (Pydantic)
|
|
49
|
+
|
|
50
|
+
Key models: `Household`, `BalanceSheet`, `Asset`, `Liability`, `MarketModel`, `TaxModel`, `UtilityModel`, `SimulationConfig`
|
|
51
|
+
|
|
52
|
+
### Core Formulas
|
|
53
|
+
|
|
54
|
+
**CEFR Calculation:**
|
|
55
|
+
```
|
|
56
|
+
CEFR = Σ(Asset × (1-tax_rate) × liquidity_factor × reliability_factor) / PV(Liabilities)
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
**CRRA Utility with Floor:**
|
|
60
|
+
```
|
|
61
|
+
u(C) = (C - F)^(1-γ) / (1-γ) where C > F (subsistence floor)
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Development Tiers
|
|
65
|
+
|
|
66
|
+
1. **MVP (v0.1-0.3)**: CEFR + Monte Carlo runway with P10/P50/P90 bands
|
|
67
|
+
2. **v0.4-0.7**: Victor-style parametric policy search
|
|
68
|
+
3. **v1.0+**: Tax-aware account flows, Roth conversions
|
|
69
|
+
|
|
70
|
+
## Key Concepts
|
|
71
|
+
|
|
72
|
+
- **Haircuts**: Three adjustments to assets—after-tax (τ), liquidity (λ), reliability (ρ)
|
|
73
|
+
- **Floor/Flex spending**: Essential spending floor vs adjustable discretionary
|
|
74
|
+
- **Time metrics**: Time-to-floor-breach, time-to-ruin, max spending drawdown
|
|
75
|
+
- **Confidence intervals**: Scenario percentiles (P10/P50/P90), not statistical CIs
|
|
76
|
+
|
|
77
|
+
## Default Haircut Assumptions
|
|
78
|
+
|
|
79
|
+
Liquidity: cash=1.0, taxable_index=0.95, retirement=0.85, home_equity=0.5, private_business=0.3
|
|
80
|
+
Reliability: diversified_bonds=0.95, diversified_equity=0.85, single_stock=0.60, startup=0.30
|
|
81
|
+
|
|
82
|
+
## Deployment Preferences
|
|
83
|
+
|
|
84
|
+
- **Web App**: Deploy on Streamlit Cloud (free tier)
|
|
85
|
+
- **API**: Expose core functionality via a REST API (FastAPI recommended) for programmatic access
|
|
86
|
+
- **Tutorials**: Create Jupyter notebooks in `examples/` that run in Google Colab. Include working "Open in Colab" badge links in the README using the format:
|
|
87
|
+
```
|
|
88
|
+
[](https://colab.research.google.com/github/engineerinvestor/financial-health-calculator/blob/main/examples/NOTEBOOK.ipynb)
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Visualization Standards
|
|
92
|
+
|
|
93
|
+
Use **Plotly** as the primary visualization library for beautiful, interactive charts:
|
|
94
|
+
- Clean, professional appearance with `template="plotly_white"`
|
|
95
|
+
- Interactive features: hover tooltips, zoom, pan
|
|
96
|
+
- Consistent color palette: blues (#3498db, #2980b9) for wealth, greens (#27ae60, #2ecc71) for spending/survival
|
|
97
|
+
- Fan charts with gradient opacity for percentile bands (P10-P90)
|
|
98
|
+
- Export capability to HTML/PNG for reports
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: fundedness
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: A Python financial planning toolkit with CEFR calculations, Monte Carlo simulations, and beautiful visualizations
|
|
5
|
+
Project-URL: Homepage, https://github.com/engineerinvestor/financial-health-calculator
|
|
6
|
+
Project-URL: Documentation, https://engineerinvestor.github.io/financial-health-calculator/
|
|
7
|
+
Project-URL: Repository, https://github.com/engineerinvestor/financial-health-calculator
|
|
8
|
+
Author-email: Engineer Investor <egr.investor@gmail.com>
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
Keywords: CEFR,Monte Carlo,finance,planning,retirement,withdrawal
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
13
|
+
Classifier: Intended Audience :: Financial and Insurance Industry
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Topic :: Office/Business :: Financial :: Investment
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
|
+
Requires-Dist: numpy>=1.24.0
|
|
22
|
+
Requires-Dist: pandas>=2.0.0
|
|
23
|
+
Requires-Dist: plotly>=5.18.0
|
|
24
|
+
Requires-Dist: pydantic>=2.0.0
|
|
25
|
+
Requires-Dist: scipy>=1.11.0
|
|
26
|
+
Provides-Extra: all
|
|
27
|
+
Requires-Dist: fastapi>=0.108.0; extra == 'all'
|
|
28
|
+
Requires-Dist: hypothesis>=6.92.0; extra == 'all'
|
|
29
|
+
Requires-Dist: mkdocs-material>=9.5.0; extra == 'all'
|
|
30
|
+
Requires-Dist: mkdocs>=1.5.0; extra == 'all'
|
|
31
|
+
Requires-Dist: mkdocstrings[python]>=0.24.0; extra == 'all'
|
|
32
|
+
Requires-Dist: mypy>=1.8.0; extra == 'all'
|
|
33
|
+
Requires-Dist: pytest-cov>=4.1.0; extra == 'all'
|
|
34
|
+
Requires-Dist: pytest>=7.4.0; extra == 'all'
|
|
35
|
+
Requires-Dist: ruff>=0.1.9; extra == 'all'
|
|
36
|
+
Requires-Dist: streamlit>=1.29.0; extra == 'all'
|
|
37
|
+
Requires-Dist: uvicorn[standard]>=0.25.0; extra == 'all'
|
|
38
|
+
Provides-Extra: api
|
|
39
|
+
Requires-Dist: fastapi>=0.108.0; extra == 'api'
|
|
40
|
+
Requires-Dist: uvicorn[standard]>=0.25.0; extra == 'api'
|
|
41
|
+
Provides-Extra: dev
|
|
42
|
+
Requires-Dist: hypothesis>=6.92.0; extra == 'dev'
|
|
43
|
+
Requires-Dist: mypy>=1.8.0; extra == 'dev'
|
|
44
|
+
Requires-Dist: pytest-cov>=4.1.0; extra == 'dev'
|
|
45
|
+
Requires-Dist: pytest>=7.4.0; extra == 'dev'
|
|
46
|
+
Requires-Dist: ruff>=0.1.9; extra == 'dev'
|
|
47
|
+
Provides-Extra: docs
|
|
48
|
+
Requires-Dist: mkdocs-material>=9.5.0; extra == 'docs'
|
|
49
|
+
Requires-Dist: mkdocs>=1.5.0; extra == 'docs'
|
|
50
|
+
Requires-Dist: mkdocstrings[python]>=0.24.0; extra == 'docs'
|
|
51
|
+
Provides-Extra: streamlit
|
|
52
|
+
Requires-Dist: streamlit>=1.29.0; extra == 'streamlit'
|
|
53
|
+
Description-Content-Type: text/markdown
|
|
54
|
+
|
|
55
|
+
# Financial Health Calculator
|
|
56
|
+
|
|
57
|
+
[](https://pypi.org/project/fundedness/)
|
|
58
|
+
[](https://pypi.org/project/fundedness/)
|
|
59
|
+
[](https://github.com/engineerinvestor/financial-health-calculator/actions/workflows/ci.yml)
|
|
60
|
+
[](https://codecov.io/gh/engineerinvestor/financial-health-calculator)
|
|
61
|
+
[](https://engineerinvestor.github.io/financial-health-calculator/)
|
|
62
|
+
[](https://opensource.org/licenses/MIT)
|
|
63
|
+
[](https://colab.research.google.com/github/engineerinvestor/financial-health-calculator/blob/main/examples/01_cefr_basics.ipynb)
|
|
64
|
+
|
|
65
|
+
A comprehensive Python financial planning toolkit with CEFR calculations, Monte Carlo simulations, and beautiful Plotly visualizations.
|
|
66
|
+
|
|
67
|
+
## Features
|
|
68
|
+
|
|
69
|
+
- **CEFR (Certainty-Equivalent Funded Ratio)**: A fundedness metric that accounts for taxes, liquidity, and concentration risk
|
|
70
|
+
- **Monte Carlo Simulations**: Project retirement outcomes with configurable market assumptions
|
|
71
|
+
- **Withdrawal Strategy Lab**: Compare strategies including fixed SWR, guardrails, VPW, RMD-style, and Merton optimal
|
|
72
|
+
- **Utility Optimization**: Victor Haghani / Elm Wealth methodology for optimal spending and allocation
|
|
73
|
+
- **Beautiful Visualizations**: Interactive Plotly charts with fan charts, waterfalls, and survival curves
|
|
74
|
+
- **REST API**: FastAPI backend for programmatic access
|
|
75
|
+
- **Streamlit App**: User-friendly web interface
|
|
76
|
+
|
|
77
|
+
## Quick Start
|
|
78
|
+
|
|
79
|
+
### Installation
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
pip install fundedness
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
For development with all extras:
|
|
86
|
+
```bash
|
|
87
|
+
pip install "fundedness[all]"
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Basic Usage
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
from fundedness import Asset, BalanceSheet, Liability, compute_cefr
|
|
94
|
+
from fundedness.models.assets import AccountType, LiquidityClass, ConcentrationLevel
|
|
95
|
+
|
|
96
|
+
# Define your assets
|
|
97
|
+
assets = [
|
|
98
|
+
Asset(
|
|
99
|
+
name="401(k)",
|
|
100
|
+
value=500_000,
|
|
101
|
+
account_type=AccountType.TAX_DEFERRED,
|
|
102
|
+
liquidity_class=LiquidityClass.RETIREMENT,
|
|
103
|
+
concentration_level=ConcentrationLevel.DIVERSIFIED,
|
|
104
|
+
),
|
|
105
|
+
Asset(
|
|
106
|
+
name="Roth IRA",
|
|
107
|
+
value=200_000,
|
|
108
|
+
account_type=AccountType.TAX_EXEMPT,
|
|
109
|
+
liquidity_class=LiquidityClass.RETIREMENT,
|
|
110
|
+
concentration_level=ConcentrationLevel.DIVERSIFIED,
|
|
111
|
+
),
|
|
112
|
+
]
|
|
113
|
+
|
|
114
|
+
# Define your spending
|
|
115
|
+
liabilities = [
|
|
116
|
+
Liability(name="Living Expenses", annual_amount=50_000, is_essential=True),
|
|
117
|
+
Liability(name="Travel", annual_amount=20_000, is_essential=False),
|
|
118
|
+
]
|
|
119
|
+
|
|
120
|
+
# Calculate CEFR
|
|
121
|
+
result = compute_cefr(
|
|
122
|
+
balance_sheet=BalanceSheet(assets=assets),
|
|
123
|
+
liabilities=liabilities,
|
|
124
|
+
planning_horizon=30,
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
print(f"CEFR: {result.cefr:.2f}")
|
|
128
|
+
print(f"Funded: {result.is_funded}")
|
|
129
|
+
print(result.get_interpretation())
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## Tutorials
|
|
133
|
+
|
|
134
|
+
- [CEFR Basics](https://colab.research.google.com/github/engineerinvestor/financial-health-calculator/blob/main/examples/01_cefr_basics.ipynb) - Introduction to the CEFR metric
|
|
135
|
+
- [Time Distribution Analysis](https://colab.research.google.com/github/engineerinvestor/financial-health-calculator/blob/main/examples/02_time_distribution.ipynb) - Monte Carlo simulations
|
|
136
|
+
- [Withdrawal Strategy Comparison](https://colab.research.google.com/github/engineerinvestor/financial-health-calculator/blob/main/examples/03_withdrawal_comparison.ipynb) - Compare different approaches
|
|
137
|
+
|
|
138
|
+
## Running the Apps
|
|
139
|
+
|
|
140
|
+
### Streamlit Web App
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
streamlit run streamlit_app/app.py
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### FastAPI REST API
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
uvicorn api.main:app --reload
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
API documentation available at `http://localhost:8000/docs`
|
|
153
|
+
|
|
154
|
+
## Key Concepts
|
|
155
|
+
|
|
156
|
+
### CEFR (Certainty-Equivalent Funded Ratio)
|
|
157
|
+
|
|
158
|
+
CEFR measures how well-funded your retirement is after accounting for:
|
|
159
|
+
|
|
160
|
+
- **Tax Haircuts**: What you'll owe when withdrawing from different account types
|
|
161
|
+
- **Liquidity Haircuts**: How easily you can access your assets
|
|
162
|
+
- **Reliability Haircuts**: Risk from concentrated positions
|
|
163
|
+
|
|
164
|
+
**Formula:**
|
|
165
|
+
```
|
|
166
|
+
CEFR = Σ(Asset × (1-τ) × λ × ρ) / PV(Liabilities)
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Where τ = tax rate, λ = liquidity factor, ρ = reliability factor
|
|
170
|
+
|
|
171
|
+
**Interpretation:**
|
|
172
|
+
- CEFR ≥ 2.0: Excellent - Very well-funded
|
|
173
|
+
- CEFR 1.5-2.0: Strong - Well-funded with margin
|
|
174
|
+
- CEFR 1.0-1.5: Adequate - Fully funded
|
|
175
|
+
- CEFR < 1.0: Underfunded - Action needed
|
|
176
|
+
|
|
177
|
+
### Withdrawal Strategies
|
|
178
|
+
|
|
179
|
+
| Strategy | Description | Best For |
|
|
180
|
+
|----------|-------------|----------|
|
|
181
|
+
| Fixed SWR | 4% of initial portfolio, adjusted for inflation | Predictability |
|
|
182
|
+
| % of Portfolio | Fixed % of current value | Market adaptation |
|
|
183
|
+
| Guardrails | Adjustable with floor/ceiling | Balance |
|
|
184
|
+
| VPW | Age-based variable percentage | Maximizing spending |
|
|
185
|
+
| RMD-Style | IRS distribution table based | Tax efficiency |
|
|
186
|
+
| Merton Optimal | Utility-maximizing spending rate | Optimality |
|
|
187
|
+
|
|
188
|
+
### Utility Optimization
|
|
189
|
+
|
|
190
|
+
The toolkit includes Merton's optimal consumption and portfolio choice framework, as applied in modern retirement planning research<sup>[1]</sup>:
|
|
191
|
+
|
|
192
|
+
- **Optimal Equity Allocation**: `k* = (μ - r) / (γ × σ²)`
|
|
193
|
+
- **Wealth-Adjusted Allocation**: Reduces equity as wealth approaches subsistence floor
|
|
194
|
+
- **Optimal Spending Rate**: Increases with age as horizon shortens
|
|
195
|
+
- **Expected Lifetime Utility**: Track utility across Monte Carlo paths
|
|
196
|
+
|
|
197
|
+
Key insights from this methodology:
|
|
198
|
+
1. Optimal spending starts low (~2-3%) and rises with age
|
|
199
|
+
2. Allocation should decrease as wealth approaches the floor
|
|
200
|
+
3. Risk aversion (gamma) is the critical input parameter
|
|
201
|
+
4. The 4% rule is suboptimal from a utility perspective
|
|
202
|
+
|
|
203
|
+
## Development
|
|
204
|
+
|
|
205
|
+
### Setup
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
git clone https://github.com/engineerinvestor/financial-health-calculator.git
|
|
209
|
+
cd financial-health-calculator
|
|
210
|
+
pip install -e ".[dev]"
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### Running Tests
|
|
214
|
+
|
|
215
|
+
```bash
|
|
216
|
+
pytest
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### Code Quality
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
ruff check .
|
|
223
|
+
mypy fundedness
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
## Project Structure
|
|
227
|
+
|
|
228
|
+
```
|
|
229
|
+
financial-health-calculator/
|
|
230
|
+
├── fundedness/ # Core Python package
|
|
231
|
+
│ ├── models/ # Pydantic data models
|
|
232
|
+
│ ├── viz/ # Plotly visualizations
|
|
233
|
+
│ ├── withdrawals/ # Withdrawal strategies (SWR, guardrails, VPW, Merton)
|
|
234
|
+
│ ├── allocation/ # Asset allocation strategies (constant, glidepath, Merton)
|
|
235
|
+
│ ├── cefr.py # CEFR calculation
|
|
236
|
+
│ ├── simulate.py # Monte Carlo engine with utility tracking
|
|
237
|
+
│ ├── merton.py # Merton optimal formulas
|
|
238
|
+
│ ├── optimize.py # Policy parameter optimization
|
|
239
|
+
│ └── policies.py # Spending/allocation policies
|
|
240
|
+
├── api/ # FastAPI REST API
|
|
241
|
+
├── streamlit_app/ # Streamlit web application
|
|
242
|
+
│ └── pages/ # Includes Utility Optimization page
|
|
243
|
+
├── examples/ # Jupyter notebooks
|
|
244
|
+
└── tests/ # pytest tests
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
## Contact
|
|
248
|
+
|
|
249
|
+
- Twitter: [@egr_investor](https://x.com/egr_investor)
|
|
250
|
+
- GitHub: [engineerinvestor](https://github.com/engineerinvestor)
|
|
251
|
+
- Email: egr.investor@gmail.com
|
|
252
|
+
|
|
253
|
+
## License
|
|
254
|
+
|
|
255
|
+
MIT License
|
|
256
|
+
|
|
257
|
+
## References
|
|
258
|
+
|
|
259
|
+
1. Haghani, V., & White, J. (2023). *The Missing Billionaires: A Guide to Better Financial Decisions*. Wiley. See also [Elm Wealth](https://elmwealth.com/) for related research on optimal spending and allocation.
|
|
260
|
+
|
|
261
|
+
2. Merton, R. C. (1969). Lifetime Portfolio Selection under Uncertainty: The Continuous-Time Case. *The Review of Economics and Statistics*, 51(3), 247-257.
|
|
262
|
+
|
|
263
|
+
## Disclaimer
|
|
264
|
+
|
|
265
|
+
This tool is for educational purposes only and does not constitute financial advice. Consult a qualified financial advisor for personalized recommendations.
|