fundedness 0.2.0__tar.gz → 0.2.2__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.
Potentially problematic release.
This version of fundedness might be problematic. Click here for more details.
- fundedness-0.2.2/CLAUDE.md +169 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/PKG-INFO +38 -4
- {fundedness-0.2.0 → fundedness-0.2.2}/README.md +37 -3
- {fundedness-0.2.0 → fundedness-0.2.2}/docs/guide/utility-optimization.md +18 -10
- fundedness-0.2.2/docs/javascripts/mathjax.js +19 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/fundedness/__init__.py +1 -1
- {fundedness-0.2.0 → fundedness-0.2.2}/mkdocs.yml +6 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/pyproject.toml +1 -1
- {fundedness-0.2.0 → fundedness-0.2.2}/streamlit_app/pages/5_Utility_Optimization.py +1 -1
- fundedness-0.2.0/CLAUDE.md +0 -98
- {fundedness-0.2.0 → fundedness-0.2.2}/.github/workflows/docs.yml +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/.github/workflows/publish.yml +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/.gitignore +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/api/__init__.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/api/main.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/api/routes/__init__.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/api/routes/cefr.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/api/routes/compare.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/api/routes/simulate.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/background_information.md +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/docs/api/core.md +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/docs/api/merton.md +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/docs/api/models.md +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/docs/api/viz.md +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/docs/api/withdrawals.md +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/docs/examples/tutorials.md +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/docs/getting-started/installation.md +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/docs/getting-started/quickstart.md +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/docs/guide/cefr.md +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/docs/guide/simulations.md +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/docs/guide/visualizations.md +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/docs/guide/withdrawals.md +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/docs/index.md +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/examples/01_cefr_basics.ipynb +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/examples/02_time_distribution.ipynb +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/examples/03_withdrawal_comparison.ipynb +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/fundedness/allocation/__init__.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/fundedness/allocation/base.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/fundedness/allocation/constant.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/fundedness/allocation/glidepath.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/fundedness/allocation/merton_optimal.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/fundedness/cefr.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/fundedness/liabilities.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/fundedness/liquidity.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/fundedness/merton.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/fundedness/models/__init__.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/fundedness/models/assets.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/fundedness/models/household.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/fundedness/models/liabilities.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/fundedness/models/market.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/fundedness/models/simulation.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/fundedness/models/tax.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/fundedness/models/utility.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/fundedness/optimize.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/fundedness/policies.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/fundedness/risk.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/fundedness/simulate.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/fundedness/viz/__init__.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/fundedness/viz/colors.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/fundedness/viz/comparison.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/fundedness/viz/fan_chart.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/fundedness/viz/histogram.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/fundedness/viz/optimal.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/fundedness/viz/survival.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/fundedness/viz/tornado.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/fundedness/viz/waterfall.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/fundedness/withdrawals/__init__.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/fundedness/withdrawals/base.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/fundedness/withdrawals/comparison.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/fundedness/withdrawals/fixed_swr.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/fundedness/withdrawals/guardrails.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/fundedness/withdrawals/merton_optimal.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/fundedness/withdrawals/rmd_style.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/fundedness/withdrawals/vpw.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/requirements.txt +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/streamlit_app/__init__.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/streamlit_app/app.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/streamlit_app/components/__init__.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/streamlit_app/components/asset_editor.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/streamlit_app/components/liability_editor.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/streamlit_app/components/metrics_display.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/streamlit_app/pages/0_Inputs.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/streamlit_app/pages/1_CEFR_Dashboard.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/streamlit_app/pages/2_Time_Runway.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/streamlit_app/pages/3_Withdrawal_Lab.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/streamlit_app/pages/4_Sensitivity.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/streamlit_app/utils/__init__.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/streamlit_app/utils/session_state.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/tests/__init__.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/tests/conftest.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/tests/test_api.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/tests/test_cefr.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/tests/test_liabilities.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/tests/test_merton.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/tests/test_optimize.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/tests/test_simulate.py +0 -0
- {fundedness-0.2.0 → fundedness-0.2.2}/tests/test_withdrawals.py +0 -0
|
@@ -0,0 +1,169 @@
|
|
|
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
|
+
- **Merton Optimal Policies**: 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, Merton optimal)
|
|
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 **actively developed** and published on PyPI as `fundedness`.
|
|
17
|
+
|
|
18
|
+
Current version: **0.2.x**
|
|
19
|
+
|
|
20
|
+
## Commands
|
|
21
|
+
|
|
22
|
+
- **Install**: `pip install fundedness` or `pip install "fundedness[all]"` for all extras
|
|
23
|
+
- **Testing**: `pytest` (runs 99+ tests)
|
|
24
|
+
- **Docs**: `mkdocs serve` (local) or auto-deployed to GitHub Pages
|
|
25
|
+
- **Streamlit**: `streamlit run streamlit_app/app.py`
|
|
26
|
+
- **API**: `uvicorn api.main:app --reload`
|
|
27
|
+
|
|
28
|
+
## Architecture
|
|
29
|
+
|
|
30
|
+
### Core Package Structure (`fundedness/`)
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
fundedness/
|
|
34
|
+
├── __init__.py # Package exports
|
|
35
|
+
├── cefr.py # CEFR ratio calculation with haircut breakdowns
|
|
36
|
+
├── liabilities.py # Liability PV calculations with schedules
|
|
37
|
+
├── liquidity.py # Liquidity factor adjustments
|
|
38
|
+
├── risk.py # Reliability/concentration haircuts
|
|
39
|
+
├── simulate.py # Monte Carlo engine with utility tracking
|
|
40
|
+
├── merton.py # Merton optimal formulas (allocation, spending, CE return)
|
|
41
|
+
├── optimize.py # Parametric policy optimization
|
|
42
|
+
├── policies.py # Spending/allocation policy interface
|
|
43
|
+
├── models/ # Pydantic data models
|
|
44
|
+
│ ├── assets.py
|
|
45
|
+
│ ├── household.py
|
|
46
|
+
│ ├── liabilities.py
|
|
47
|
+
│ ├── market.py
|
|
48
|
+
│ ├── simulation.py
|
|
49
|
+
│ ├── tax.py
|
|
50
|
+
│ └── utility.py
|
|
51
|
+
├── withdrawals/ # Withdrawal strategy implementations
|
|
52
|
+
│ ├── base.py
|
|
53
|
+
│ ├── fixed_swr.py
|
|
54
|
+
│ ├── guardrails.py
|
|
55
|
+
│ ├── vpw.py
|
|
56
|
+
│ ├── rmd_style.py
|
|
57
|
+
│ ├── merton_optimal.py
|
|
58
|
+
│ └── comparison.py
|
|
59
|
+
├── allocation/ # Asset allocation strategies
|
|
60
|
+
│ ├── base.py
|
|
61
|
+
│ ├── constant.py
|
|
62
|
+
│ ├── glidepath.py
|
|
63
|
+
│ └── merton_optimal.py
|
|
64
|
+
└── viz/ # Plotly visualizations
|
|
65
|
+
├── colors.py
|
|
66
|
+
├── fan_chart.py
|
|
67
|
+
├── waterfall.py
|
|
68
|
+
├── survival.py
|
|
69
|
+
├── comparison.py
|
|
70
|
+
├── optimal.py
|
|
71
|
+
└── ...
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Data Models (Pydantic)
|
|
75
|
+
|
|
76
|
+
Key models: `Household`, `BalanceSheet`, `Asset`, `Liability`, `MarketModel`, `TaxModel`, `UtilityModel`, `SimulationConfig`
|
|
77
|
+
|
|
78
|
+
### Core Formulas
|
|
79
|
+
|
|
80
|
+
**CEFR Calculation:**
|
|
81
|
+
```
|
|
82
|
+
CEFR = Σ(Asset × (1-tax_rate) × liquidity_factor × reliability_factor) / PV(Liabilities)
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
**Merton Optimal Allocation:**
|
|
86
|
+
```
|
|
87
|
+
k* = (μ - r) / (γ × σ²)
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
**Merton Optimal Spending Rate:**
|
|
91
|
+
```
|
|
92
|
+
c* = rce - (rce - ρ) / γ
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
**CRRA Utility with Floor:**
|
|
96
|
+
```
|
|
97
|
+
u(C) = (C - F)^(1-γ) / (1-γ) where C > F (subsistence floor)
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Key Concepts
|
|
101
|
+
|
|
102
|
+
- **Haircuts**: Three adjustments to assets—after-tax (τ), liquidity (λ), reliability (ρ)
|
|
103
|
+
- **Floor/Flex spending**: Essential spending floor vs adjustable discretionary
|
|
104
|
+
- **Time metrics**: Time-to-floor-breach, time-to-ruin, max spending drawdown
|
|
105
|
+
- **Confidence intervals**: Scenario percentiles (P10/P50/P90), not statistical CIs
|
|
106
|
+
- **Utility optimization**: Merton framework for optimal spending and allocation
|
|
107
|
+
|
|
108
|
+
## Default Haircut Assumptions
|
|
109
|
+
|
|
110
|
+
Liquidity: cash=1.0, taxable_index=0.95, retirement=0.85, home_equity=0.5, private_business=0.3
|
|
111
|
+
Reliability: diversified_bonds=0.95, diversified_equity=0.85, single_stock=0.60, startup=0.30
|
|
112
|
+
|
|
113
|
+
## Deployment
|
|
114
|
+
|
|
115
|
+
- **PyPI**: Published as `fundedness` - releases triggered by GitHub Release
|
|
116
|
+
- **Docs**: MkDocs Material deployed to GitHub Pages via `docs.yml` workflow
|
|
117
|
+
- **Web App**: Streamlit Cloud (free tier)
|
|
118
|
+
- **API**: FastAPI with endpoints in `api/`
|
|
119
|
+
|
|
120
|
+
## Visualization Standards
|
|
121
|
+
|
|
122
|
+
Use **Plotly** as the primary visualization library for beautiful, interactive charts:
|
|
123
|
+
- Clean, professional appearance with `template="plotly_white"`
|
|
124
|
+
- Interactive features: hover tooltips, zoom, pan
|
|
125
|
+
- Consistent color palette: blues (#3498db, #2980b9) for wealth, greens (#27ae60, #2ecc71) for spending/survival
|
|
126
|
+
- Fan charts with gradient opacity for percentile bands (P10-P90)
|
|
127
|
+
- Export capability to HTML/PNG for reports
|
|
128
|
+
|
|
129
|
+
## Documentation Notes
|
|
130
|
+
|
|
131
|
+
### LaTeX Equations in MkDocs
|
|
132
|
+
|
|
133
|
+
**Issue**: LaTeX equations using `$$...$$` syntax don't render in MkDocs Material.
|
|
134
|
+
|
|
135
|
+
**Solution**: Use `pymdownx.arithmatex` extension with MathJax:
|
|
136
|
+
|
|
137
|
+
1. In `mkdocs.yml`:
|
|
138
|
+
```yaml
|
|
139
|
+
markdown_extensions:
|
|
140
|
+
- pymdownx.arithmatex:
|
|
141
|
+
generic: true
|
|
142
|
+
|
|
143
|
+
extra_javascript:
|
|
144
|
+
- javascripts/mathjax.js
|
|
145
|
+
- https://unpkg.com/mathjax@3/es5/tex-mml-chtml.js
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
2. Create `docs/javascripts/mathjax.js`:
|
|
149
|
+
```javascript
|
|
150
|
+
window.MathJax = {
|
|
151
|
+
tex: {
|
|
152
|
+
inlineMath: [["\\(", "\\)"]],
|
|
153
|
+
displayMath: [["\\[", "\\]"]],
|
|
154
|
+
processEscapes: true,
|
|
155
|
+
processEnvironments: true
|
|
156
|
+
},
|
|
157
|
+
options: {
|
|
158
|
+
ignoreHtmlClass: ".*|",
|
|
159
|
+
processHtmlClass: "arithmatex"
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
3. Use `\[...\]` for display math and `\(...\)` for inline math in markdown files.
|
|
165
|
+
|
|
166
|
+
## References
|
|
167
|
+
|
|
168
|
+
- Merton, R.C. (1969). Lifetime Portfolio Selection under Uncertainty. *The Review of Economics and Statistics*, 51(3), 247-257.
|
|
169
|
+
- Haghani, V. & White, J. (2023). *The Missing Billionaires: A Guide to Better Financial Decisions*. Wiley.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fundedness
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: A Python financial planning toolkit with CEFR calculations, Monte Carlo simulations, and beautiful visualizations
|
|
5
5
|
Project-URL: Homepage, https://github.com/engineerinvestor/financial-health-calculator
|
|
6
6
|
Project-URL: Documentation, https://engineerinvestor.github.io/financial-health-calculator/
|
|
@@ -56,8 +56,6 @@ Description-Content-Type: text/markdown
|
|
|
56
56
|
|
|
57
57
|
[](https://pypi.org/project/fundedness/)
|
|
58
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
59
|
[](https://engineerinvestor.github.io/financial-health-calculator/)
|
|
62
60
|
[](https://opensource.org/licenses/MIT)
|
|
63
61
|
[](https://colab.research.google.com/github/engineerinvestor/financial-health-calculator/blob/main/examples/01_cefr_basics.ipynb)
|
|
@@ -69,7 +67,7 @@ A comprehensive Python financial planning toolkit with CEFR calculations, Monte
|
|
|
69
67
|
- **CEFR (Certainty-Equivalent Funded Ratio)**: A fundedness metric that accounts for taxes, liquidity, and concentration risk
|
|
70
68
|
- **Monte Carlo Simulations**: Project retirement outcomes with configurable market assumptions
|
|
71
69
|
- **Withdrawal Strategy Lab**: Compare strategies including fixed SWR, guardrails, VPW, RMD-style, and Merton optimal
|
|
72
|
-
- **Utility Optimization**:
|
|
70
|
+
- **Utility Optimization**: Merton optimal spending and allocation based on lifetime utility maximization
|
|
73
71
|
- **Beautiful Visualizations**: Interactive Plotly charts with fan charts, waterfalls, and survival curves
|
|
74
72
|
- **REST API**: FastAPI backend for programmatic access
|
|
75
73
|
- **Streamlit App**: User-friendly web interface
|
|
@@ -260,6 +258,42 @@ MIT License
|
|
|
260
258
|
|
|
261
259
|
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
260
|
|
|
261
|
+
## Citation
|
|
262
|
+
|
|
263
|
+
If you use this package in academic work, please cite:
|
|
264
|
+
|
|
265
|
+
```bibtex
|
|
266
|
+
@software{fundedness,
|
|
267
|
+
title = {Fundedness: A Python Financial Planning Toolkit},
|
|
268
|
+
author = {Engineer Investor},
|
|
269
|
+
year = {2024},
|
|
270
|
+
url = {https://github.com/engineerinvestor/financial-health-calculator},
|
|
271
|
+
version = {0.2.1}
|
|
272
|
+
}
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
For the underlying methodology, please also cite:
|
|
276
|
+
|
|
277
|
+
```bibtex
|
|
278
|
+
@article{merton1969lifetime,
|
|
279
|
+
title = {Lifetime Portfolio Selection under Uncertainty: The Continuous-Time Case},
|
|
280
|
+
author = {Merton, Robert C.},
|
|
281
|
+
journal = {The Review of Economics and Statistics},
|
|
282
|
+
volume = {51},
|
|
283
|
+
number = {3},
|
|
284
|
+
pages = {247--257},
|
|
285
|
+
year = {1969},
|
|
286
|
+
publisher = {MIT Press}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
@book{haghani2023missing,
|
|
290
|
+
title = {The Missing Billionaires: A Guide to Better Financial Decisions},
|
|
291
|
+
author = {Haghani, Victor and White, James},
|
|
292
|
+
year = {2023},
|
|
293
|
+
publisher = {Wiley}
|
|
294
|
+
}
|
|
295
|
+
```
|
|
296
|
+
|
|
263
297
|
## Disclaimer
|
|
264
298
|
|
|
265
299
|
This tool is for educational purposes only and does not constitute financial advice. Consult a qualified financial advisor for personalized recommendations.
|
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://pypi.org/project/fundedness/)
|
|
4
4
|
[](https://pypi.org/project/fundedness/)
|
|
5
|
-
[](https://github.com/engineerinvestor/financial-health-calculator/actions/workflows/ci.yml)
|
|
6
|
-
[](https://codecov.io/gh/engineerinvestor/financial-health-calculator)
|
|
7
5
|
[](https://engineerinvestor.github.io/financial-health-calculator/)
|
|
8
6
|
[](https://opensource.org/licenses/MIT)
|
|
9
7
|
[](https://colab.research.google.com/github/engineerinvestor/financial-health-calculator/blob/main/examples/01_cefr_basics.ipynb)
|
|
@@ -15,7 +13,7 @@ A comprehensive Python financial planning toolkit with CEFR calculations, Monte
|
|
|
15
13
|
- **CEFR (Certainty-Equivalent Funded Ratio)**: A fundedness metric that accounts for taxes, liquidity, and concentration risk
|
|
16
14
|
- **Monte Carlo Simulations**: Project retirement outcomes with configurable market assumptions
|
|
17
15
|
- **Withdrawal Strategy Lab**: Compare strategies including fixed SWR, guardrails, VPW, RMD-style, and Merton optimal
|
|
18
|
-
- **Utility Optimization**:
|
|
16
|
+
- **Utility Optimization**: Merton optimal spending and allocation based on lifetime utility maximization
|
|
19
17
|
- **Beautiful Visualizations**: Interactive Plotly charts with fan charts, waterfalls, and survival curves
|
|
20
18
|
- **REST API**: FastAPI backend for programmatic access
|
|
21
19
|
- **Streamlit App**: User-friendly web interface
|
|
@@ -206,6 +204,42 @@ MIT License
|
|
|
206
204
|
|
|
207
205
|
2. Merton, R. C. (1969). Lifetime Portfolio Selection under Uncertainty: The Continuous-Time Case. *The Review of Economics and Statistics*, 51(3), 247-257.
|
|
208
206
|
|
|
207
|
+
## Citation
|
|
208
|
+
|
|
209
|
+
If you use this package in academic work, please cite:
|
|
210
|
+
|
|
211
|
+
```bibtex
|
|
212
|
+
@software{fundedness,
|
|
213
|
+
title = {Fundedness: A Python Financial Planning Toolkit},
|
|
214
|
+
author = {Engineer Investor},
|
|
215
|
+
year = {2024},
|
|
216
|
+
url = {https://github.com/engineerinvestor/financial-health-calculator},
|
|
217
|
+
version = {0.2.1}
|
|
218
|
+
}
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
For the underlying methodology, please also cite:
|
|
222
|
+
|
|
223
|
+
```bibtex
|
|
224
|
+
@article{merton1969lifetime,
|
|
225
|
+
title = {Lifetime Portfolio Selection under Uncertainty: The Continuous-Time Case},
|
|
226
|
+
author = {Merton, Robert C.},
|
|
227
|
+
journal = {The Review of Economics and Statistics},
|
|
228
|
+
volume = {51},
|
|
229
|
+
number = {3},
|
|
230
|
+
pages = {247--257},
|
|
231
|
+
year = {1969},
|
|
232
|
+
publisher = {MIT Press}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
@book{haghani2023missing,
|
|
236
|
+
title = {The Missing Billionaires: A Guide to Better Financial Decisions},
|
|
237
|
+
author = {Haghani, Victor and White, James},
|
|
238
|
+
year = {2023},
|
|
239
|
+
publisher = {Wiley}
|
|
240
|
+
}
|
|
241
|
+
```
|
|
242
|
+
|
|
209
243
|
## Disclaimer
|
|
210
244
|
|
|
211
245
|
This tool is for educational purposes only and does not constitute financial advice. Consult a qualified financial advisor for personalized recommendations.
|
|
@@ -18,28 +18,34 @@ Utility optimization provides a rigorous framework for finding the **optimal** s
|
|
|
18
18
|
|
|
19
19
|
The Merton formula gives the optimal fraction to invest in risky assets:
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
\[
|
|
22
|
+
k^* = \frac{\mu - r}{\gamma \cdot \sigma^2}
|
|
23
|
+
\]
|
|
22
24
|
|
|
23
25
|
Where:
|
|
24
26
|
|
|
25
|
-
-
|
|
26
|
-
-
|
|
27
|
-
-
|
|
28
|
-
-
|
|
27
|
+
- \(\mu\) = expected stock return
|
|
28
|
+
- \(r\) = bond/risk-free return
|
|
29
|
+
- \(\gamma\) = risk aversion coefficient
|
|
30
|
+
- \(\sigma\) = stock volatility
|
|
29
31
|
|
|
30
32
|
### Certainty Equivalent Return
|
|
31
33
|
|
|
32
34
|
The guaranteed return that provides the same utility as the risky portfolio:
|
|
33
35
|
|
|
34
|
-
|
|
36
|
+
\[
|
|
37
|
+
r_{CE} = r + k^*(\mu - r) - \frac{\gamma \cdot (k^*)^2 \cdot \sigma^2}{2}
|
|
38
|
+
\]
|
|
35
39
|
|
|
36
40
|
### Optimal Spending Rate
|
|
37
41
|
|
|
38
42
|
For an infinite horizon:
|
|
39
43
|
|
|
40
|
-
|
|
44
|
+
\[
|
|
45
|
+
c^* = r_{CE} - \frac{r_{CE} - \rho}{\gamma}
|
|
46
|
+
\]
|
|
41
47
|
|
|
42
|
-
Where
|
|
48
|
+
Where \(\rho\) is your time preference (discount rate).
|
|
43
49
|
|
|
44
50
|
## Quick Start
|
|
45
51
|
|
|
@@ -82,9 +88,11 @@ print(f"Year 1 spending: ${1_000_000 * result.optimal_spending_rate:,.0f}")
|
|
|
82
88
|
|
|
83
89
|
Near the subsistence floor, you can't afford to take risk. The wealth-adjusted allocation accounts for this:
|
|
84
90
|
|
|
85
|
-
|
|
91
|
+
\[
|
|
92
|
+
k_{adj} = k^* \cdot \frac{W - F}{W}
|
|
93
|
+
\]
|
|
86
94
|
|
|
87
|
-
Where
|
|
95
|
+
Where \(W\) is wealth and \(F\) is the subsistence floor.
|
|
88
96
|
|
|
89
97
|
As wealth approaches the floor, allocation approaches zero. As wealth rises far above the floor, allocation approaches the unconstrained optimal.
|
|
90
98
|
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
window.MathJax = {
|
|
2
|
+
tex: {
|
|
3
|
+
inlineMath: [["\\(", "\\)"]],
|
|
4
|
+
displayMath: [["\\[", "\\]"]],
|
|
5
|
+
processEscapes: true,
|
|
6
|
+
processEnvironments: true
|
|
7
|
+
},
|
|
8
|
+
options: {
|
|
9
|
+
ignoreHtmlClass: ".*|",
|
|
10
|
+
processHtmlClass: "arithmatex"
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
document$.subscribe(() => {
|
|
15
|
+
MathJax.startup.output.clearCache()
|
|
16
|
+
MathJax.typesetClear()
|
|
17
|
+
MathJax.texReset()
|
|
18
|
+
MathJax.typesetPromise()
|
|
19
|
+
})
|
|
@@ -46,6 +46,12 @@ nav:
|
|
|
46
46
|
markdown_extensions:
|
|
47
47
|
- pymdownx.highlight
|
|
48
48
|
- pymdownx.superfences
|
|
49
|
+
- pymdownx.arithmatex:
|
|
50
|
+
generic: true
|
|
49
51
|
- admonition
|
|
50
52
|
- toc:
|
|
51
53
|
permalink: true
|
|
54
|
+
|
|
55
|
+
extra_javascript:
|
|
56
|
+
- javascripts/mathjax.js
|
|
57
|
+
- https://unpkg.com/mathjax@3/es5/tex-mml-chtml.js
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "fundedness"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.2"
|
|
8
8
|
description = "A Python financial planning toolkit with CEFR calculations, Monte Carlo simulations, and beautiful visualizations"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
fundedness-0.2.0/CLAUDE.md
DELETED
|
@@ -1,98 +0,0 @@
|
|
|
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
|
|
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
|