Hej!
Jag har tillsammans med Gemini snickrat ihop en Python kod för att simulera pensionskapital och FIRE som jag tänkte dela med mig av.
Många enkla kalkylatorer räknar linjärt (“börsen går upp 7% varje år”). Problemet är att verkligheten inte ser ut så. Om börsen kraschar 30% precis året efter att du slutat jobba (Sequence of Return Risk) spelar det ingen roll om snittet blir bra på 30 år – dina pengar kan hinna ta slut innan dess.
Det här verktyget använder Monte Carlo-simulering (kör 4 000 olika slumpmässiga “framtider”) för att stresstesta din strategi.
Vad gör den här modellen?
Den simulerar en variabel uttagsstrategi med buffert (Floor-strategi). Istället för att bara ha pengar på hög, räknar modellen ut hur stor buffert du behöver baserat på din “smärtgräns” (den lägsta inkomst du kan leva på under krisår).
-
Bra år: Du tar ut din önskade “lyx-nivå” direkt från avkastningen (ISK).
-
Dåliga år: Om börsen backar, rör du inte fonderna. Istället lever du på din buffert (sparkonto) och drar ner utgifterna till din smärtgräns.
-
Effekt: Detta gör att portföljen återhämtar sig snabbare efter en krasch, vilket ofta drastiskt ökar chansen att pengarna räcker livet ut.
Vad får du för svar?
När du kör koden får du en rapport och grafer som visar 4 scenarier:
-
Scenario A (Ditt val): Hur det går med din valda uttagsnivå (t.ex. 4%).
-
Scenario B (Låg kostnad): Hur kapitalet växer om du alltid lever snålt (på din smärtgräns).
-
Scenario C (Bevara kapitalet): Vilken uttagsnivå (%) du bör ligga på om du vill att köpkraften ska vara intakt när angiven tidsperiod passerat.
-
Scenario D (Die With Zero): Hur mycket du kan unna dig om målet är att kontot ska vara tomt (0 kr) exakt när angiven tidsperiod passerat.
Den räknar även om allt till vad det motsvarar i bruttolön (baserat på skattesats som du angivit) så siffrorna blir greppbara.
Antaganden i koden (Marknadsdata)
Simuleringen räknar med nominell avkastning (inklusive volatilitet/risk) baserat på historiska schabloner, och justerar sedan allt för inflation och skatt.
-
Globalfond (MSCI World): 7,5% avkastning (Risk/Std: 15%).
- OBS: Detta inkluderar enbart utvecklade marknader (USA, Europa etc), ej tillväxtmarknader.
-
Sverigefond: 9,5% avkastning (Risk/Std: 22%). Högre risk/reward.
-
Europafond: 7,5% avkastning (Risk/Std: 18%).
-
Tillväxtmarknader (EM): 8,5% avkastning (Risk/Std: 25%). Högst risk.
-
Inflation: 2,0%.
-
ISK-skatt & Avgifter: ca 1,2% totalt.
Vill du ändra dessa siffror? I koden letar du upp funktionen def calculate_portfolio_metrics. Där ligger variabeln stats = { ... } där du enkelt kan ändra mean (avkastning) och std (risk) för respektive region.
Så här kör du koden (även om du inte kan programmera)
Du behöver inte installera något. Du kan köra detta direkt i webbläsaren via Google Colab (gratis).
-
Gå till colab.research.google.com (logga in med Google-konto).
-
Klicka på “New Notebook” (Ny anteckningsbok).
-
I den tomma rutan, klistra in hela koden nedanför.
-
Klicka på den lilla “Play-knappen” (pil) till vänster om koden.
-
Skrolla ner lite. Programmet ställer frågor (t.ex. “Totalt kapital”).
-
Tips: Där det står ett värde inom klamrar, t.ex.
[Standard: 4.0], kan du bara trycka Enter för att välja det.
Här är koden.
#!/usr/bin/env python3
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.ticker as mticker
from typing import Optional, Tuple, List
# -------------------------------------------------------------------------
# 1. SKATTEBERÄKNING
# -------------------------------------------------------------------------
def calculate_gross_salary_from_net(target_net_monthly, local_tax_rate, state_tax_threshold):
low = target_net_monthly
high = target_net_monthly * 2.5
def calc_net(gross):
basic_deduction = 1250
if gross < 20000: basic_deduction = 2000
taxable_income = gross - basic_deduction
muni_tax = taxable_income * local_tax_rate
state_tax = 0
if taxable_income > state_tax_threshold:
state_tax = (taxable_income - state_tax_threshold) * 0.20
job_deduction = 0
if gross > 40000: job_deduction = 3500
elif gross > 20000: job_deduction = 2500
else: job_deduction = 1500
total_tax = muni_tax + state_tax - job_deduction
if total_tax < 0: total_tax = 0
return gross - total_tax
for _ in range(30):
mid = (low + high) / 2
net = calc_net(mid)
if net < target_net_monthly:
low = mid
else:
high = mid
return high
# -------------------------------------------------------------------------
# 2. PORTFÖLJ-LOGIK
# -------------------------------------------------------------------------
def calculate_portfolio_metrics(pct_global, pct_swe, pct_eur, pct_em):
stats = {
"Global": {"mean": 0.075, "std": 0.15},
"Sverige": {"mean": 0.095, "std": 0.22},
"Europa": {"mean": 0.075, "std": 0.18},
"Tillväxt": {"mean": 0.085, "std": 0.25}
}
w_g, w_s = pct_global / 100.0, pct_swe / 100.0
w_e, w_em = pct_eur / 100.0, pct_em / 100.0
port_mean = (w_g * stats["Global"]["mean"] + w_s * stats["Sverige"]["mean"] +
w_e * stats["Europa"]["mean"] + w_em * stats["Tillväxt"]["mean"])
port_std = (w_g * stats["Global"]["std"] + w_s * stats["Sverige"]["std"] +
w_e * stats["Europa"]["std"] + w_em * stats["Tillväxt"]["std"])
return port_mean, port_std, stats
# -------------------------------------------------------------------------
# 3. HJÄLPFUNKTIONER
# -------------------------------------------------------------------------
def fmt_sek(amount):
return f"{amount:,.0f}".replace(",", " ")
def get_user_input(prompt_text, default_value, value_type=float):
if default_value >= 1000:
display_default = f"{default_value:,.0f}".replace(",", " ")
else:
display_default = str(default_value)
user_str = input(f"{prompt_text} [Standard: {display_default}]: ")
if not user_str.strip(): return default_value
try:
clean_str = user_str.replace(" ", "").replace(",", ".")
if value_type is int: return int(float(clean_str))
return float(clean_str)
except ValueError: return default_value
def get_mandatory_input(prompt_text, value_type=float):
while True:
user_str = input(f"{prompt_text}: ")
if not user_str.strip():
print("⚠️ Du måste ange ett värde.")
continue
try:
clean_str = user_str.replace(" ", "").replace(",", ".")
if value_type is int: return int(float(clean_str))
return float(clean_str)
except ValueError:
print("⚠️ Felaktigt format. Försök igen.")
def get_yes_no(prompt_text, default="n"):
user_str = input(f"{prompt_text} (j/n) [Standard: {default}]: ").strip().lower()
if not user_str: return default == "j"
return user_str.startswith("j") or user_str.startswith("y")
# -------------------------------------------------------------------------
# 4. SIMULERINGSLOGIK
# -------------------------------------------------------------------------
def simulate_strategy(
n_sims, years, start_capital, withdraw_rate, min_withdraw_yearly_start,
stock_mean, stock_std, management_fee,
isk_tax, inflation, skip_threshold, buffer_years, seed,
return_full_stats=False
):
if seed is not None: np.random.seed(seed)
buffer_size_needed = min_withdraw_yearly_start * buffer_years
if start_capital <= buffer_size_needed:
invested_capital = 0.0
current_buffer_start = start_capital
else:
invested_capital = start_capital - buffer_size_needed
current_buffer_start = buffer_size_needed
all_paths_nominal = np.zeros((n_sims, years + 1))
all_paths_nominal[:, 0] = start_capital
skip_years_used_list = []
max_skip_streak_list = []
survival_years_list = []
market_returns = np.random.normal(stock_mean, stock_std, (n_sims, years))
for i in range(n_sims):
curr_isk = invested_capital
curr_buffer = current_buffer_start
std_withdraw_amt = invested_capital * withdraw_rate
min_withdraw_amt = min_withdraw_yearly_start
skip_years_used = 0
curr_streak = 0
max_streak = 0
money_lasted_years = years
for year in range(1, years + 1):
if curr_isk <= 0 and curr_buffer <= 0:
if money_lasted_years == years: money_lasted_years = year - 1
all_paths_nominal[i, year] = 0
continue
m_ret = market_returns[i, year-1]
net_ret = m_ret - management_fee
# 1. Aktieutveckling + Skatt
curr_isk *= (1 + net_ret)
if curr_isk > 0: curr_isk -= (curr_isk * isk_tax)
if curr_isk < 0: curr_isk = 0.0
# 2. Buffertutveckling (Inflation)
curr_buffer *= (1 + inflation)
# 3. Beslut: ISK eller Buffert?
actual_std_withdraw = max(std_withdraw_amt, min_withdraw_amt)
if m_ret <= skip_threshold and curr_buffer >= min_withdraw_amt:
# DÅLIGT ÅR -> Ta från Buffert
curr_buffer -= min_withdraw_amt
skip_years_used += 1
curr_streak += 1
max_streak = max(max_streak, curr_streak)
else:
# BRA ÅR -> Ta från ISK
take_amount = actual_std_withdraw
if curr_isk >= take_amount:
curr_isk -= take_amount
else:
remaining = take_amount - curr_isk
curr_isk = 0.0
if curr_buffer >= remaining:
curr_buffer -= remaining
else:
curr_buffer = 0.0
curr_streak = 0
# 4. Indexera upp behovet inför nästa år
std_withdraw_amt *= (1 + inflation)
min_withdraw_amt *= (1 + inflation)
total_now = curr_isk + curr_buffer
all_paths_nominal[i, year] = total_now
if total_now <= 0 and money_lasted_years == years:
money_lasted_years = year
skip_years_used_list.append(skip_years_used)
max_skip_streak_list.append(max_streak)
survival_years_list.append(money_lasted_years)
final_caps = all_paths_nominal[:, -1]
final_real = final_caps / ((1+inflation)**years)
prob_preservation = float(np.mean(final_real >= start_capital))
median_final_nominal = float(np.median(final_caps))
if return_full_stats:
median_nom_path = np.median(all_paths_nominal, axis=0)
median_real_path = median_nom_path / np.array([(1+inflation)**y for y in range(years+1)])
median_survival = float(np.median(survival_years_list))
return (
median_final_nominal,
float(np.median(final_real)),
prob_preservation,
skip_years_used_list,
max_skip_streak_list,
median_nom_path,
median_real_path,
invested_capital,
current_buffer_start,
median_survival,
all_paths_nominal
)
else:
return median_final_nominal
# --- OPTIMERINGAR ---
def find_preservation_rate(n_sims, years, total_cap, min_withdraw, stock_mean, stock_std, fee, tax, inf, skip, buf_years, seed):
low, high = 0.00, 0.15
best = 0.0
for _ in range(15):
mid = (low+high)/2
result = simulate_strategy(
min(n_sims, 2000), years, total_cap, mid, min_withdraw,
stock_mean, stock_std, fee, tax, inf, skip, buf_years, seed, True
)
if result[2] > 0.50: best = mid; low = mid
else: high = mid
return best
def find_depletion_rate(n_sims, years, total_cap, min_withdraw, stock_mean, stock_std, fee, tax, inf, skip, buf_years, seed):
low, high = 0.00, 0.30
best = 0.0
for _ in range(15):
mid = (low+high)/2
final_cap = simulate_strategy(
min(n_sims, 2000), years, total_cap, mid, min_withdraw,
stock_mean, stock_std, fee, tax, inf, skip, buf_years, seed, False
)
if final_cap > 10000: best = mid; low = mid
else: high = mid
return best
def export_detailed_csv(all_paths_nominal, years, inflation):
df_data = []
inflation_factors = np.array([(1 + inflation) ** y for y in range(years + 1)])
p10 = np.percentile(all_paths_nominal, 10, axis=0)
p50 = np.percentile(all_paths_nominal, 50, axis=0)
p90 = np.percentile(all_paths_nominal, 90, axis=0)
for y in range(years + 1):
row = {
"År": y,
"Pessimistiskt (10%) - Nominellt": p10[y],
"Median (50%) - Nominellt": p50[y],
"Optimistiskt (90%) - Nominellt": p90[y],
"Pessimistiskt (10%) - Realt": p10[y] / inflation_factors[y],
"Median (50%) - Realt": p50[y] / inflation_factors[y],
"Optimistiskt (90%) - Realt": p90[y] / inflation_factors[y]
}
df_data.append(row)
pd.DataFrame(df_data).to_csv("fire_detaljerad_data.csv", index=False, float_format='%.0f')
print(f"\n✅ Detaljerad data sparad till 'fire_detaljerad_data.csv'")
def plot_four_scenarios(years, start_capital, res_A, res_B, res_C, res_D, rate_A, rate_C, rate_D, min_withdraw_monthly):
path_nom_A, path_real_A = res_A[5], res_A[6]
path_nom_B, path_real_B = res_B[5], res_B[6]
path_nom_C, path_real_C = res_C[5], res_C[6]
path_nom_D, path_real_D = res_D[5], res_D[6]
x_years = np.arange(years + 1)
fig, axs = plt.subplots(2, 2, figsize=(14, 10))
fig.suptitle(f"Utfall av 4 strategier (Medianutveckling över {years} år)", fontsize=16, fontweight='bold')
def currency_fmt(x, pos):
if x >= 1_000_000: return f'{x/1_000_000:.1f} M'
return f'{x/1_000:.0f} k'
scenarios = [
(axs[0, 0], "A: DITT VAL", path_nom_A, path_real_A, f"{rate_A*100:.1f}% uttag"),
(axs[0, 1], "B: LÅG KOSTNAD (Smärtgräns)", path_nom_B, path_real_B, f"{fmt_sek(min_withdraw_monthly)} kr/mån"),
(axs[1, 0], "C: BEVARA KAPITAL", path_nom_C, path_real_C, f"{rate_C*100:.1f}% uttag"),
(axs[1, 1], "D: DIE WITH ZERO", path_nom_D, path_real_D, f"{rate_D*100:.1f}% uttag"),
]
for ax, title, p_nom, p_real, subtitle in scenarios:
width = 0.4
ax.bar(x_years - width/2, p_nom, width, label='Nominellt (På kontot)', color='#4c72b0', alpha=0.9)
ax.bar(x_years + width/2, p_real, width, label='Realt (Köpkraft)', color='#55a868', alpha=0.9)
ax.axhline(y=start_capital, color='red', linestyle='--', linewidth=1.5, label='Startkapital')
ax.set_title(title, fontsize=12, fontweight='bold')
ax.text(0.05, 0.95, subtitle, transform=ax.transAxes, fontsize=10, verticalalignment='top', bbox=dict(boxstyle='round', facecolor='white', alpha=0.8))
ax.grid(axis='y', linestyle='--', alpha=0.3)
ax.yaxis.set_major_formatter(mticker.FuncFormatter(currency_fmt))
if ax == axs[0, 0]: ax.legend(loc='upper right', fontsize=9)
plt.tight_layout(rect=[0, 0.03, 1, 0.95])
plt.savefig('fire_scenarios.png', dpi=100)
plt.show()
# -------------------------------------------------------------------------
# 7. MAIN
# -------------------------------------------------------------------------
def main():
print("\n--- STEG 1: EKONOMI & STRATEGI ---")
total_available_capital = get_mandatory_input("TOTALT KAPITAL (ISK + Kontanter) (kr)")
min_monthly = get_user_input("Smärtgräns uttag under krisår (kr/mån)", 50000, int)
min_withdraw_yearly = min_monthly * 12
buffer_years = get_user_input("Hur många år ska bufferten räcka?", 4, int)
withdraw_percent = get_user_input("Önskat uttag BRA år (% av investerat ISK)", 4.0)
withdraw_rate = withdraw_percent / 100.0
years = get_user_input("Tidsperiod (år)", 30, int)
create_detailed_report = get_yes_no("Vill du spara en detaljerad Excel-fil (CSV) med utfall år för år?", "n")
print("\n--- STEG 2: PORTFÖLJALLOKERING ---")
print("Ange fördelning i % (Bör summera till 100).")
pct_global = get_user_input("Globalfond (%)", 65.0)
pct_swe = get_user_input("Sverigefond (%)", 25.0)
pct_em = get_user_input("Tillväxtmarknader (%)", 10.0)
pct_eur = get_user_input("Europafond (%)", 0.0)
total_pct = pct_global + pct_swe + pct_em + pct_eur
if abs(total_pct - 100.0) > 0.1:
pct_global = (pct_global / total_pct) * 100
pct_swe = (pct_swe / total_pct) * 100
pct_em = (pct_em / total_pct) * 100
pct_eur = (pct_eur / total_pct) * 100
print("\n--- STEG 3: SKATTEINSTÄLLNINGAR ---")
user_tax_rate_input = get_user_input("Kommunalskatt (%)", 32.21)
user_state_threshold_input = get_user_input("Brytpunkt statlig skatt (kr/mån)", 53_590, int)
local_tax_rate = user_tax_rate_input / 100.0
state_tax_threshold = user_state_threshold_input
stock_mean, stock_std, stats_data = calculate_portfolio_metrics(pct_global, pct_swe, pct_eur, pct_em)
n_sims = 4000
management_fee = 0.002
isk_tax = 0.010
inflation = 0.02
skip_threshold = -0.05
seed = 42
print(f"\n🚀 Kör simuleringar för alla scenarier...")
rate_preservation = find_preservation_rate(
n_sims, years, total_available_capital, min_withdraw_yearly,
stock_mean, stock_std, management_fee, isk_tax, inflation,
skip_threshold, buffer_years, seed
)
rate_depletion = find_depletion_rate(
n_sims, years, total_available_capital, min_withdraw_yearly,
stock_mean, stock_std, management_fee, isk_tax, inflation,
skip_threshold, buffer_years, seed
)
res_A = simulate_strategy(
n_sims, years, total_available_capital, withdraw_rate, min_withdraw_yearly,
stock_mean, stock_std, management_fee, isk_tax, inflation,
skip_threshold, buffer_years, seed, return_full_stats=True
)
res_B = simulate_strategy(
n_sims, years, total_available_capital, 0.0, min_withdraw_yearly,
stock_mean, stock_std, management_fee, isk_tax, inflation,
skip_threshold, buffer_years, seed, return_full_stats=True
)
res_C = simulate_strategy(
n_sims, years, total_available_capital, rate_preservation, min_withdraw_yearly,
stock_mean, stock_std, management_fee, isk_tax, inflation,
skip_threshold, buffer_years, seed, return_full_stats=True
)
res_D = simulate_strategy(
n_sims, years, total_available_capital, rate_depletion, min_withdraw_yearly,
stock_mean, stock_std, management_fee, isk_tax, inflation,
skip_threshold, buffer_years, seed, return_full_stats=True
)
if create_detailed_report:
export_detailed_csv(res_A[10], years, inflation)
invested_cap = res_A[7]
buffer_cap = res_A[8]
pct_invested = (invested_cap / total_available_capital) * 100 if total_available_capital > 0 else 0
pct_buffer = (buffer_cap / total_available_capital) * 100 if total_available_capital > 0 else 0
yr_A = invested_cap * withdraw_rate
mo_A = yr_A / 12
gross_A = calculate_gross_salary_from_net(mo_A, local_tax_rate, state_tax_threshold)
surv_A = res_A[9]; txt_surv_A = f"{surv_A:.0f}" if surv_A < years else f"{years}+"
yr_C = invested_cap * rate_preservation; mo_C = yr_C / 12
gross_C = calculate_gross_salary_from_net(mo_C, local_tax_rate, state_tax_threshold)
margin_C = mo_C - mo_A
yr_D = invested_cap * rate_depletion; mo_D = yr_D / 12
gross_D = calculate_gross_salary_from_net(mo_D, local_tax_rate, state_tax_threshold)
pct_any_skip = float(np.mean(np.array(res_A[3]) > 0))
avg_skipped = float(np.mean(res_A[3]))
med_streak = float(np.median(res_A[4])) if res_A[4] else 0.0
assumptions_str = ""
for market, data in stats_data.items():
assumptions_str += f"- {market}: {data['mean']*100:.1f}% avkastning / {data['std']*100:.1f}% risk\n"
summary_text = (
f"📊 RAPPORT: FIRE-SIMULERING (4 SCENARIER)\n"
f"Resultat baserat på {n_sims} antal Monte Carlo-simuleringar över {years} år\n"
f"==========================================================\n"
f"TOTALT KAPITAL: {fmt_sek(total_available_capital)} kr\n"
f"FÖRDELNING (Baserat på smärtgräns {fmt_sek(min_monthly)} kr/mån × {buffer_years} år):\n"
f" 👉 Investeras på ISK: {fmt_sek(invested_cap)} kr ({pct_invested:.1f}%)\n"
f" 👉 Buffert (Sparkonto): {fmt_sek(buffer_cap)} kr ({pct_buffer:.1f}%)\n"
f"==========================================================\n"
f"Portfölj: Global {pct_global:.0f}% | Sve {pct_swe:.0f}% | Tillväxt {pct_em:.0f}% | Europa {pct_eur:.0f}%\n"
f"Skattemodell: {user_tax_rate_input}% kommunal, {fmt_sek(state_tax_threshold)} kr brytpunkt\n"
f"\n"
f"ANTAGANDEN (Nominell avkastning & Standardavvikelse):\n"
f"{assumptions_str}"
f"\n"
f"💰 EKONOMI & UTFALL (Dagens penningvärde)\n"
f"-----------------------------------------\n"
f"SCENARIO A: DITT VAL ({withdraw_percent}% av ISK)\n"
f" Uttag/mån: {fmt_sek(mo_A)} kr (Motsvarar lön: {fmt_sek(gross_A)} kr)\n"
f" Uttag/år: {fmt_sek(yr_A)} kr\n"
f" Kapitalet räcker: {txt_surv_A} år (i snitt)\n"
f" Median slutkapital: {fmt_sek(res_A[1])} kr (realt)\n"
f"\n"
f"SCENARIO B: LÅG KOSTNAD (Lever alltid på smärtgränsen)\n"
f" Uttag/mån: {fmt_sek(min_monthly)} kr\n"
f" Median slutkapital: {fmt_sek(res_B[1])} kr (realt) <-- Maximerar tillväxt\n"
f"\n"
f"SCENARIO C: BEVARA KAPITALET (Säkert uttag)\n"
f" Max uttag %: {rate_preservation*100:.2f}%\n"
f" Uttag/mån: {fmt_sek(mo_C)} kr (Motsvarar lön: {fmt_sek(gross_C)} kr)\n"
f" Diff mot A: {fmt_sek(margin_C)} kr/mån\n"
f" Median slutkapital: {fmt_sek(res_C[1])} kr (realt)\n"
f"\n"
f"SCENARIO D: NOLLA KONTOT ('Die with Zero')\n"
f" Max uttag %: {rate_depletion*100:.2f}%\n"
f" Uttag/mån: {fmt_sek(mo_D)} kr (Motsvarar lön: {fmt_sek(gross_D)} kr)\n"
f" Median slutkapital: {fmt_sek(res_D[1])} kr (realt)\n"
f"\n"
f"🧰 BUFFERTANVÄNDNING (För Scenario A)\n"
f"-------------------------------\n"
f"- Sannolikhet att behöva använda buffert: {pct_any_skip:.1%}\n"
f"- Snitt antal år med buffertanvändning: {avg_skipped:.1f} år\n"
f"\n"
f"🔍 SÅ GICK DET TILL\n"
f"Här är logiken som kördes {n_sims} gånger:\n"
f"1. Marknadens nycker: Varje år slumpas en avkastning baserad på din portföljs risk.\n"
f"2. Beslutsregeln (Golv-strategin):\n"
f" - Är årets avkastning sämre än {skip_threshold*100:.0f}%? -> Vi tar smärtgräns-beloppet från bufferten.\n"
f" - Är avkastningen ok? -> Vi tar ut standardbeloppet från ISK-portföljen.\n"
f"3. Inflation & Skatt: Alla uttag räknas upp med {inflation*100}%/år. ISK-skatt dras automatiskt.\n"
f"4. Utfall: Vi mäter hur många av de {n_sims} simulerade liven som lyckades.\n"
)
filename = "fire_simulator_summering.txt"
with open(filename, "w", encoding="utf-8") as f:
f.write(summary_text)
print(f"\n✅ Resultat sparat till {filename}")
print(summary_text)
print("\nGenererar grafer för alla scenarier...")
plot_four_scenarios(years, total_available_capital, res_A, res_B, res_C, res_D, withdraw_rate, rate_preservation, rate_depletion, min_monthly)
if __name__ == "__main__":
main()
