hermanda commited on
Commit
cc83ffd
·
verified ·
1 Parent(s): 8d0a6ac

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +269 -0
app.py ADDED
@@ -0,0 +1,269 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ import matplotlib.pyplot as plt
3
+ from matplotlib.ticker import FuncFormatter
4
+ import polars as pl
5
+ import gradio as gr
6
+
7
+ def calculate_mortgage(principal, annual_interest_rate, years, compound_yearly=True):
8
+ if compound_yearly:
9
+ # Convert annual rate to monthly effective rate for yearly compounding
10
+ monthly_interest_rate = (1 + annual_interest_rate) ** (1/12) - 1
11
+ else:
12
+ monthly_interest_rate = annual_interest_rate / 12
13
+
14
+ months = years * 12
15
+ if monthly_interest_rate == 0:
16
+ return principal / months
17
+
18
+ mortgage_payment = (
19
+ principal * monthly_interest_rate * (1 + monthly_interest_rate) ** months
20
+ ) / ((1 + monthly_interest_rate) ** months - 1)
21
+ return mortgage_payment
22
+
23
+ def generate_amortization_schedule(principal, annual_interest_rate, years):
24
+ monthly_payment = calculate_mortgage(principal, annual_interest_rate, years)
25
+ monthly_rate = annual_interest_rate / 12
26
+ months = years * 12
27
+ schedule = []
28
+ remaining_balance = principal
29
+
30
+ for month in range(1, months + 1):
31
+ interest_payment = remaining_balance * monthly_rate
32
+ principal_payment = monthly_payment - interest_payment
33
+ remaining_balance -= principal_payment
34
+ schedule.append({
35
+ "month": month,
36
+ "remaining_balance": remaining_balance,
37
+ "payment": monthly_payment,
38
+ "principal": principal_payment,
39
+ "interest": interest_payment,
40
+ })
41
+ return schedule
42
+
43
+ class FlatInvestmentParameters:
44
+ flat_price = 2000000
45
+ one_time_payment = 100000
46
+ yearly_interest_rate = 0.05
47
+ mortgage_years = 30
48
+ initial_rent = 12000
49
+ yearly_rent_increase = 0.05
50
+ yearly_flat_appreciation = 0.07
51
+ down_payment_percentage = 0.1
52
+
53
+ def calculate_flat_investment(flatInvestmentParameters: FlatInvestmentParameters):
54
+ flat_price = flatInvestmentParameters.flat_price
55
+ one_time_payment = flatInvestmentParameters.one_time_payment
56
+ interest_rate = flatInvestmentParameters.yearly_interest_rate
57
+ mortgage_years = flatInvestmentParameters.mortgage_years
58
+ rent_current = flatInvestmentParameters.initial_rent
59
+ rent_increase = flatInvestmentParameters.yearly_rent_increase
60
+ flat_appreciation = flatInvestmentParameters.yearly_flat_appreciation
61
+ down_payment_percentage = flatInvestmentParameters.down_payment_percentage
62
+
63
+ down_payment = flat_price * down_payment_percentage
64
+ initial_investment = down_payment + one_time_payment
65
+ loan_amount = flat_price * (1 - down_payment_percentage)
66
+
67
+ amortization = generate_amortization_schedule(loan_amount, interest_rate, mortgage_years)
68
+ total_months = mortgage_years * 12
69
+
70
+ months = []
71
+ net_worth = []
72
+ cash_balance = [-initial_investment]
73
+ rent_received = []
74
+ cash_flow = []
75
+
76
+ for i, month_data in enumerate(amortization):
77
+ current_month = i + 1
78
+ current_year = (current_month - 1) // 12
79
+ current_year_float = (current_month - 1) / 12
80
+
81
+ current_rent = rent_current * (1 + rent_increase) ** current_year # Removed *0.9
82
+ current_flat_price = flat_price * (1 + flat_appreciation) ** current_year_float
83
+ rent_received.append(current_rent)
84
+
85
+ new_cash = cash_balance[-1] + current_rent - month_data["payment"]
86
+ cash_flow_this_month = current_rent - month_data["payment"]
87
+ cash_flow.append(cash_flow_this_month)
88
+ cash_balance.append(new_cash)
89
+
90
+ months.append(current_month)
91
+ current_net_worth = (current_flat_price - month_data["remaining_balance"]) + cash_balance[-1]
92
+ net_worth.append(current_net_worth)
93
+
94
+ debt = [month["remaining_balance"] for month in amortization]
95
+ cash_flow_cumulative = np.cumsum(cash_flow)
96
+
97
+ monthly_roi = []
98
+ for month in range(1, total_months + 1):
99
+ total_cashflow = sum(cash_flow[:month])
100
+ mortgage_current = debt[month-1]
101
+ flat_price_current = flat_price * (1 + flat_appreciation) ** ((month - 1) / 12) # Corrected
102
+ roi = (total_cashflow - mortgage_current + flat_price_current - initial_investment) / initial_investment
103
+ monthly_roi.append(roi)
104
+
105
+ values = [{
106
+ "month": i,
107
+ "rent": rent_received[i],
108
+ "payment": amortization[i]["payment"],
109
+ "cash_flow": cash_flow[i],
110
+ "debt": debt[i],
111
+ "cash_flow_cumulative": cash_flow_cumulative[i],
112
+ "flat_price": flat_price * (1 + flat_appreciation) ** (i / 12),
113
+ "net_worth": net_worth[i],
114
+ "roi": monthly_roi[i],
115
+ } for i in range(total_months)]
116
+ return values
117
+
118
+
119
+ def create_plots(investment_history, mortgage_years):
120
+ # Create formatter function
121
+ def currency(x, pos):
122
+ return f"{x/1000000:,.0f}M CZK"
123
+
124
+ # Create figure with 3 subplots
125
+ fig = plt.figure(figsize=(15, 12))
126
+
127
+ # First subplot - Yearly view
128
+ ax1 = plt.subplot(311)
129
+ months = investment_history["month"].to_numpy()
130
+ debt = investment_history["debt"].to_numpy()
131
+ flat_price = investment_history["flat_price"].to_numpy()
132
+ cash_flow_cumulative = investment_history["cash_flow_cumulative"].to_numpy()
133
+ net_worth = investment_history["net_worth"].to_numpy()
134
+
135
+ yearly_mask = [i % 12 == 11 for i in range(len(months))]
136
+ ax1.plot(months[yearly_mask] / 12, debt[yearly_mask], label="Debt")
137
+ ax1.plot(months[yearly_mask] / 12, flat_price[yearly_mask], label="Flat Price")
138
+ ax1.plot(months[yearly_mask] / 12, cash_flow_cumulative[yearly_mask], label="Total Cash Flow")
139
+ ax1.plot(months[yearly_mask] / 12, net_worth[yearly_mask], label="Net Worth")
140
+ ax1.set_title("Yearly View")
141
+ ax1.set_xlabel("Years")
142
+ ax1.legend()
143
+ ax1.yaxis.set_major_formatter(FuncFormatter(currency))
144
+ ax1.grid(True)
145
+
146
+ # Second subplot - Monthly view
147
+ ax2 = plt.subplot(312)
148
+ ax2.plot(months, debt, label="Debt")
149
+ ax2.plot(months, flat_price, label="Flat Price")
150
+ ax2.plot(months, cash_flow_cumulative, label="Total Cash Flow")
151
+ ax2.plot(months, net_worth, label="Net Worth")
152
+ ax2.set_title("Monthly View")
153
+ ax2.set_xlabel("Months")
154
+ ax2.legend()
155
+ ax2.yaxis.set_major_formatter(FuncFormatter(currency))
156
+ ax2.grid(True)
157
+
158
+ # Third subplot - ROI
159
+ ax3 = plt.subplot(313)
160
+ ax3.plot(range(1, mortgage_years + 1), investment_history["roi"].to_numpy()[yearly_mask])
161
+ ax3.set_title("Yearly ROI")
162
+ ax3.set_xlabel("Years")
163
+ ax3.set_ylabel("ROI")
164
+ ax3.yaxis.set_major_formatter(FuncFormatter(lambda x, _: f"{x:.0%}"))
165
+ ax3.grid(True)
166
+
167
+ plt.tight_layout()
168
+ return fig
169
+
170
+ def calculate_investment(
171
+ flat_price: float,
172
+ one_time_payment: float,
173
+ yearly_interest_rate: float,
174
+ mortgage_years: int,
175
+ initial_rent: float,
176
+ yearly_rent_increase: float,
177
+ yearly_flat_appreciation: float,
178
+ down_payment_percentage: float
179
+ ):
180
+ params = FlatInvestmentParameters()
181
+ params.flat_price = flat_price
182
+ params.one_time_payment = one_time_payment
183
+ params.yearly_interest_rate = yearly_interest_rate
184
+ params.mortgage_years = mortgage_years
185
+ params.initial_rent = initial_rent
186
+ params.yearly_rent_increase = yearly_rent_increase
187
+ params.yearly_flat_appreciation = yearly_flat_appreciation
188
+ params.down_patment_percentage = down_payment_percentage
189
+
190
+ # Calculate initial investment components
191
+ down_payment = flat_price * down_payment_percentage
192
+ initial_investment = down_payment + one_time_payment
193
+ monthly_payment = calculate_mortgage(flat_price * (1 - down_payment_percentage), yearly_interest_rate, mortgage_years)
194
+
195
+ investment_summary = [
196
+ ["Down Payment", f"{down_payment:,.0f} CZK"],
197
+ ["One Time Payment", f"{one_time_payment:,.0f} CZK"],
198
+ ["Total Initial Investment", f"{initial_investment:,.0f} CZK"],
199
+ ["Monthly Payment", f"{monthly_payment:,.0f} CZK"]
200
+ ]
201
+
202
+ investment_history = calculate_flat_investment(params)
203
+ investment_df = pl.DataFrame(investment_history)
204
+
205
+ plot = create_plots(investment_df, mortgage_years)
206
+
207
+ display_df = investment_df.select([
208
+ pl.col("month"),
209
+ pl.col("rent").round(0),
210
+ pl.col("payment").round(0),
211
+ pl.col("cash_flow").round(0),
212
+ pl.col("debt").round(0),
213
+ pl.col("cash_flow_cumulative").round(0),
214
+ pl.col("flat_price").round(0),
215
+ pl.col("net_worth").round(0),
216
+ pl.col("roi").round(2).map_elements(lambda x: f"{x:.0%}")
217
+ ])
218
+
219
+ return plot, display_df.to_pandas(), investment_summary
220
+
221
+ def create_gradio_interface():
222
+ with gr.Blocks() as app:
223
+ gr.Markdown("# Flat Investment Calculator")
224
+
225
+ with gr.Row():
226
+ with gr.Column():
227
+ flat_price = gr.Number(value=2000000, label="Flat Price (CZK)")
228
+ one_time_payment = gr.Number(value=100000, label="One Time Payment (CZK)")
229
+ yearly_interest_rate = gr.Slider(minimum=0, maximum=0.15, value=0.05, step=0.001, label="Yearly Interest Rate")
230
+ mortgage_years = gr.Slider(minimum=5, maximum=40, value=30, step=1, label="Mortgage Years")
231
+ with gr.Column():
232
+ initial_rent = gr.Number(value=12000, label="Initial Monthly Rent (CZK)")
233
+ yearly_rent_increase = gr.Slider(minimum=0, maximum=0.15, value=0.05, step=0.001, label="Yearly Rent Increase")
234
+ yearly_flat_appreciation = gr.Slider(minimum=0, maximum=0.15, value=0.07, step=0.001, label="Yearly Flat Appreciation")
235
+ down_payment_percentage = gr.Slider(minimum=0.1, maximum=1.0, value=0.1, step=0.05, label="Down Payment Percentage")
236
+
237
+ calculate_btn = gr.Button("Calculate")
238
+
239
+ with gr.Row():
240
+ investment_summary = gr.Dataframe(
241
+ headers=["Item", "Amount"],
242
+ label="Investment Summary",
243
+ value=[["", ""]], # Initial empty value
244
+ interactive=False,
245
+ wrap=True
246
+ )
247
+
248
+ output_plot = gr.Plot()
249
+ output_table = gr.DataFrame()
250
+
251
+ calculate_btn.click(
252
+ calculate_investment,
253
+ inputs=[
254
+ flat_price,
255
+ one_time_payment,
256
+ yearly_interest_rate,
257
+ mortgage_years,
258
+ initial_rent,
259
+ yearly_rent_increase,
260
+ yearly_flat_appreciation,
261
+ down_payment_percentage
262
+ ],
263
+ outputs=[output_plot, output_table, investment_summary]
264
+ )
265
+ return app
266
+
267
+ if __name__ == "__main__":
268
+ app = create_gradio_interface()
269
+ app.launch()