cryman38 commited on
Commit
9728008
Β·
verified Β·
1 Parent(s): 65954f5

Upload 14 files

Browse files
interface/portfolio_rebalancing_interface.py CHANGED
@@ -9,7 +9,7 @@ def portfolio_rebalancing_interface_fn(main_currency, holdings, cash_amount, cas
9
 
10
  currency_codes = get_currency_codes()
11
  examples = [
12
- ["KRW", "458730 KRW 580 8,\n368590 KRW 80 2", 7977, 0],
13
  ["KRW", "SCHD USD 500 8,\nQQQ USD 200 2", 0, 15]
14
  ]
15
 
 
9
 
10
  currency_codes = get_currency_codes()
11
  examples = [
12
+ ["KRW", "458730 KRW 580 8,\n368590 KRW 80 2", 507977, 0],
13
  ["KRW", "SCHD USD 500 8,\nQQQ USD 200 2", 0, 15]
14
  ]
15
 
interface/retirement_planning_interface.py CHANGED
@@ -2,8 +2,8 @@ import gradio as gr
2
  from modules.utils import load_css
3
  from modules.retirement_planning import retirement_planning
4
 
5
- def retirement_planning_interface_fn(current_age, retirement_age, current_investment, monthly_investment, pre_retirement_roi, post_retirement_roi, pre_retirement_dividend_yield, post_retirement_dividend_yield, reinvest_dividends, life_expectancy):
6
- result = retirement_planning(current_age, retirement_age, current_investment, monthly_investment, pre_retirement_roi, post_retirement_roi, pre_retirement_dividend_yield, post_retirement_dividend_yield, reinvest_dividends, life_expectancy)
7
  css = load_css()
8
  return css + result
9
 
@@ -17,11 +17,13 @@ retirement_planning_inputs = [
17
  gr.Number(label="Expected Dividend Yield (Pre-retirement) (%)", value=3.3),
18
  gr.Number(label="Expected Dividend Yield (Post-retirement) (%)", value=3.3),
19
  gr.Checkbox(label="Reinvest Dividends", value=True),
20
- gr.Slider(label="Life Expectancy (Upto 100 Years)", value=80, minimum=30, maximum=100, step=1)
 
 
21
  ]
22
 
23
  output = gr.HTML()
24
 
25
  # Define the update function
26
- def update_output(current_age, retirement_age, current_investment, monthly_investment, pre_retirement_roi, post_retirement_roi, pre_retirement_dividend_yield, post_retirement_dividend_yield, reinvest_dividends, life_expectancy):
27
- return retirement_planning_interface_fn(current_age, retirement_age, current_investment, monthly_investment, pre_retirement_roi, post_retirement_roi, pre_retirement_dividend_yield, post_retirement_dividend_yield, reinvest_dividends, life_expectancy)
 
2
  from modules.utils import load_css
3
  from modules.retirement_planning import retirement_planning
4
 
5
+ def retirement_planning_interface_fn(current_age, retirement_age, current_investment, monthly_investment, pre_retirement_roi, post_retirement_roi, pre_retirement_dividend_yield, post_retirement_dividend_yield, reinvest_dividends, life_expectancy, monthly_expenses, inflation_rate):
6
+ result = retirement_planning(current_age, retirement_age, current_investment, monthly_investment, pre_retirement_roi, post_retirement_roi, pre_retirement_dividend_yield, post_retirement_dividend_yield, reinvest_dividends, life_expectancy, monthly_expenses, inflation_rate)
7
  css = load_css()
8
  return css + result
9
 
 
17
  gr.Number(label="Expected Dividend Yield (Pre-retirement) (%)", value=3.3),
18
  gr.Number(label="Expected Dividend Yield (Post-retirement) (%)", value=3.3),
19
  gr.Checkbox(label="Reinvest Dividends", value=True),
20
+ gr.Slider(label="Life Expectancy (Upto 100 Years)", value=80, minimum=30, maximum=100, step=1),
21
+ gr.Number(label="Monthly Expenses", value=2000000),
22
+ gr.Number(label="Inflation Rate (%)", value=2)
23
  ]
24
 
25
  output = gr.HTML()
26
 
27
  # Define the update function
28
+ def update_output(current_age, retirement_age, current_investment, monthly_investment, pre_retirement_roi, post_retirement_roi, pre_retirement_dividend_yield, post_retirement_dividend_yield, reinvest_dividends, life_expectancy, monthly_expenses, inflation_rate):
29
+ return retirement_planning_interface_fn(current_age, retirement_age, current_investment, monthly_investment, pre_retirement_roi, post_retirement_roi, pre_retirement_dividend_yield, post_retirement_dividend_yield, reinvest_dividends, life_expectancy, monthly_expenses, inflation_rate)
modules/retirement_planning.py CHANGED
@@ -1,6 +1,10 @@
 
 
 
 
1
  from modules.utils import load_css
