import base64 import csv from io import StringIO import matplotlib.pyplot as plt import io from modules.utils import load_css def retirement_planning( current_age=None, retirement_age=None, life_expectancy=None, monthly_income_required=None, inflation_rate=None, current_investment=None, monthly_investment=None, annual_increase_in_monthly_investment=None, # 추가된 입력 reinvest_dividends=None, pre_retirement_roi=None, post_retirement_roi=None, pre_retirement_dividend_yield=None, post_retirement_dividend_yield=None ): # NoneType일 때 0으로 처리 current_age = current_age if current_age is not None else 0 retirement_age = retirement_age if retirement_age is not None else 0 current_investment = current_investment if current_investment is not None else 0 monthly_investment = monthly_investment if monthly_investment is not None else 0 annual_increase_in_monthly_investment = annual_increase_in_monthly_investment if annual_increase_in_monthly_investment is not None else 0 pre_retirement_roi = pre_retirement_roi if pre_retirement_roi is not None else 0 post_retirement_roi = post_retirement_roi if post_retirement_roi is not None else 0 pre_retirement_dividend_yield = pre_retirement_dividend_yield if pre_retirement_dividend_yield is not None else 0 post_retirement_dividend_yield = post_retirement_dividend_yield if post_retirement_dividend_yield is not None else 0 life_expectancy = life_expectancy if life_expectancy is not None else 0 monthly_income_required = monthly_income_required if monthly_income_required is not None else 0 inflation_rate = inflation_rate if inflation_rate is not None else 0 # 은퇴 전후의 년 수 계산 if retirement_age > life_expectancy: return "
Error: Retirement age cannot be greater than life expectancy.
" if retirement_age < current_age: return "Error: Retirement age cannot be less than current age.
" years_to_retirement = retirement_age - current_age post_retirement_years = life_expectancy - retirement_age # 현재 투자액으로 초기 투자 설정 total_investment = current_investment # 은퇴 전 월간 이자율 계산 monthly_return_pre = (1 + pre_retirement_roi / 100) ** (1 / 12) - 1 # 은퇴 시점의 투자 계산 for year in range(years_to_retirement): for month in range(12): # 월간 투자액과 이자율을 적용하여 총 투자액 갱신 total_investment = (total_investment + monthly_investment) * (1 + monthly_return_pre) # 배당금을 재투자할 경우 배당금 추가 if reinvest_dividends: total_investment += total_investment * (pre_retirement_dividend_yield / 100 / 12) # 연간 증가액을 월 투자액에 추가 monthly_investment += annual_increase_in_monthly_investment # 은퇴 시작 시점의 총 투자액과 연간 배당 수익 저장 investment_at_retirement = total_investment annual_dividend_at_retirement = investment_at_retirement * (pre_retirement_dividend_yield / 100) monthly_dividend_at_retirement = annual_dividend_at_retirement / 12 # 은퇴 후 월간 이자율 계산 monthly_return_post = (1 + post_retirement_roi / 100) ** (1 / 12) - 1 # 연간 물가상승률을 반영한 월 생활비 계산 monthly_income_required_inflated = monthly_income_required monthly_income_required_over_time = [] for age in range(current_age, life_expectancy + 1): if age >= retirement_age: monthly_income_required_over_time.append((age, monthly_income_required_inflated)) monthly_income_required_inflated *= (1 + inflation_rate / 100 / 12) ** 12 annual_income_required_at_retirement = monthly_income_required_over_time[0][1] * 12 monthly_income_required_at_retirement = monthly_income_required_over_time[0][1] # 은퇴 후 투자 목록 초기화 post_retirement_investments = [(retirement_age, investment_at_retirement, annual_income_required_at_retirement, annual_dividend_at_retirement, monthly_dividend_at_retirement, monthly_income_required_at_retirement, annual_dividend_at_retirement - annual_income_required_at_retirement)] # 은퇴 후 각 년도의 투자 및 배당 수익 계산 for year in range(1, post_retirement_years + 1): # 은퇴 후 수익률을 적용하여 총 투자액 갱신 total_investment *= (1 + post_retirement_roi / 100) # 연간 배당 수익 계산 annual_dividend_income = total_investment * (post_retirement_dividend_yield / 100) # 월간 배당 수익 계산 monthly_dividend_income = annual_dividend_income / 12 # 연도별 물가상승률 반영한 월 생활비 갱신 inflated_income_required = monthly_income_required_over_time[year][1] if year < len(monthly_income_required_over_time) else monthly_income_required_over_time[-1][1] # 각 연도별 투자와 배당 수익 및 월 생활비를 리스트에 추가 difference = annual_dividend_income - inflated_income_required * 12 post_retirement_investments.append((retirement_age + year, total_investment, inflated_income_required * 12, annual_dividend_income, monthly_dividend_income, inflated_income_required, difference)) # 마이너스 값의 difference 합계 계산 negative_differences_sum = sum(diff for _, _, _, _, _, _, diff in post_retirement_investments if diff < 0) # CSV 파일 생성 csv_output = StringIO() csv_writer = csv.writer(csv_output) csv_writer.writerow(['Age', 'SAVINGS', 'Annual Income Required', 'Annual Dividend Income', 'Monthly Income Required', 'Monthly Dividend Income', 'Additional Cash Required']) for age, investment, annual_income_required, annual_dividend_income, monthly_dividend_income, income_required, difference in post_retirement_investments: additional_cash_required = f'{abs(difference):,.0f}' if difference < 0 else '' csv_writer.writerow([age, f'{investment:,.0f}', f'{annual_income_required:,.0f}', f'{income_required:,.0f}', f'{annual_dividend_income:,.0f}', f'{monthly_dividend_income:,.0f}', additional_cash_required]) csv_string = csv_output.getvalue().encode('utf-8') csv_base64 = base64.b64encode(csv_string).decode('utf-8') # style.css에서 CSS 읽기 css = load_css() # SVG 그래프 생성 fig, ax = plt.subplots() ages = [investment[0] for investment in post_retirement_investments] income_required = [investment[2] for investment in post_retirement_investments] dividend_income = [investment[3] for investment in post_retirement_investments] ax.plot(ages, income_required, label='Income Required', color='red') ax.plot(ages, dividend_income, label='Dividend Income', color='green') ax.set_xlabel('Age') ax.set_ylabel('Amount') # ax.set_title('Retirement Plan Overview') ax.legend() ax.grid(True) # 그래프를 SVG 형식으로 저장 svg_output = io.StringIO() plt.savefig(svg_output, format='svg') plt.close(fig) svg_data = svg_output.getvalue() svg_base64 = base64.b64encode(svg_data.encode('utf-8')).decode('utf-8') graph_html = f'Age | SAVINGS | Annual Income Required | Monthly Income Required | Annual Dividend Income | Monthly Dividend Income | Additional Cash Required |
---|---|---|---|---|---|---|
{age} | {investment:,.0f} | {annual_income_required:,.0f} | {income_required:,.0f} | {annual_dividend_income:,.0f} | {monthly_dividend_income:,.0f} | {additional_cash_required} |
Note: No additional investments or reinvestment of dividends after retirement.
""" return result_html