Hakureirm commited on
Commit
9c02682
·
verified ·
1 Parent(s): 5801ff5

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +62 -48
app.py CHANGED
@@ -1,7 +1,7 @@
1
- import gradio as gr
2
- import pandas as pd
3
  import numpy as np
4
- import plotly.graph_objects as go
5
 
6
  def calculate_schedule(
7
  principal: float,
@@ -9,37 +9,50 @@ def calculate_schedule(
9
  annual_rate: float,
10
  compounding: str,
11
  deposit_freq: str,
 
 
12
  display_freq: str,
13
  years: int,
14
  stop_deposit_year: int
15
  ):
 
 
 
 
 
 
 
 
16
  freq_map = {"Annual": 1, "Monthly": 12, "Daily": 365}
17
  m_comp = freq_map[compounding]
18
  m_dep = freq_map[deposit_freq]
 
19
 
20
  total_days = years * 365
21
  comp_interval = 365 // m_comp
22
  dep_interval = 365 // m_dep
23
  stop_day = stop_deposit_year * 365
24
 
25
- balance = principal
26
- deposit_count = 0
27
- schedule = []
 
28
 
29
  for day in range(1, total_days + 1):
30
- # 复利增长
31
  if compounding == "Daily":
32
  balance *= 1 + (annual_rate / 100) / 365
33
- else:
34
- if day % comp_interval == 0:
35
- balance *= 1 + (annual_rate / 100) / m_comp
36
-
37
- # 定投执行
38
  if day <= stop_day and day % dep_interval == 0:
39
- balance += deposit
40
  deposit_count += 1
 
 
 
41
 
42
- # 记录粒度
43
  record = False
44
  if display_freq == "Daily":
45
  record = True
@@ -50,81 +63,82 @@ def calculate_schedule(
50
  elif display_freq == "Yearly" and day % 365 == 0:
51
  record = True
52
  period = day // 365
53
-
54
  if record:
55
- total_inv = principal + deposit_count * deposit
56
  fv = balance
57
  schedule.append({
58
  display_freq: period,
59
  "Future Value (RMB)": fv,
60
- "Total Invested (RMB)": total_inv,
61
- "Interest Earned (RMB)": fv - total_inv,
62
  })
63
 
64
- # 构造 DataFrame 并新增“利息增量”列
65
  df = pd.DataFrame(schedule).round(2)
66
- df["Interest Increment (RMB)"] = df["Interest Earned (RMB)"].diff().fillna(0).round(2)
 
67
 
68
- # 绘制未来价值折线图
69
- fig_line = go.Figure()
70
- fig_line.add_trace(go.Scatter(
71
  x=df[display_freq],
72
  y=df["Future Value (RMB)"],
73
  mode='lines+markers',
74
- name='Future Value',
75
- line=dict(color='blue')
76
  ))
77
  fig_line.update_layout(
78
  title=f"Compound Growth over Time ({display_freq})",
79
  xaxis_title=display_freq,
80
  yaxis_title="Future Value (RMB)",
81
- template="plotly_white"
82
  )
83
 
84
- # 绘制利息增量柱状
85
- fig_bar = go.Figure()
86
- fig_bar.add_trace(go.Bar(
87
  x=df[display_freq],
88
  y=df["Interest Increment (RMB)"],
89
- name='Interest Increment',
90
- marker_color='orange'
91
  ))
92
- fig_bar.update_layout(
93
  title=f"Interest Increment per {display_freq}",
94
  xaxis_title=display_freq,
95
  yaxis_title="Interest Increment (RMB)",
96
  template="plotly_white"
97
  )
98
 
99
- return df, fig_line, fig_bar
100
 
101
  with gr.Blocks() as demo:
102
  gr.Markdown("## 复利计算器\n填写参数后点击“计算”查看结果")
103
-
104
  with gr.Row():
105
- principal = gr.Number(label="初始本金 (RMB)", value=20000)
106
- deposit = gr.Number(label="每次定投 (RMB)", value=5000)
107
- annual_rate = gr.Number(label="年化收益率 (%)", value=10.22)
108
-
 
 
 
 
 
 
109
  with gr.Row():
110
- compounding = gr.Radio(choices=["Annual", "Monthly", "Daily"], label="复利频率", value="Monthly")
111
- deposit_freq = gr.Radio(choices=["Annual", "Monthly", "Daily"], label="定投频率", value="Monthly")
112
- display_freq = gr.Radio(choices=["Yearly", "Monthly", "Daily"], label="结果展示频率", value="Yearly")
113
  years = gr.Slider(1, 50, value=41, label="计算年限 (年)")
114
  stop_deposit_year = gr.Slider(0, 50, value=41, label="何年后停止定投 (年)")
115
-
116
- compute_btn = gr.Button("计算", variant="primary")
117
 
118
- result_table = gr.Dataframe(interactive=False)
119
- result_plot = gr.Plot()
120
- interest_plot = gr.Plot()
 
121
 
122
  compute_btn.click(
123
  fn=calculate_schedule,
124
  inputs=[
125
  principal, deposit, annual_rate,
126
- compounding, deposit_freq, display_freq,
127
- years, stop_deposit_year
 
128
  ],
129
  outputs=[result_table, result_plot, interest_plot]
130
  )
 
1
+ import gradio as gr # UI 框架 :contentReference[oaicite:10]{index=10}
2
+ import pandas as pd # 表格处理 :contentReference[oaicite:11]{index=11}
3
  import numpy as np
4
+ import plotly.graph_objects as go # 用于瀑布图和折线图 :contentReference[oaicite:12]{index=12}
5
 
6
  def calculate_schedule(
7
  principal: float,
 
9
  annual_rate: float,
10
  compounding: str,
11
  deposit_freq: str,
12
+ inflation_rate: float,
13
+ inflation_freq: str,
14
  display_freq: str,
15
  years: int,
16
  stop_deposit_year: int
17
  ):
18
+ """
19
+ - compounding: 复利频率 (Annual/Monthly/Daily)
20
+ - deposit_freq: 定投频率 (Annual/Monthly/Daily)
21
+ - inflation_rate & inflation_freq: 定投膨胀率与频率
22
+ - stop_deposit_year: 第几年后停止定投
23
+ - display_freq: 结果展示频率 (Yearly/Monthly/Daily)
24
+ """
25
+ # 频率映射
26
  freq_map = {"Annual": 1, "Monthly": 12, "Daily": 365}
27
  m_comp = freq_map[compounding]
28
  m_dep = freq_map[deposit_freq]
29
+ m_inf = freq_map[inflation_freq]
30
 
31
  total_days = years * 365
32
  comp_interval = 365 // m_comp
33
  dep_interval = 365 // m_dep
34
  stop_day = stop_deposit_year * 365
35
 
36
+ balance = principal
37
+ total_invested = principal
38
+ deposit_count = 0
39
+ schedule = []
40
 
41
  for day in range(1, total_days + 1):
42
+ # 复利增长:每日或周期性触发 :contentReference[oaicite:13]{index=13}
43
  if compounding == "Daily":
44
  balance *= 1 + (annual_rate / 100) / 365
45
+ elif day % comp_interval == 0:
46
+ balance *= 1 + (annual_rate / 100) / m_comp
47
+
48
+ # 定投执行:仅在 stop_day 之前且周期点加入膨胀后金额 :contentReference[oaicite:14]{index=14}
 
49
  if day <= stop_day and day % dep_interval == 0:
 
50
  deposit_count += 1
51
+ amount = deposit * (1 + (inflation_rate/100)/m_inf) ** (deposit_count - 1)
52
+ balance += amount
53
+ total_invested += amount
54
 
55
+ # 展示粒度记录
56
  record = False
57
  if display_freq == "Daily":
58
  record = True
 
63
  elif display_freq == "Yearly" and day % 365 == 0:
64
  record = True
65
  period = day // 365
66
+
67
  if record:
 
68
  fv = balance
69
  schedule.append({
70
  display_freq: period,
71
  "Future Value (RMB)": fv,
72
+ "Total Invested (RMB)": total_invested,
73
+ "Interest Earned (RMB)": fv - total_invested,
74
  })
75
 
76
+ # 构造 DataFrame 并保留两位小数 :contentReference[oaicite:15]{index=15}
77
  df = pd.DataFrame(schedule).round(2)
78
+ df["Interest Increment (RMB)"] = df["Interest Earned (RMB)"] \
79
+ .diff().fillna(0).round(2)
80
 
81
+ # 折线图:Future Value :contentReference[oaicite:16]{index=16}
82
+ fig_line = go.Figure(go.Scatter(
 
83
  x=df[display_freq],
84
  y=df["Future Value (RMB)"],
85
  mode='lines+markers',
86
+ name='Future Value'
 
87
  ))
88
  fig_line.update_layout(
89
  title=f"Compound Growth over Time ({display_freq})",
90
  xaxis_title=display_freq,
91
  yaxis_title="Future Value (RMB)",
92
+ template="plotly_white" # 专业配色 :contentReference[oaicite:17]{index=17}
93
  )
94
 
95
+ # 瀑布:Interest Increment :contentReference[oaicite:18]{index=18}
96
+ fig_waterfall = go.Figure(go.Waterfall(
 
97
  x=df[display_freq],
98
  y=df["Interest Increment (RMB)"],
99
+ measure=["relative"] * len(df),
100
+ name="Interest Increment"
101
  ))
102
+ fig_waterfall.update_layout(
103
  title=f"Interest Increment per {display_freq}",
104
  xaxis_title=display_freq,
105
  yaxis_title="Interest Increment (RMB)",
106
  template="plotly_white"
107
  )
108
 
109
+ return df, fig_line, fig_waterfall
110
 
111
  with gr.Blocks() as demo:
112
  gr.Markdown("## 复利计算器\n填写参数后点击“计算”查看结果")
113
+
114
  with gr.Row():
115
+ principal = gr.Number(label="初始本金 (RMB)", value=20000)
116
+ deposit = gr.Number(label="每次定投 (RMB)", value=5000)
117
+ annual_rate = gr.Number(label="年化收益率 (%)", value=10.22)
118
+
119
+ with gr.Row():
120
+ compounding = gr.Radio(choices=["Annual","Monthly","Daily"], label="复利频率", value="Monthly")
121
+ deposit_freq = gr.Radio(choices=["Annual","Monthly","Daily"], label="定投频率", value="Monthly")
122
+ inflation_rate = gr.Number(label="定投膨胀率 (%)", value=0.0)
123
+ inflation_freq = gr.Radio(choices=["Annual","Monthly","Daily"], label="膨胀频率", value="Annual")
124
+
125
  with gr.Row():
126
+ display_freq = gr.Radio(choices=["Yearly","Monthly","Daily"], label="结果展示频率", value="Yearly")
 
 
127
  years = gr.Slider(1, 50, value=41, label="计算年限 (年)")
128
  stop_deposit_year = gr.Slider(0, 50, value=41, label="何年后停止定投 (年)")
 
 
129
 
130
+ compute_btn = gr.Button("计算", variant="primary") # 按钮触发 :contentReference[oaicite:19]{index=19}
131
+ result_table = gr.Dataframe(interactive=False)
132
+ result_plot = gr.Plot()
133
+ interest_plot = gr.Plot()
134
 
135
  compute_btn.click(
136
  fn=calculate_schedule,
137
  inputs=[
138
  principal, deposit, annual_rate,
139
+ compounding, deposit_freq,
140
+ inflation_rate, inflation_freq,
141
+ display_freq, years, stop_deposit_year
142
  ],
143
  outputs=[result_table, result_plot, interest_plot]
144
  )