2
 
3
- def retirement_planning(current_age=None, retirement_age=None, current_investment=None, monthly_investment=None, pre_retirement_roi=None, post_retirement_roi=None, pre_retirement_dividend_yield=None, post_retirement_dividend_yield=None, reinvest_dividends=False, life_expectancy=None):
4
  # NoneType일 λ•Œ 0으둜 처리
5
  current_age = current_age if current_age is not None else 0
6
  retirement_age = retirement_age if retirement_age is not None else 0
@@ -11,6 +15,8 @@ def retirement_planning(current_age=None, retirement_age=None, current_investmen
11
  pre_retirement_dividend_yield = pre_retirement_dividend_yield if pre_retirement_dividend_yield is not None else 0
12
  post_retirement_dividend_yield = post_retirement_dividend_yield if post_retirement_dividend_yield is not None else 0
13
  life_expectancy = life_expectancy if life_expectancy is not None else 0
 
 
14
 
15
  # 은퇴 μ „ν›„μ˜ λ…„ 수 계산
16
  years_to_retirement = retirement_age - current_age
@@ -23,6 +29,7 @@ def retirement_planning(current_age=None, retirement_age=None, current_investmen
23
  monthly_return_pre = (1 + pre_retirement_roi / 100) ** (1 / 12) - 1
24
 
25
  # 은퇴 μ‹œμ μ˜ 투자 계산
 
26
  for year in range(years_to_retirement):
27
  for month in range(12):
28
  # μ›”κ°„ νˆ¬μžμ•‘κ³Ό μ΄μžμœ¨μ„ μ μš©ν•˜μ—¬ 총 νˆ¬μžμ•‘ κ°±μ‹ 
@@ -30,6 +37,7 @@ def retirement_planning(current_age=None, retirement_age=None, current_investmen
30
  # λ°°λ‹ΉκΈˆμ„ μž¬νˆ¬μžν•  경우 λ°°λ‹ΉκΈˆ μΆ”κ°€
31
  if reinvest_dividends:
32
  total_investment += total_investment * (pre_retirement_dividend_yield / 100 / 12)
 
33
 
34
  # 은퇴 μ‹œμž‘ μ‹œμ μ˜ 총 νˆ¬μžμ•‘κ³Ό μ—°κ°„ λ°°λ‹Ή 수읡 μ €μž₯
35
  investment_at_retirement = total_investment
@@ -53,9 +61,37 @@ def retirement_planning(current_age=None, retirement_age=None, current_investmen
53
  # 각 연도별 νˆ¬μžμ™€ λ°°λ‹Ή μˆ˜μ΅μ„ λ¦¬μŠ€νŠΈμ— μΆ”κ°€
54
  post_retirement_investments.append((retirement_age + year, total_investment, annual_dividend_income, monthly_dividend_income))
55
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56
  # style.cssμ—μ„œ CSS 읽기
57
  css = load_css()
58
 
 
 
 
 
59
  # 은퇴 κ³„νšμ— λŒ€ν•œ HTML κ²°κ³Ό 생성
60
  result_html = css + f"""
61
  <div class="wrap-text" style="box-shadow: 0 0.25rem 0.5rem rgba(0, 0, 0, 0.1); border-radius: 0.5rem; padding: 3rem; position: relative; width: 100%; padding: 1.5rem;">
@@ -81,8 +117,14 @@ def retirement_planning(current_age=None, retirement_age=None, current_investmen
81
  <hr style="margin: 1.5rem 0;">
82
  </div>
83
  </div>
 
 
 
 
 
 
 
84
  </div>
85
- <h3>Dividend Income After Retirement</h3>
86
  <div class='table-container'>
87
  <table>
88
  <thead>
@@ -91,19 +133,21 @@ def retirement_planning(current_age=None, retirement_age=None, current_investmen
91
  <th>SAVINGS</th>
92
  <th>Annual</th>
93
  <th>Monthly</th>
 
94
  </tr>
95
  </thead>
96
  <tbody>
97
  """
98
 
99
  # 각 연도별 νˆ¬μžμ™€ λ°°λ‹Ή μˆ˜μ΅μ„ ν…Œμ΄λΈ”μ— μΆ”κ°€
100
- for age, investment, annual_dividend_income, monthly_dividend_income in post_retirement_investments:
101
  result_html += f"""
102
  <tr>
103
  <td>{age}</td>
104
  <td>{investment:,.0f}</td>
105
  <td>{annual_dividend_income:,.0f}</td>
106
  <td>{monthly_dividend_income:,.0f}</td>
 
107
  </tr>
108
  """
109
 
 
1
+ import matplotlib.pyplot as plt
2
+ import pandas as pd
3
+ from io import BytesIO
4
+ import base64
5
  from modules.utils import load_css
6
 
7
+ def retirement_planning(current_age=None, retirement_age=None, current_investment=None, monthly_investment=None, pre_retirement_roi=None, post_retirement_roi=None, pre_retirement_dividend_yield=None, post_retirement_dividend_yield=None, reinvest_dividends=False, life_expectancy=None, monthly_expenses=None, inflation_rate=None):
8
  # NoneType일 λ•Œ 0으둜 처리
9
  current_age = current_age if current_age is not None else 0
10
  retirement_age = retirement_age if retirement_age is not None else 0
 
15
  pre_retirement_dividend_yield = pre_retirement_dividend_yield if pre_retirement_dividend_yield is not None else 0
16
  post_retirement_dividend_yield = post_retirement_dividend_yield if post_retirement_dividend_yield is not None else 0
17
  life_expectancy = life_expectancy if life_expectancy is not None else 0
18
+ monthly_expenses = monthly_expenses if monthly_expenses is not None else 0
19
+ inflation_rate = inflation_rate if inflation_rate is not None else 0
20
 
21
  # 은퇴 μ „ν›„μ˜ λ…„ 수 계산
22
  years_to_retirement = retirement_age - current_age
 
29
  monthly_return_pre = (1 + pre_retirement_roi / 100) ** (1 / 12) - 1
30
 
31
  # 은퇴 μ‹œμ μ˜ 투자 계산
32
+ investment_over_time = []
33
  for year in range(years_to_retirement):
34
  for month in range(12):
35
  # μ›”κ°„ νˆ¬μžμ•‘κ³Ό μ΄μžμœ¨μ„ μ μš©ν•˜μ—¬ 총 νˆ¬μžμ•‘ κ°±μ‹ 
 
37
  # λ°°λ‹ΉκΈˆμ„ μž¬νˆ¬μžν•  경우 λ°°λ‹ΉκΈˆ μΆ”κ°€
38
  if reinvest_dividends:
39
  total_investment += total_investment * (pre_retirement_dividend_yield / 100 / 12)
40
+ investment_over_time.append((current_age + year + 1, total_investment))
41
 
42
  # 은퇴 μ‹œμž‘ μ‹œμ μ˜ 총 νˆ¬μžμ•‘κ³Ό μ—°κ°„ λ°°λ‹Ή 수읡 μ €μž₯
43
  investment_at_retirement = total_investment
 
61
  # 각 연도별 νˆ¬μžμ™€ λ°°λ‹Ή μˆ˜μ΅μ„ λ¦¬μŠ€νŠΈμ— μΆ”κ°€
62
  post_retirement_investments.append((retirement_age + year, total_investment, annual_dividend_income, monthly_dividend_income))
63
 
64
+ # λ¬Όκ°€μƒμŠΉλ₯ μ„ λ°˜μ˜ν•œ μ›” λͺ©ν‘œ μƒν™œλΉ„ 계산
65
+ adjusted_monthly_expenses = [monthly_expenses * ((1 + inflation_rate / 100) ** year) for year in range(post_retirement_years + 1)]
66
+
67
+ # 데이터 ν”„λ ˆμž„μœΌλ‘œ λ³€ν™˜
68
+ df = pd.DataFrame(post_retirement_investments, columns=['Age', 'SAVINGS', 'Annual Dividend', 'Monthly Dividend'])
69
+ df['Monthly Expenses'] = adjusted_monthly_expenses
70
+
71
+ # κ·Έλž˜ν”„ 생성
72
+ plt.figure(figsize=(10, 6))
73
+ plt.plot(df['Age'], df['Monthly Dividend'], label='Monthly Dividend')
74
+ plt.plot(df['Age'], df['Monthly Expenses'], label='Monthly Expenses', linestyle='--')
75
+ plt.xlabel('Age')
76
+ plt.ylabel('Amount')
77
+ plt.title('Monthly Dividend vs Monthly Expenses (Adjusted for Inflation)')
78
+ plt.legend()
79
+ plt.grid(True)
80
+
81
+ # κ·Έλž˜ν”„λ₯Ό μ΄λ―Έμ§€λ‘œ λ³€ν™˜
82
+ buffer = BytesIO()
83
+ plt.savefig(buffer, format='png')
84
+ buffer.seek(0)
85
+ img_str = base64.b64encode(buffer.read()).decode('utf-8')
86
+ plt.close()
87
+
88
  # style.cssμ—μ„œ CSS 읽기
89
  css = load_css()
90
 
91
+ # CSV 데이터 생성
92
+ csv_data = df.to_csv(index=False)
93
+ csv_base64 = base64.b64encode(csv_data.encode()).decode()
94
+
95
  # 은퇴 κ³„νšμ— λŒ€ν•œ HTML κ²°κ³Ό 생성
96
  result_html = css + f"""
97
  <div class="wrap-text" style="box-shadow: 0 0.25rem 0.5rem rgba(0, 0, 0, 0.1); border-radius: 0.5rem; padding: 3rem; position: relative; width: 100%; padding: 1.5rem;">
 
117
  <hr style="margin: 1.5rem 0;">
118
  </div>
119
  </div>
120
+ <div>
121
+ <img src="data:image/png;base64,{img_str}" alt="Monthly Dividend vs Monthly Expenses (Adjusted for Inflation)" style="max-width: 100%; height: auto;"/>
122
+ </div>
123
+ </div>
124
+ <div style="display: flex; align-items: center; justify-content: space-between;">
125
+ <h3>Dividend Income After Retirement</h3>
126
+ <a href="data:text/csv;base64,{csv_base64}" download="retirement_planning.csv" style="padding: 10px 20px; border: 1px solid; border-radius: 5px; background-color: #1678fb; color: white; text-decoration: none;">Download CSV</a>
127
  </div>
 
128
  <div class='table-container'>
129
  <table>
130
  <thead>
 
133
  <th>SAVINGS</th>
134
  <th>Annual</th>
135
  <th>Monthly</th>
136
+ <th>Expenses</th>
137
  </tr>
138
  </thead>
139
  <tbody>
140
  """
141
 
142
  # 각 연도별 νˆ¬μžμ™€ λ°°λ‹Ή μˆ˜μ΅μ„ ν…Œμ΄λΈ”μ— μΆ”κ°€
143
+ for age, investment, annual_dividend_income, monthly_dividend_income, monthly_exp in zip(df['Age'], df['SAVINGS'], df['Annual Dividend'], df['Monthly Dividend'], df['Monthly Expenses']):
144
  result_html += f"""
145
  <tr>
146
  <td>{age}</td>
147
  <td>{investment:,.0f}</td>
148
  <td>{annual_dividend_income:,.0f}</td>
149
  <td>{monthly_dividend_income:,.0f}</td>
150
+ <td>{monthly_exp:,.0f}</td>
151
  </tr>
152
  """
153
 
style.css CHANGED
@@ -142,6 +142,7 @@
142
  }
143
  }
144
 
 
145
  .table-container {
146
  width: 100%;
147
  overflow: auto;
@@ -163,12 +164,9 @@
163
  background-color: var(--background-color-light);
164
  }
165
 
166
- .table-container tr:hover td {
167
- background: #e7f9ef;
168
- }
169
-
170
  .table-container th {
171
  background-color: var(--highlight-color-light);
 
172
  position: sticky;
173
  top: 0;
174
  z-index: 2;
@@ -185,6 +183,16 @@
185
  z-index: 3;
186
  }
187
 
 
 
 
 
 
 
 
 
 
 
188
  @media (prefers-color-scheme: dark) {
189
  .table-container {
190
  border: 1px hidden #444;
@@ -209,5 +217,14 @@
209
  .table-container tr:hover td {
210
  background: #e7f9ef;
211
  color: #000;
 
 
 
212
  }
213
  }
 
 
 
 
 
 
 
142
  }
143
  }
144
 
145
+ /* κΈ°λ³Έ ν…Œμ΄λΈ” μŠ€νƒ€μΌ */
146
  .table-container {
147
  width: 100%;
148
  overflow: auto;
 
164
  background-color: var(--background-color-light);
165
  }
166
 
 
 
 
 
167
  .table-container th {
168
  background-color: var(--highlight-color-light);
169
+ color: var(--header-color-light); /* 라이트 λͺ¨λ“œμ—μ„œ 타이틀 색상을 μ„€μ • */
170
  position: sticky;
171
  top: 0;
172
  z-index: 2;
 
183
  z-index: 3;
184
  }
185
 
186
+ /* λ§ˆμš°μŠ€μ˜€λ²„ 효과 */
187
+ .table-container tr:hover td {
188
+ background: #e7f9ef;
189
+ color: #000;
190
+ border: 1px solid #4caf50;
191
+ transform: scale(1.02);
192
+ transition: all 0.3s ease;
193
+ }
194
+
195
+ /* μ–΄λ‘μš΄ ν…Œλ§ˆ 적용 */
196
  @media (prefers-color-scheme: dark) {
197
  .table-container {
198
  border: 1px hidden #444;
 
217
  .table-container tr:hover td {
218
  background: #e7f9ef;
219
  color: #000;
220
+ border: 1px solid #4caf50;
221
+ transform: scale(1.02);
222
+ transition: all 0.3s ease;
223
  }
224
  }
225
+
226
+ /* 좔가적인 λ§ˆμš°μŠ€μ˜€λ²„ 효과 */
227
+ .table-container tr:hover td {
228
+ text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.2);
229
+ cursor: pointer;
230
+ }