fundedness 0.1.0__py3-none-any.whl → 0.2.1__py3-none-any.whl
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/__init__.py +34 -1
- fundedness/allocation/__init__.py +8 -0
- fundedness/allocation/merton_optimal.py +220 -0
- fundedness/merton.py +289 -0
- fundedness/optimize.py +473 -0
- fundedness/simulate.py +158 -0
- fundedness/viz/__init__.py +14 -0
- fundedness/viz/optimal.py +542 -0
- fundedness/withdrawals/__init__.py +8 -0
- fundedness/withdrawals/fixed_swr.py +61 -0
- fundedness/withdrawals/merton_optimal.py +286 -0
- {fundedness-0.1.0.dist-info → fundedness-0.2.1.dist-info}/METADATA +41 -9
- {fundedness-0.1.0.dist-info → fundedness-0.2.1.dist-info}/RECORD +15 -10
- {fundedness-0.1.0.dist-info → fundedness-0.2.1.dist-info}/WHEEL +0 -0
- {fundedness-0.1.0.dist-info → fundedness-0.2.1.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
"""Merton optimal spending policy based on utility maximization."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
|
|
7
|
+
from fundedness.merton import (
|
|
8
|
+
merton_optimal_spending_rate,
|
|
9
|
+
certainty_equivalent_return,
|
|
10
|
+
)
|
|
11
|
+
from fundedness.models.market import MarketModel
|
|
12
|
+
from fundedness.models.utility import UtilityModel
|
|
13
|
+
from fundedness.withdrawals.base import (
|
|
14
|
+
BaseWithdrawalPolicy,
|
|
15
|
+
WithdrawalContext,
|
|
16
|
+
WithdrawalDecision,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@dataclass
|
|
21
|
+
class MertonOptimalSpendingPolicy(BaseWithdrawalPolicy):
|
|
22
|
+
"""Spending policy based on Merton optimal consumption theory.
|
|
23
|
+
|
|
24
|
+
This policy determines spending by applying the Merton optimal spending
|
|
25
|
+
rate to current wealth, adjusted for the remaining time horizon.
|
|
26
|
+
|
|
27
|
+
Key characteristics:
|
|
28
|
+
- Spending rate starts low (~2-3%) and rises with age
|
|
29
|
+
- Rate depends on risk aversion, time preference, and market assumptions
|
|
30
|
+
- Adapts to actual wealth (not locked to initial withdrawal amount)
|
|
31
|
+
- Optional smoothing to reduce year-to-year volatility
|
|
32
|
+
|
|
33
|
+
Attributes:
|
|
34
|
+
market_model: Market return and risk assumptions
|
|
35
|
+
utility_model: Utility parameters including risk aversion
|
|
36
|
+
starting_age: Age at retirement/simulation start
|
|
37
|
+
end_age: Assumed maximum age for planning
|
|
38
|
+
smoothing_factor: Blend current with previous spending (0-1, 0=no smoothing)
|
|
39
|
+
min_spending_rate: Minimum spending rate floor
|
|
40
|
+
max_spending_rate: Maximum spending rate ceiling
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
market_model: MarketModel = field(default_factory=MarketModel)
|
|
44
|
+
utility_model: UtilityModel = field(default_factory=UtilityModel)
|
|
45
|
+
starting_age: int = 65
|
|
46
|
+
end_age: int = 100
|
|
47
|
+
smoothing_factor: float = 0.5
|
|
48
|
+
min_spending_rate: float = 0.02
|
|
49
|
+
max_spending_rate: float = 0.15
|
|
50
|
+
|
|
51
|
+
@property
|
|
52
|
+
def name(self) -> str:
|
|
53
|
+
return "Merton Optimal"
|
|
54
|
+
|
|
55
|
+
@property
|
|
56
|
+
def description(self) -> str:
|
|
57
|
+
gamma = self.utility_model.gamma
|
|
58
|
+
return f"Utility-optimal spending (gamma={gamma})"
|
|
59
|
+
|
|
60
|
+
def get_optimal_rate(self, remaining_years: float) -> float:
|
|
61
|
+
"""Get the optimal spending rate for given remaining years.
|
|
62
|
+
|
|
63
|
+
Args:
|
|
64
|
+
remaining_years: Years until end of planning horizon
|
|
65
|
+
|
|
66
|
+
Returns:
|
|
67
|
+
Optimal spending rate as decimal
|
|
68
|
+
"""
|
|
69
|
+
rate = merton_optimal_spending_rate(
|
|
70
|
+
market_model=self.market_model,
|
|
71
|
+
utility_model=self.utility_model,
|
|
72
|
+
remaining_years=remaining_years,
|
|
73
|
+
)
|
|
74
|
+
return np.clip(rate, self.min_spending_rate, self.max_spending_rate)
|
|
75
|
+
|
|
76
|
+
def calculate_withdrawal(self, context: WithdrawalContext) -> WithdrawalDecision:
|
|
77
|
+
"""Calculate withdrawal using Merton optimal spending rate.
|
|
78
|
+
|
|
79
|
+
Args:
|
|
80
|
+
context: Current state information
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
WithdrawalDecision with amount and metadata
|
|
84
|
+
"""
|
|
85
|
+
# Determine current age
|
|
86
|
+
if context.age is not None:
|
|
87
|
+
current_age = context.age
|
|
88
|
+
else:
|
|
89
|
+
current_age = self.starting_age + context.year
|
|
90
|
+
|
|
91
|
+
remaining_years = max(1, self.end_age - current_age)
|
|
92
|
+
|
|
93
|
+
# Get optimal spending rate
|
|
94
|
+
rate = self.get_optimal_rate(remaining_years)
|
|
95
|
+
|
|
96
|
+
# Handle vectorized wealth
|
|
97
|
+
if isinstance(context.current_wealth, np.ndarray):
|
|
98
|
+
wealth = context.current_wealth
|
|
99
|
+
else:
|
|
100
|
+
wealth = context.current_wealth
|
|
101
|
+
|
|
102
|
+
# Calculate raw spending
|
|
103
|
+
raw_spending = wealth * rate
|
|
104
|
+
|
|
105
|
+
# Apply smoothing if we have previous spending
|
|
106
|
+
if self.smoothing_factor > 0 and context.previous_spending is not None:
|
|
107
|
+
# Adjust previous spending for inflation
|
|
108
|
+
prev_real = context.previous_spending / context.inflation_cumulative
|
|
109
|
+
smoothed = (
|
|
110
|
+
self.smoothing_factor * prev_real * context.inflation_cumulative
|
|
111
|
+
+ (1 - self.smoothing_factor) * raw_spending
|
|
112
|
+
)
|
|
113
|
+
spending = smoothed
|
|
114
|
+
else:
|
|
115
|
+
spending = raw_spending
|
|
116
|
+
|
|
117
|
+
# Apply guardrails
|
|
118
|
+
amount, is_floor_breach, is_ceiling_hit = self.apply_guardrails(
|
|
119
|
+
spending, context.current_wealth
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
return WithdrawalDecision(
|
|
123
|
+
amount=amount,
|
|
124
|
+
is_floor_breach=is_floor_breach,
|
|
125
|
+
is_ceiling_hit=is_ceiling_hit,
|
|
126
|
+
notes=f"Rate: {rate:.1%}, Remaining: {remaining_years}y",
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
def get_initial_withdrawal(self, initial_wealth: float) -> float:
|
|
130
|
+
"""Calculate first year withdrawal.
|
|
131
|
+
|
|
132
|
+
Args:
|
|
133
|
+
initial_wealth: Starting portfolio value
|
|
134
|
+
|
|
135
|
+
Returns:
|
|
136
|
+
First year withdrawal amount
|
|
137
|
+
"""
|
|
138
|
+
remaining_years = self.end_age - self.starting_age
|
|
139
|
+
rate = self.get_optimal_rate(remaining_years)
|
|
140
|
+
return initial_wealth * rate
|
|
141
|
+
|
|
142
|
+
def get_spending(
|
|
143
|
+
self,
|
|
144
|
+
wealth: np.ndarray,
|
|
145
|
+
year: int,
|
|
146
|
+
initial_wealth: float,
|
|
147
|
+
) -> np.ndarray:
|
|
148
|
+
"""Get spending for simulation (vectorized interface).
|
|
149
|
+
|
|
150
|
+
This method is used by the Monte Carlo simulation engine.
|
|
151
|
+
|
|
152
|
+
Args:
|
|
153
|
+
wealth: Current portfolio values (n_simulations,)
|
|
154
|
+
year: Current simulation year
|
|
155
|
+
initial_wealth: Starting portfolio value
|
|
156
|
+
|
|
157
|
+
Returns:
|
|
158
|
+
Spending amounts for each simulation path
|
|
159
|
+
"""
|
|
160
|
+
current_age = self.starting_age + year
|
|
161
|
+
remaining_years = max(1, self.end_age - current_age)
|
|
162
|
+
rate = self.get_optimal_rate(remaining_years)
|
|
163
|
+
|
|
164
|
+
spending = wealth * rate
|
|
165
|
+
|
|
166
|
+
# Ensure non-negative and bounded by wealth
|
|
167
|
+
spending = np.maximum(spending, 0)
|
|
168
|
+
spending = np.minimum(spending, np.maximum(wealth, 0))
|
|
169
|
+
|
|
170
|
+
# Apply floor if set
|
|
171
|
+
if self.floor_spending is not None:
|
|
172
|
+
spending = np.maximum(spending, self.floor_spending)
|
|
173
|
+
# But still can't spend more than we have
|
|
174
|
+
spending = np.minimum(spending, np.maximum(wealth, 0))
|
|
175
|
+
|
|
176
|
+
return spending
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
@dataclass
|
|
180
|
+
class SmoothedMertonPolicy(MertonOptimalSpendingPolicy):
|
|
181
|
+
"""Merton optimal with aggressive smoothing for stable spending.
|
|
182
|
+
|
|
183
|
+
This variant applies stronger smoothing to reduce spending volatility,
|
|
184
|
+
trading off some optimality for a more stable spending experience.
|
|
185
|
+
"""
|
|
186
|
+
|
|
187
|
+
smoothing_factor: float = 0.7
|
|
188
|
+
adaptation_rate: float = 0.1
|
|
189
|
+
|
|
190
|
+
@property
|
|
191
|
+
def name(self) -> str:
|
|
192
|
+
return "Smoothed Merton"
|
|
193
|
+
|
|
194
|
+
@property
|
|
195
|
+
def description(self) -> str:
|
|
196
|
+
return "Merton optimal with spending smoothing"
|
|
197
|
+
|
|
198
|
+
def get_spending(
|
|
199
|
+
self,
|
|
200
|
+
wealth: np.ndarray,
|
|
201
|
+
year: int,
|
|
202
|
+
initial_wealth: float,
|
|
203
|
+
) -> np.ndarray:
|
|
204
|
+
"""Get smoothed spending for simulation.
|
|
205
|
+
|
|
206
|
+
Uses exponential smoothing of the optimal spending amount.
|
|
207
|
+
|
|
208
|
+
Args:
|
|
209
|
+
wealth: Current portfolio values
|
|
210
|
+
year: Current simulation year
|
|
211
|
+
initial_wealth: Starting portfolio value
|
|
212
|
+
|
|
213
|
+
Returns:
|
|
214
|
+
Smoothed spending amounts
|
|
215
|
+
"""
|
|
216
|
+
# Get raw Merton optimal spending
|
|
217
|
+
current_age = self.starting_age + year
|
|
218
|
+
remaining_years = max(1, self.end_age - current_age)
|
|
219
|
+
rate = self.get_optimal_rate(remaining_years)
|
|
220
|
+
|
|
221
|
+
optimal_spending = wealth * rate
|
|
222
|
+
|
|
223
|
+
# For first year or if tracking isn't set up, use optimal directly
|
|
224
|
+
# In practice, smoothing would be applied via simulation state
|
|
225
|
+
spending = optimal_spending
|
|
226
|
+
|
|
227
|
+
# Apply floor if set
|
|
228
|
+
if self.floor_spending is not None:
|
|
229
|
+
spending = np.maximum(spending, self.floor_spending)
|
|
230
|
+
spending = np.minimum(spending, np.maximum(wealth, 0))
|
|
231
|
+
|
|
232
|
+
return spending
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
@dataclass
|
|
236
|
+
class FloorAdjustedMertonPolicy(MertonOptimalSpendingPolicy):
|
|
237
|
+
"""Merton optimal that accounts for subsistence floor in spending.
|
|
238
|
+
|
|
239
|
+
This variant only applies the optimal rate to wealth above the
|
|
240
|
+
floor-supporting level, ensuring floor spending is always protected.
|
|
241
|
+
"""
|
|
242
|
+
|
|
243
|
+
years_of_floor_to_protect: int = 5
|
|
244
|
+
|
|
245
|
+
@property
|
|
246
|
+
def name(self) -> str:
|
|
247
|
+
return "Floor-Protected Merton"
|
|
248
|
+
|
|
249
|
+
@property
|
|
250
|
+
def description(self) -> str:
|
|
251
|
+
return f"Merton optimal protecting {self.years_of_floor_to_protect}y floor"
|
|
252
|
+
|
|
253
|
+
def get_spending(
|
|
254
|
+
self,
|
|
255
|
+
wealth: np.ndarray,
|
|
256
|
+
year: int,
|
|
257
|
+
initial_wealth: float,
|
|
258
|
+
) -> np.ndarray:
|
|
259
|
+
"""Get spending that protects floor for several years.
|
|
260
|
+
|
|
261
|
+
Args:
|
|
262
|
+
wealth: Current portfolio values
|
|
263
|
+
year: Current simulation year
|
|
264
|
+
initial_wealth: Starting portfolio value
|
|
265
|
+
|
|
266
|
+
Returns:
|
|
267
|
+
Floor-protected spending amounts
|
|
268
|
+
"""
|
|
269
|
+
current_age = self.starting_age + year
|
|
270
|
+
remaining_years = max(1, self.end_age - current_age)
|
|
271
|
+
rate = self.get_optimal_rate(remaining_years)
|
|
272
|
+
|
|
273
|
+
floor = self.utility_model.subsistence_floor
|
|
274
|
+
protected_wealth = floor * self.years_of_floor_to_protect
|
|
275
|
+
|
|
276
|
+
# Only apply rate to wealth above protected level
|
|
277
|
+
excess_wealth = np.maximum(wealth - protected_wealth, 0)
|
|
278
|
+
flex_spending = excess_wealth * rate
|
|
279
|
+
|
|
280
|
+
# Total spending = floor + flexible portion
|
|
281
|
+
spending = floor + flex_spending
|
|
282
|
+
|
|
283
|
+
# Can't spend more than we have
|
|
284
|
+
spending = np.minimum(spending, np.maximum(wealth, 0))
|
|
285
|
+
|
|
286
|
+
return spending
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fundedness
|
|
3
|
-
Version: 0.1
|
|
3
|
+
Version: 0.2.1
|
|
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/
|
|
@@ -54,15 +54,22 @@ Description-Content-Type: text/markdown
|
|
|
54
54
|
|
|
55
55
|
# Financial Health Calculator
|
|
56
56
|
|
|
57
|
-
|
|
58
|
-
|
|
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)
|
|
59
63
|
[](https://colab.research.google.com/github/engineerinvestor/financial-health-calculator/blob/main/examples/01_cefr_basics.ipynb)
|
|
60
64
|
|
|
65
|
+
A comprehensive Python financial planning toolkit with CEFR calculations, Monte Carlo simulations, and beautiful Plotly visualizations.
|
|
66
|
+
|
|
61
67
|
## Features
|
|
62
68
|
|
|
63
69
|
- **CEFR (Certainty-Equivalent Funded Ratio)**: A fundedness metric that accounts for taxes, liquidity, and concentration risk
|
|
64
70
|
- **Monte Carlo Simulations**: Project retirement outcomes with configurable market assumptions
|
|
65
|
-
- **Withdrawal Strategy Lab**: Compare strategies including fixed SWR, guardrails, VPW,
|
|
71
|
+
- **Withdrawal Strategy Lab**: Compare strategies including fixed SWR, guardrails, VPW, RMD-style, and Merton optimal
|
|
72
|
+
- **Utility Optimization**: Merton optimal spending and allocation based on lifetime utility maximization
|
|
66
73
|
- **Beautiful Visualizations**: Interactive Plotly charts with fan charts, waterfalls, and survival curves
|
|
67
74
|
- **REST API**: FastAPI backend for programmatic access
|
|
68
75
|
- **Streamlit App**: User-friendly web interface
|
|
@@ -72,12 +79,12 @@ A comprehensive Python financial planning toolkit with CEFR calculations, Monte
|
|
|
72
79
|
### Installation
|
|
73
80
|
|
|
74
81
|
```bash
|
|
75
|
-
pip install
|
|
82
|
+
pip install fundedness
|
|
76
83
|
```
|
|
77
84
|
|
|
78
85
|
For development with all extras:
|
|
79
86
|
```bash
|
|
80
|
-
pip install "
|
|
87
|
+
pip install "fundedness[all]"
|
|
81
88
|
```
|
|
82
89
|
|
|
83
90
|
### Basic Usage
|
|
@@ -176,6 +183,22 @@ Where τ = tax rate, λ = liquidity factor, ρ = reliability factor
|
|
|
176
183
|
| Guardrails | Adjustable with floor/ceiling | Balance |
|
|
177
184
|
| VPW | Age-based variable percentage | Maximizing spending |
|
|
178
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
|
|
179
202
|
|
|
180
203
|
## Development
|
|
181
204
|
|
|
@@ -207,13 +230,16 @@ financial-health-calculator/
|
|
|
207
230
|
├── fundedness/ # Core Python package
|
|
208
231
|
│ ├── models/ # Pydantic data models
|
|
209
232
|
│ ├── viz/ # Plotly visualizations
|
|
210
|
-
│ ├── withdrawals/ # Withdrawal strategies
|
|
211
|
-
│ ├── allocation/ # Asset allocation strategies
|
|
233
|
+
│ ├── withdrawals/ # Withdrawal strategies (SWR, guardrails, VPW, Merton)
|
|
234
|
+
│ ├── allocation/ # Asset allocation strategies (constant, glidepath, Merton)
|
|
212
235
|
│ ├── cefr.py # CEFR calculation
|
|
213
|
-
│ ├── simulate.py # Monte Carlo engine
|
|
236
|
+
│ ├── simulate.py # Monte Carlo engine with utility tracking
|
|
237
|
+
│ ├── merton.py # Merton optimal formulas
|
|
238
|
+
│ ├── optimize.py # Policy parameter optimization
|
|
214
239
|
│ └── policies.py # Spending/allocation policies
|
|
215
240
|
├── api/ # FastAPI REST API
|
|
216
241
|
├── streamlit_app/ # Streamlit web application
|
|
242
|
+
│ └── pages/ # Includes Utility Optimization page
|
|
217
243
|
├── examples/ # Jupyter notebooks
|
|
218
244
|
└── tests/ # pytest tests
|
|
219
245
|
```
|
|
@@ -228,6 +254,12 @@ financial-health-calculator/
|
|
|
228
254
|
|
|
229
255
|
MIT License
|
|
230
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
|
+
|
|
231
263
|
## Disclaimer
|
|
232
264
|
|
|
233
265
|
This tool is for educational purposes only and does not constitute financial advice. Consult a qualified financial advisor for personalized recommendations.
|
|
@@ -1,14 +1,17 @@
|
|
|
1
|
-
fundedness/__init__.py,sha256=
|
|
1
|
+
fundedness/__init__.py,sha256=7cGKTGVcoHzzjwZDy5yZ0N1bmDAXCFjWjf133dlVknQ,1678
|
|
2
2
|
fundedness/cefr.py,sha256=hCImRrjz-DCPJsuF3HShDZK5tw1vslakh-DrNBHsh2k,7728
|
|
3
3
|
fundedness/liabilities.py,sha256=uKvEV6JQnQdrd7b6VsCc2qf9S2DJdK0XhEX9qwca2Ws,6662
|
|
4
4
|
fundedness/liquidity.py,sha256=ncZF70AfgoVoYZnozpA_CHemfaHmI4KKCe3vITp5ljM,1713
|
|
5
|
+
fundedness/merton.py,sha256=VUKVxkNimoI0gsQJROb1wrO-SW4ubiNvcYDL2aH69AU,9218
|
|
6
|
+
fundedness/optimize.py,sha256=21ksSkNgtDY_UGTub0KRlIvfaFA363csfSfHnLJrmJs,15567
|
|
5
7
|
fundedness/policies.py,sha256=pyIYz86Z3sMYAW2rNhPLnXQ3PQCDCa-oxf9NhWyawy8,5854
|
|
6
8
|
fundedness/risk.py,sha256=Lpls6Q2wVq5SX4p9ZQwCtTM73AcqrGCm3hE2QcgKuq0,2750
|
|
7
|
-
fundedness/simulate.py,sha256=
|
|
8
|
-
fundedness/allocation/__init__.py,sha256=
|
|
9
|
+
fundedness/simulate.py,sha256=A0_ZScMTF8YJcjVHys_nmxMG4x-c81sU_W8iMApscNE,19678
|
|
10
|
+
fundedness/allocation/__init__.py,sha256=5p85uRFltSfEwXjengr56FNY1s4KvcMMxuH05I_Omfs,677
|
|
9
11
|
fundedness/allocation/base.py,sha256=kDypu2t86fsn2DyL5an1fPjbPbQWNmqydz3axWUgjLI,763
|
|
10
12
|
fundedness/allocation/constant.py,sha256=6QcUJ0aBQcJcRJtOMhs7uUu13wJtgcPU7ToQzQZhcgw,531
|
|
11
13
|
fundedness/allocation/glidepath.py,sha256=-q6Jb5WpRuZjJ68akT5WgeRIx3QSIDtlNih0_Iz-_cc,3440
|
|
14
|
+
fundedness/allocation/merton_optimal.py,sha256=krRd7sKbvXXxfewLJuF9RWbMLYUHbehvdbdYSjwnczk,7702
|
|
12
15
|
fundedness/models/__init__.py,sha256=EyW6tGUI9T6QMbIfzsG3igqg5--DtZHSTAuMX6foOiA,874
|
|
13
16
|
fundedness/models/assets.py,sha256=ZKgxl4YaqdRVfDErL9weRhh4St_azo8ruN4g15T3IsQ,5013
|
|
14
17
|
fundedness/models/household.py,sha256=t64FjvO0uQJemddLtCPpK3NNYdZCXU6KjA1VZshaqEk,4671
|
|
@@ -17,22 +20,24 @@ fundedness/models/market.py,sha256=c3jskREsB7m_mjzuBwJ7oo6hlvLmR423t0JT8_a50eg,5
|
|
|
17
20
|
fundedness/models/simulation.py,sha256=0jtIJWISDL-TlKVjr6KxcRfAj5Mrbp-VNyA4Bu7IUfU,2224
|
|
18
21
|
fundedness/models/tax.py,sha256=0XhoBNZqfRqF1_acakrkYgMS5L6Pknq-TloQQBrFw1U,3859
|
|
19
22
|
fundedness/models/utility.py,sha256=0AoJdccTb2hKBrTz5LExm8SrSsaWhhBf7y2NNaUzWQ0,4678
|
|
20
|
-
fundedness/viz/__init__.py,sha256=
|
|
23
|
+
fundedness/viz/__init__.py,sha256=Om8qlI13w13MfDmyB_xeR6hgr7LpWX1tjAf_x3eDbEQ,1168
|
|
21
24
|
fundedness/viz/colors.py,sha256=kbYyCLvLARoIAMztHjnJZDxMGF9-an5z4obORa6JFEU,3204
|
|
22
25
|
fundedness/viz/comparison.py,sha256=DoQW6xr0r2ko55qyli4ue8ndj__opun97brbbHSnKVA,8530
|
|
23
26
|
fundedness/viz/fan_chart.py,sha256=GqdrOKdW12K7Y8sFQJ853QbYG3ASxvEzfY9cC-EKK70,6102
|
|
24
27
|
fundedness/viz/histogram.py,sha256=i56g330-S84WxUU8GGya40yNUQbnAI2D0vzUbFy51DI,6784
|
|
28
|
+
fundedness/viz/optimal.py,sha256=w5vI2O-4O6F1Dobsfg55pznlfD100SRnSgZqLIpcT9c,16056
|
|
25
29
|
fundedness/viz/survival.py,sha256=xtaAHkJ3jlTUCYnLrTvwWlOlfLao6NC5cRxT5XKWrxM,6515
|
|
26
30
|
fundedness/viz/tornado.py,sha256=1dZzAfKTDCcyyfbDUBE39f44e6k48yviF8kTRee-pwQ,6684
|
|
27
31
|
fundedness/viz/waterfall.py,sha256=6LD0SbZDUzJrA0Zh1Y1qDx0I4BM5ZN_f2eVCXNK5HRc,5586
|
|
28
|
-
fundedness/withdrawals/__init__.py,sha256=
|
|
32
|
+
fundedness/withdrawals/__init__.py,sha256=FiXfK7QBzUp4Iwf25VK0jbZyguF8bLlZAWWMjg8tFPo,886
|
|
29
33
|
fundedness/withdrawals/base.py,sha256=WXBuo-tJtp4V2Ottp2PC2YtyK3mGVJ9Cgq21zGUWObg,3472
|
|
30
34
|
fundedness/withdrawals/comparison.py,sha256=eiobGMHmeQpGnr0_HcY_EKrv5_Nu7EaVf5Y9DdDNAyg,7833
|
|
31
|
-
fundedness/withdrawals/fixed_swr.py,sha256=
|
|
35
|
+
fundedness/withdrawals/fixed_swr.py,sha256=2ZgkQ_xZakpcdZQIop46TAFML7ESz7nyTVdVfI-1Z18,5469
|
|
32
36
|
fundedness/withdrawals/guardrails.py,sha256=rZKVojKbl9LLJLi9LlK1I2JXb537MN_AbZfn4hIU8is,5468
|
|
37
|
+
fundedness/withdrawals/merton_optimal.py,sha256=mSxRAKGx8sr_YdlhQMtIvnojqfuG0MiYtBp18xboLHs,9269
|
|
33
38
|
fundedness/withdrawals/rmd_style.py,sha256=E5FfrUYxFJwULKxzxbtZFLoLspLzUUomTQRUWLGLDpg,6373
|
|
34
39
|
fundedness/withdrawals/vpw.py,sha256=aajHLAkHfsxh33uGRgzv0ozVuZREG-EmARJgWOU6mis,4389
|
|
35
|
-
fundedness-0.1.
|
|
36
|
-
fundedness-0.1.
|
|
37
|
-
fundedness-0.1.
|
|
38
|
-
fundedness-0.1.
|
|
40
|
+
fundedness-0.2.1.dist-info/METADATA,sha256=Lg-LFdrLs2mcL9oyBjk3-X1qt9bB7U-K01zFHJXY6eI,10381
|
|
41
|
+
fundedness-0.2.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
42
|
+
fundedness-0.2.1.dist-info/entry_points.txt,sha256=Oh-Hg08i044YHuSHViCdfoD8CenIGcKrVuUVysvN9sY,51
|
|
43
|
+
fundedness-0.2.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|