Withdrawal Policies¶
Classes implementing different withdrawal strategies.
Base Policy¶
fundedness.withdrawals.base.WithdrawalPolicy
¶
Bases: Protocol
Protocol defining the interface for withdrawal strategies.
Source code in fundedness/withdrawals/base.py
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | |
description
property
¶
Brief description of how the strategy works.
name
property
¶
Human-readable name for the strategy.
calculate_withdrawal(context)
¶
Calculate the withdrawal amount for the given context.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
context
|
WithdrawalContext
|
Current state information |
required |
Returns:
| Type | Description |
|---|---|
WithdrawalDecision
|
WithdrawalDecision with amount and metadata |
Source code in fundedness/withdrawals/base.py
45 46 47 48 49 50 51 52 53 54 | |
get_initial_withdrawal(initial_wealth)
¶
Calculate the first year's withdrawal.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
initial_wealth
|
float
|
Starting portfolio value |
required |
Returns:
| Type | Description |
|---|---|
float
|
First year withdrawal amount |
Source code in fundedness/withdrawals/base.py
56 57 58 59 60 61 62 63 64 65 | |
fundedness.withdrawals.base.BaseWithdrawalPolicy
dataclass
¶
Base class with common functionality for withdrawal policies.
Source code in fundedness/withdrawals/base.py
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 | |
apply_guardrails(amount, wealth)
¶
Apply floor and ceiling guardrails to withdrawal amount.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
amount
|
float | ndarray
|
Proposed withdrawal amount |
required |
wealth
|
float | ndarray
|
Current wealth |
required |
Returns:
| Type | Description |
|---|---|
tuple[float | ndarray, bool | ndarray, bool | ndarray]
|
Tuple of (adjusted_amount, is_floor_breach, is_ceiling_hit) |
Source code in fundedness/withdrawals/base.py
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 | |
Fixed SWR¶
fundedness.withdrawals.fixed_swr.FixedRealSWRPolicy
dataclass
¶
Bases: BaseWithdrawalPolicy
Classic fixed real (inflation-adjusted) withdrawal strategy.
The "4% rule" approach: withdraw a fixed percentage of initial portfolio, then adjust for inflation each year.
Source code in fundedness/withdrawals/fixed_swr.py
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | |
calculate_withdrawal(context)
¶
Calculate inflation-adjusted withdrawal.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
context
|
WithdrawalContext
|
Current state including initial wealth and year |
required |
Returns:
| Type | Description |
|---|---|
WithdrawalDecision
|
WithdrawalDecision with fixed real amount |
Source code in fundedness/withdrawals/fixed_swr.py
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | |
get_initial_withdrawal(initial_wealth)
¶
Calculate first year withdrawal.
Source code in fundedness/withdrawals/fixed_swr.py
36 37 38 | |
get_spending(wealth, year, initial_wealth)
¶
Get spending for simulation (vectorized interface).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
wealth
|
ndarray
|
Current portfolio values (n_simulations,) |
required |
year
|
int
|
Current simulation year |
required |
initial_wealth
|
float
|
Starting portfolio value |
required |
Returns:
| Type | Description |
|---|---|
ndarray
|
Spending amounts for each simulation path |
Source code in fundedness/withdrawals/fixed_swr.py
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | |
Percentage of Portfolio¶
fundedness.withdrawals.fixed_swr.PercentOfPortfolioPolicy
dataclass
¶
Bases: BaseWithdrawalPolicy
Withdraw a fixed percentage of current portfolio value each year.
More volatile than fixed SWR but automatically adjusts to portfolio performance.
Source code in fundedness/withdrawals/fixed_swr.py
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 | |
calculate_withdrawal(context)
¶
Calculate percentage-of-portfolio withdrawal.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
context
|
WithdrawalContext
|
Current state including current wealth |
required |
Returns:
| Type | Description |
|---|---|
WithdrawalDecision
|
WithdrawalDecision based on current portfolio value |
Source code in fundedness/withdrawals/fixed_swr.py
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 | |
get_initial_withdrawal(initial_wealth)
¶
Calculate first year withdrawal.
Source code in fundedness/withdrawals/fixed_swr.py
119 120 121 | |
get_spending(wealth, year, initial_wealth)
¶
Get spending for simulation (vectorized interface).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
wealth
|
ndarray
|
Current portfolio values (n_simulations,) |
required |
year
|
int
|
Current simulation year |
required |
initial_wealth
|
float
|
Starting portfolio value |
required |
Returns:
| Type | Description |
|---|---|
ndarray
|
Spending amounts for each simulation path |
Source code in fundedness/withdrawals/fixed_swr.py
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 | |
Guardrails¶
fundedness.withdrawals.guardrails.GuardrailsPolicy
dataclass
¶
Bases: BaseWithdrawalPolicy
Guyton-Klinger style guardrails withdrawal strategy.
Start with initial withdrawal rate, then adjust based on portfolio performance: - If withdrawal rate rises above upper guardrail, cut spending - If withdrawal rate falls below lower guardrail, increase spending - Otherwise, adjust previous spending for inflation
Source code in fundedness/withdrawals/guardrails.py
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 | |
calculate_withdrawal(context)
¶
Calculate guardrails-adjusted withdrawal.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
context
|
WithdrawalContext
|
Current state including previous spending and market returns |
required |
Returns:
| Type | Description |
|---|---|
WithdrawalDecision
|
WithdrawalDecision with guardrail-adjusted amount |
Source code in fundedness/withdrawals/guardrails.py
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 | |
get_initial_withdrawal(initial_wealth)
¶
Calculate first year withdrawal.
Source code in fundedness/withdrawals/guardrails.py
46 47 48 49 | |
Variable Percentage Withdrawal¶
fundedness.withdrawals.vpw.VPWPolicy
dataclass
¶
Bases: BaseWithdrawalPolicy
Variable Percentage Withdrawal (VPW) strategy.
Withdrawal rate varies based on age and remaining life expectancy. Uses actuarial tables to determine appropriate withdrawal percentage.
Source code in fundedness/withdrawals/vpw.py
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 | |
calculate_withdrawal(context)
¶
Calculate VPW withdrawal.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
context
|
WithdrawalContext
|
Current state including age or year |
required |
Returns:
| Type | Description |
|---|---|
WithdrawalDecision
|
WithdrawalDecision based on VPW table |
Source code in fundedness/withdrawals/vpw.py
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 | |
get_initial_withdrawal(initial_wealth)
¶
Calculate first year withdrawal.
Source code in fundedness/withdrawals/vpw.py
87 88 89 90 | |
RMD-Style¶
fundedness.withdrawals.rmd_style.RMDStylePolicy
dataclass
¶
Bases: BaseWithdrawalPolicy
RMD-style withdrawal strategy.
Uses IRS Required Minimum Distribution table to determine withdrawals. Withdrawal = Portfolio Value / Distribution Period
This approach automatically increases withdrawal rate as you age, similar to how RMDs work for tax-deferred accounts.
Source code in fundedness/withdrawals/rmd_style.py
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 | |
calculate_withdrawal(context)
¶
Calculate RMD-style withdrawal.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
context
|
WithdrawalContext
|
Current state including age or year |
required |
Returns:
| Type | Description |
|---|---|
WithdrawalDecision
|
WithdrawalDecision based on RMD table |
Source code in fundedness/withdrawals/rmd_style.py
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 | |
get_initial_withdrawal(initial_wealth)
¶
Calculate first year withdrawal.
Source code in fundedness/withdrawals/rmd_style.py
75 76 77 78 | |