Create app.py with basic calculators
Browse files
app.py
ADDED
@@ -0,0 +1,529 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import matplotlib.pyplot as plt
|
2 |
+
import numpy_financial as npf
|
3 |
+
import streamlit as st
|
4 |
+
import pandas as pd
|
5 |
+
import numpy as np
|
6 |
+
|
7 |
+
def calculate_loan_shift_savings(current_balance, current_rate, new_rate, remaining_term, processing_fee):
|
8 |
+
# Calculate monthly interest rates
|
9 |
+
monthly_current_rate = current_rate / 12 / 100
|
10 |
+
monthly_new_rate = new_rate / 12 / 100
|
11 |
+
|
12 |
+
# Calculate monthly payments for current and new loan
|
13 |
+
current_monthly_payment = npf.pmt(monthly_current_rate, remaining_term, -current_balance)
|
14 |
+
new_monthly_payment = npf.pmt(monthly_new_rate, remaining_term, -current_balance)
|
15 |
+
|
16 |
+
# Calculate total payments for current and new loan
|
17 |
+
total_current_payment = current_monthly_payment * remaining_term
|
18 |
+
total_new_payment = new_monthly_payment * remaining_term + processing_fee
|
19 |
+
|
20 |
+
# Calculate savings
|
21 |
+
savings = total_current_payment - total_new_payment
|
22 |
+
return savings
|
23 |
+
|
24 |
+
def loan_shift_decision_tab():
|
25 |
+
st.header("Should I Shift My Loan Calculator")
|
26 |
+
|
27 |
+
current_balance = st.number_input("Current Loan Balance", min_value=0.0)
|
28 |
+
current_rate = st.number_input("Current Interest Rate (Annual %)", min_value=0.0)
|
29 |
+
new_rate = st.number_input("New Interest Rate (Annual %)", min_value=0.0)
|
30 |
+
remaining_term = st.number_input("Remaining Term of Loan (Months)", min_value=1)
|
31 |
+
processing_fee = st.number_input("Processing Fee for New Loan", min_value=0.0)
|
32 |
+
|
33 |
+
if st.button("Calculate Savings"):
|
34 |
+
savings = calculate_loan_shift_savings(current_balance, current_rate, new_rate, remaining_term, processing_fee)
|
35 |
+
if savings > 0:
|
36 |
+
st.success(f"Shifting your loan saves you ${savings:,.2f} over the remaining term of the loan.")
|
37 |
+
else:
|
38 |
+
st.error(f"Shifting your loan does not save money. It costs you an additional ${-savings:,.2f}.")
|
39 |
+
|
40 |
+
|
41 |
+
def calculate_real_future_values(principal, interest_rate, inflation_rate, years):
|
42 |
+
return np.array([principal * ((1 + interest_rate / 100) ** year) / ((1 + inflation_rate / 100) ** year) for year in np.arange(1, years + 1)])
|
43 |
+
|
44 |
+
def inflation_calculator_tab():
|
45 |
+
st.header("Multiple Investments Growth Calculator with Inflation")
|
46 |
+
st.write("Calculate and compare the real value growth of multiple investments considering inflation.")
|
47 |
+
|
48 |
+
# Dynamic input fields for multiple amounts, rates, and inflation rate
|
49 |
+
entries = []
|
50 |
+
n_entries = st.number_input("Number of Investments", min_value=1, max_value=10, value=1, step=1)
|
51 |
+
for i in range(n_entries):
|
52 |
+
col1, col2 = st.columns(2)
|
53 |
+
with col1:
|
54 |
+
amount = st.number_input(f"Amount {i+1}", min_value=0.0, value=1000.0, format="%.2f")
|
55 |
+
with col2:
|
56 |
+
rate = st.number_input(f"Interest Rate {i+1} (%)", min_value=0.0, value=5.0, format="%.2f")
|
57 |
+
entries.append((amount, rate))
|
58 |
+
|
59 |
+
inflation_rate = st.number_input("Annual Inflation Rate (%)", min_value=0.0, value=2.0, format="%.2f")
|
60 |
+
years = st.number_input("Number of Years:", min_value=1, max_value=100, step=1)
|
61 |
+
|
62 |
+
if st.button('Calculate and Plot'):
|
63 |
+
plt.figure(figsize=(10, 6))
|
64 |
+
combined_future_value = np.zeros(years)
|
65 |
+
|
66 |
+
for i, (amount, rate) in enumerate(entries):
|
67 |
+
real_future_values = calculate_real_future_values(amount, rate, inflation_rate, years)
|
68 |
+
combined_future_value += real_future_values
|
69 |
+
plt.plot(range(1, years + 1), real_future_values, label=f'Investment {i+1}')
|
70 |
+
|
71 |
+
plt.plot(range(1, years + 1), combined_future_value, label='Combined Investment (Adjusted for Inflation)', color='black', linestyle='--')
|
72 |
+
plt.title('Investment Real Value Growth Over Time Considering Inflation')
|
73 |
+
plt.xlabel('Years')
|
74 |
+
plt.ylabel('Real Future Value')
|
75 |
+
plt.legend()
|
76 |
+
st.pyplot(plt)
|
77 |
+
|
78 |
+
|
79 |
+
def calculate_emi(principal, annual_interest_rate, tenure_years):
|
80 |
+
monthly_interest_rate = annual_interest_rate / (12 * 100)
|
81 |
+
total_payments = tenure_years * 12
|
82 |
+
emi = principal * monthly_interest_rate / (1 - (1 + monthly_interest_rate) ** -total_payments)
|
83 |
+
return emi
|
84 |
+
|
85 |
+
def emi_breakdown(principal, annual_interest_rate, tenure_years):
|
86 |
+
monthly_interest_rate = annual_interest_rate / (12 * 100)
|
87 |
+
total_payments = tenure_years * 12
|
88 |
+
emi = calculate_emi(principal, annual_interest_rate, tenure_years)
|
89 |
+
balance = principal
|
90 |
+
emi_data = []
|
91 |
+
|
92 |
+
for month in range(1, total_payments + 1):
|
93 |
+
interest = balance * monthly_interest_rate
|
94 |
+
principal_payment = emi - interest
|
95 |
+
balance -= principal_payment
|
96 |
+
emi_data.append([month, emi, principal_payment, interest, balance])
|
97 |
+
|
98 |
+
return pd.DataFrame(emi_data, columns=["Month", "EMI", "Principal", "Interest", "Balance"])
|
99 |
+
|
100 |
+
def plot_emi_data(emi_df):
|
101 |
+
plt.figure(figsize=(10, 5))
|
102 |
+
plt.plot(emi_df['Month'], emi_df['Principal'], label='Principal Component')
|
103 |
+
plt.plot(emi_df['Month'], emi_df['Interest'], label='Interest Component')
|
104 |
+
plt.xlabel('Month')
|
105 |
+
plt.ylabel('Amount')
|
106 |
+
plt.title('EMI Components Over Time')
|
107 |
+
plt.legend()
|
108 |
+
st.pyplot(plt)
|
109 |
+
|
110 |
+
plt.figure(figsize=(10, 5))
|
111 |
+
plt.plot(emi_df['Month'], emi_df['Balance'], label='Remaining Balance')
|
112 |
+
plt.xlabel('Month')
|
113 |
+
plt.ylabel('Amount')
|
114 |
+
plt.title('Loan Balance Over Time')
|
115 |
+
plt.legend()
|
116 |
+
st.pyplot(plt)
|
117 |
+
|
118 |
+
def emi_calculator_tab():
|
119 |
+
st.header("EMI Calculator")
|
120 |
+
loan_amount = st.number_input("Loan Amount", min_value=0.0, value=100000.0, step=1000.0)
|
121 |
+
annual_interest_rate = st.number_input("Annual Interest Rate (%)", min_value=0.0, value=8.0, step=0.1)
|
122 |
+
tenure_years = st.number_input("Tenure (Years)", min_value=1, value=10, step=1)
|
123 |
+
|
124 |
+
if st.button('Calculate EMI'):
|
125 |
+
emi = calculate_emi(loan_amount, annual_interest_rate, tenure_years)
|
126 |
+
st.success(f"Monthly EMI: ₹ {emi:.2f}")
|
127 |
+
|
128 |
+
emi_df = emi_breakdown(loan_amount, annual_interest_rate, tenure_years)
|
129 |
+
plot_emi_data(emi_df)
|
130 |
+
st.write(emi_df)
|
131 |
+
|
132 |
+
def calculate_compound_interest(principal, annual_rate, compounding_frequency, years):
|
133 |
+
"""
|
134 |
+
Calculate the compound interest based on the given parameters.
|
135 |
+
"""
|
136 |
+
factor = {
|
137 |
+
"Monthly": 12,
|
138 |
+
"Quarterly": 4,
|
139 |
+
"Yearly": 1
|
140 |
+
}
|
141 |
+
n = factor[compounding_frequency]
|
142 |
+
amount = principal * ((1 + annual_rate/(100 * n)) ** (n * years))
|
143 |
+
return amount
|
144 |
+
|
145 |
+
def plot_growth(principal, annual_rate, compounding_frequency, years):
|
146 |
+
"""
|
147 |
+
Plot the returns of the investment over time.
|
148 |
+
"""
|
149 |
+
factor = {
|
150 |
+
"Monthly": 12,
|
151 |
+
"Quarterly": 4,
|
152 |
+
"Yearly": 1
|
153 |
+
}
|
154 |
+
n = factor[compounding_frequency]
|
155 |
+
times = np.linspace(0, years, years * n + 1)
|
156 |
+
future_values = principal * ((1 + annual_rate/(100 * n)) ** (n * times))
|
157 |
+
returns = future_values - principal
|
158 |
+
|
159 |
+
plt.figure(figsize=(10, 6))
|
160 |
+
plt.plot(times, returns, color='purple', linestyle='-', linewidth=2, label='Investment Returns')
|
161 |
+
plt.fill_between(times, returns, color='blue', alpha=0.3)
|
162 |
+
plt.title('Investment Returns Over Time')
|
163 |
+
plt.xlabel('Years')
|
164 |
+
plt.ylabel('Returns (Future Value - Principal)')
|
165 |
+
plt.legend()
|
166 |
+
st.pyplot(plt)
|
167 |
+
|
168 |
+
|
169 |
+
def plot_growth_old(principal, annual_rate, compounding_frequency, years):
|
170 |
+
"""
|
171 |
+
Plot the growth of the investment over time.
|
172 |
+
"""
|
173 |
+
factor = {
|
174 |
+
"Monthly": 12,
|
175 |
+
"Quarterly": 4,
|
176 |
+
"Yearly": 1
|
177 |
+
}
|
178 |
+
n = factor[compounding_frequency]
|
179 |
+
times = np.linspace(0, years, years * n + 1)
|
180 |
+
values = principal * ((1 + annual_rate/(100 * n)) ** (n * times))
|
181 |
+
|
182 |
+
plt.figure(figsize=(10, 6))
|
183 |
+
plt.plot(times, values, color='purple', linestyle='-', linewidth=2, label='Investment Growth')
|
184 |
+
plt.fill_between(times, values, color='blue', alpha=0.3)
|
185 |
+
plt.title('Compound Interest Growth Over Time')
|
186 |
+
plt.xlabel('Years')
|
187 |
+
plt.ylabel('Future Value')
|
188 |
+
plt.legend()
|
189 |
+
st.pyplot(plt)
|
190 |
+
|
191 |
+
def compound_interest_calculator():
|
192 |
+
st.header("Compound Interest Calculator")
|
193 |
+
st.write("Calculate the future value of your investment with compound interest.")
|
194 |
+
|
195 |
+
principal = st.number_input("Enter the principal amount:", min_value=0.0, value=10000.0, format="%.2f")
|
196 |
+
annual_rate = st.number_input("Enter the annual interest rate (%):", min_value=0.0, value=5.0, format="%.2f")
|
197 |
+
compounding_frequency = st.selectbox("Select the compounding frequency:", ["Monthly", "Quarterly", "Yearly"])
|
198 |
+
years = st.number_input("Enter the number of years:", min_value=1, max_value=50, value=10, step=1)
|
199 |
+
|
200 |
+
if st.button('Calculate and Plot'):
|
201 |
+
future_value = calculate_compound_interest(principal, annual_rate, compounding_frequency, years)
|
202 |
+
st.success(f"The future value of your investment is: ₹ {future_value:.2f}")
|
203 |
+
|
204 |
+
plot_growth(principal, annual_rate, compounding_frequency, years)
|
205 |
+
|
206 |
+
def calculate_fire_number(monthly_expenses, withdrawal_rate):
|
207 |
+
"""
|
208 |
+
Calculate the FIRE Number based on monthly expenses and withdrawal rate.
|
209 |
+
Annual expenses are derived by multiplying monthly expenses by 12.
|
210 |
+
"""
|
211 |
+
annual_expenses = monthly_expenses * 12
|
212 |
+
fire_number = annual_expenses / (withdrawal_rate / 100)
|
213 |
+
return fire_number
|
214 |
+
|
215 |
+
def fire_number_calculator():
|
216 |
+
st.header("FIRE Number Calculator")
|
217 |
+
st.write("Calculate the amount you need to achieve Financial Independence and Retire Early (FIRE) based on your monthly expenses.")
|
218 |
+
|
219 |
+
monthly_expenses = st.number_input("Enter your monthly expenses:", min_value=0.0, value=5000.0, format="%.2f")
|
220 |
+
withdrawal_rate = st.number_input("Enter your desired withdrawal rate (%):", min_value=1.0, max_value=10.0, value=4.0, format="%.2f")
|
221 |
+
|
222 |
+
if st.button('Calculate FIRE Number'):
|
223 |
+
fire_number = calculate_fire_number(monthly_expenses, withdrawal_rate)
|
224 |
+
st.success(f"Your FIRE Number is: ₹ {fire_number:.2f}")
|
225 |
+
|
226 |
+
def project_fd_value(principal, annual_rate, years):
|
227 |
+
return np.array([principal * ((1 + annual_rate) ** year) for year in range(1, years + 1)])
|
228 |
+
|
229 |
+
def plot_projections_with_fd(years, best_case_values, worst_case_values, fd_values):
|
230 |
+
plt.figure(figsize=(10, 6))
|
231 |
+
plt.plot(range(1, years + 1), best_case_values, label='Best Case', color='#1f77b4') # Blue
|
232 |
+
plt.plot(range(1, years + 1), worst_case_values, label='Worst Case', color='#ff7f0e') # Orange
|
233 |
+
plt.plot(range(1, years + 1), fd_values, label='FD Return', color='#2ca02c') # Green
|
234 |
+
plt.xlabel('Years')
|
235 |
+
plt.ylabel('Projected Value (₹)')
|
236 |
+
plt.yscale('log') # Set the y-axis to a logarithmic scale
|
237 |
+
plt.title('Investment Projections Over Time (Log Scale)')
|
238 |
+
plt.legend()
|
239 |
+
st.pyplot(plt)
|
240 |
+
|
241 |
+
def investment_projections(investment_amount, risk_appetite, years):
|
242 |
+
# Defining return rates for best and worst cases
|
243 |
+
if risk_appetite >= 75: # High Risk
|
244 |
+
best_case_rate = 0.15 # 15% optimistic annual return
|
245 |
+
worst_case_rate = -0.05 # -5% pessimistic annual return
|
246 |
+
elif 25 < risk_appetite < 75: # Medium Risk
|
247 |
+
best_case_rate = 0.10 # 10% optimistic annual return
|
248 |
+
worst_case_rate = 0.00 # 0% pessimistic annual return
|
249 |
+
else: # Low Risk
|
250 |
+
best_case_rate = 0.05 # 5% optimistic annual return
|
251 |
+
worst_case_rate = 0.01 # 1% pessimistic annual return
|
252 |
+
|
253 |
+
# Projecting future values
|
254 |
+
best_case_value = project_future_value(investment_amount, best_case_rate, years)
|
255 |
+
worst_case_value = project_future_value(investment_amount, worst_case_rate, years)
|
256 |
+
|
257 |
+
return best_case_value, worst_case_value
|
258 |
+
|
259 |
+
def plot_projections(years, best_case_values, worst_case_values):
|
260 |
+
plt.figure(figsize=(10, 6))
|
261 |
+
plt.plot(range(1, years + 1), best_case_values, label='Best Case', color='#1f77b4') # Blue
|
262 |
+
plt.plot(range(1, years + 1), worst_case_values, label='Worst Case', color='#ff7f0e') # Orange
|
263 |
+
plt.xlabel('Years')
|
264 |
+
plt.ylabel('Projected Value (₹)')
|
265 |
+
plt.title('Investment Projections Over Time')
|
266 |
+
plt.legend()
|
267 |
+
st.pyplot(plt)
|
268 |
+
|
269 |
+
def project_future_value(principal, annual_rate, years):
|
270 |
+
return np.array([principal * ((1 + annual_rate) ** year) for year in range(1, years + 1)])
|
271 |
+
|
272 |
+
def investment_advice(income, expenses, age, risk_appetite):
|
273 |
+
# Calculate the disposable income (income - expenses)
|
274 |
+
disposable_income = income - expenses
|
275 |
+
|
276 |
+
# Emergency Fund Recommendation
|
277 |
+
emergency_fund = expenses * 6 # 6 months of expenses
|
278 |
+
|
279 |
+
# Retirement Savings Recommendation (simplified example)
|
280 |
+
retirement_savings = disposable_income * 0.15 # 15% of disposable income
|
281 |
+
|
282 |
+
# Investment Allocation
|
283 |
+
if risk_appetite >= 75: # High Risk
|
284 |
+
stocks = disposable_income * 0.5 # 50% in stocks
|
285 |
+
bonds = disposable_income * 0.2 # 20% in bonds
|
286 |
+
mutual_funds = disposable_income * 0.3 # 30% in mutual funds
|
287 |
+
elif 25 < risk_appetite < 75: # Medium Risk
|
288 |
+
stocks = disposable_income * 0.3 # 30% in stocks
|
289 |
+
bonds = disposable_income * 0.4 # 40% in bonds
|
290 |
+
mutual_funds = disposable_income * 0.3 # 30% in mutual funds
|
291 |
+
else: # Low Risk
|
292 |
+
stocks = disposable_income * 0.1 # 10% in stocks
|
293 |
+
bonds = disposable_income * 0.6 # 60% in bonds
|
294 |
+
mutual_funds = disposable_income * 0.3 # 30% in mutual funds
|
295 |
+
|
296 |
+
return {
|
297 |
+
"Emergency Fund": emergency_fund,
|
298 |
+
"Retirement Savings": retirement_savings,
|
299 |
+
"Stocks": stocks,
|
300 |
+
"Bonds": bonds,
|
301 |
+
"Mutual Funds": mutual_funds
|
302 |
+
}
|
303 |
+
|
304 |
+
def investment_advisor():
|
305 |
+
st.title("Smart Income Investment Advisor")
|
306 |
+
|
307 |
+
income = st.number_input("Enter your monthly income:", min_value=0.0, format="%.2f")
|
308 |
+
expenses = st.number_input("Enter your monthly expenses:", min_value=0.0, format="%.2f")
|
309 |
+
age = st.number_input("Enter your age:", min_value=18, max_value=100, step=1)
|
310 |
+
risk_appetite = st.slider("Select your risk appetite (0 = Low, 100 = High):", 0, 100, 50)
|
311 |
+
|
312 |
+
fd_rate = st.number_input("Enter FD Interest Rate:", min_value = 0.1, max_value = 10.0, format="%.2f")
|
313 |
+
|
314 |
+
years = st.number_input("Investment Time Horizon (Years):", min_value=1, max_value=30, step=1)
|
315 |
+
|
316 |
+
if st.button("Get Investment Advice"):
|
317 |
+
advice = investment_advice(income, expenses, age, risk_appetite)
|
318 |
+
st.write(advice)
|
319 |
+
|
320 |
+
total_investment = advice["Stocks"] + advice["Bonds"] + advice["Mutual Funds"]
|
321 |
+
best_case_values, worst_case_values = investment_projections(total_investment, risk_appetite, years)
|
322 |
+
|
323 |
+
fd_values = project_fd_value(total_investment, fd_rate / 100, years)
|
324 |
+
|
325 |
+
st.write("Projection for your total investment:")
|
326 |
+
st.write(f"Best-case scenario (in {years} years): ₹ {best_case_values[-1]:.2f}")
|
327 |
+
st.write(f"Worst-case scenario (in {years} years): ₹ {worst_case_values[-1]:.2f}")
|
328 |
+
st.write(f"Fixed Deposit scenario (in {years} years): ₹ {fd_values[-1]:.2f}")
|
329 |
+
|
330 |
+
# Plot the projections with FD
|
331 |
+
plot_projections_with_fd(years, best_case_values, worst_case_values, fd_values)
|
332 |
+
|
333 |
+
def calculate_sip_returns(sip_amount, duration_years, rd_fd_rate, mf_rate, index_fund_rate):
|
334 |
+
# Convert annual rates to monthly rates
|
335 |
+
monthly_rd_fd_rate = rd_fd_rate / 12 / 100
|
336 |
+
monthly_mf_rate = mf_rate / 12 / 100
|
337 |
+
monthly_index_fund_rate = index_fund_rate / 12 / 100
|
338 |
+
|
339 |
+
# Total months
|
340 |
+
total_months = duration_years * 12
|
341 |
+
|
342 |
+
# RD/FD Returns Calculation (Compounded Monthly for simplification)
|
343 |
+
rd_fd_total = 0
|
344 |
+
for month in range(total_months):
|
345 |
+
rd_fd_total *= (1 + monthly_rd_fd_rate)
|
346 |
+
rd_fd_total += sip_amount
|
347 |
+
|
348 |
+
# Mutual Funds and Index Funds Returns Calculation (Compounded Monthly)
|
349 |
+
mf_total = 0
|
350 |
+
index_fund_total = 0
|
351 |
+
for month in range(total_months):
|
352 |
+
mf_total *= (1 + monthly_mf_rate)
|
353 |
+
mf_total += sip_amount
|
354 |
+
index_fund_total *= (1 + monthly_index_fund_rate)
|
355 |
+
index_fund_total += sip_amount
|
356 |
+
|
357 |
+
return rd_fd_total, mf_total, index_fund_total
|
358 |
+
|
359 |
+
def sip_return_comparator_tab():
|
360 |
+
st.header("SIP Return Comparator")
|
361 |
+
st.write("Compare the returns from different investment options based on your SIP.")
|
362 |
+
|
363 |
+
sip_amount = st.number_input("Enter your monthly SIP amount:", min_value=500.0, value=5000.0, format="%.2f")
|
364 |
+
duration_years = st.number_input("Enter the investment duration (in years):", min_value=1, max_value=30, value=5, step=1)
|
365 |
+
|
366 |
+
# Optional: Allow users to modify the default interest rates
|
367 |
+
rd_fd_rate = st.number_input("Enter RD/FD Interest Rate (% per annum):", min_value=0.0, value=6.0, format="%.2f")
|
368 |
+
mf_rate = st.number_input("Enter Mutual Funds Return Rate (% per annum):", min_value=0.0, value=12.0, format="%.2f")
|
369 |
+
index_fund_rate = st.number_input("Enter Index Funds Return Rate (% per annum):", min_value=0.0, value=10.0, format="%.2f")
|
370 |
+
|
371 |
+
if st.button('Calculate SIP Returns'):
|
372 |
+
rd_fd_returns, mf_returns, index_fund_returns = calculate_sip_returns(sip_amount, duration_years, rd_fd_rate, mf_rate, index_fund_rate)
|
373 |
+
st.success(f"RD/FD Returns: ₹ {rd_fd_returns:.2f}\nMutual Funds Returns: ₹ {mf_returns:.2f}\nIndex Funds Returns: ₹ {index_fund_returns:.2f}")
|
374 |
+
|
375 |
+
# Optional: Plotting the results for a visual comparison
|
376 |
+
labels = ['RD/FD', 'Mutual Funds', 'Index Funds']
|
377 |
+
returns = [rd_fd_returns, mf_returns, index_fund_returns]
|
378 |
+
colors = [(0.1, 0.2, 0.5, 0.7), (0.2, 0.6, 0.2, 0.7), (1.0, 0.5, 0.0, 0.7)] # RGBA format
|
379 |
+
plt.figure(figsize=(10, 6))
|
380 |
+
plt.bar(labels, returns, color=colors)
|
381 |
+
plt.title('SIP Returns Comparison')
|
382 |
+
plt.ylabel('Total Returns in ₹')
|
383 |
+
st.pyplot(plt)
|
384 |
+
|
385 |
+
|
386 |
+
def calculate_emi(principal, interest_rate, years):
|
387 |
+
monthly_interest_rate = interest_rate / (12 * 100)
|
388 |
+
total_payments = years * 12
|
389 |
+
emi = principal * monthly_interest_rate * ((1 + monthly_interest_rate) ** total_payments) / ((1 + monthly_interest_rate) ** total_payments - 1)
|
390 |
+
return emi
|
391 |
+
|
392 |
+
def calculate_loan_eligibility(net_monthly_income, other_emis, interest_rate, tenure_years, income_multiplier=5):
|
393 |
+
# Assuming the bank allows a maximum of 50% of net income towards EMI
|
394 |
+
max_emi_allowed = net_monthly_income * 0.5 - other_emis
|
395 |
+
monthly_interest_rate = interest_rate / (12 * 100)
|
396 |
+
total_payments = tenure_years * 12
|
397 |
+
max_loan_amount = max_emi_allowed / (monthly_interest_rate * ((1 + monthly_interest_rate) ** total_payments) / ((1 + monthly_interest_rate) ** total_payments - 1))
|
398 |
+
return max_loan_amount * income_multiplier
|
399 |
+
|
400 |
+
def estimate_tax_savings(interest_paid_annually, principal_paid_annually, income_tax_slab, co_purchaser):
|
401 |
+
max_deduction_interest = 200000 # Section 24(b)
|
402 |
+
max_deduction_principal = 150000 # Section 80C
|
403 |
+
interest_deduction = min(interest_paid_annually, max_deduction_interest)
|
404 |
+
principal_deduction = min(principal_paid_annually, max_deduction_principal)
|
405 |
+
tax_savings = (interest_deduction + principal_deduction) * income_tax_slab / 100
|
406 |
+
if co_purchaser == "Yes":
|
407 |
+
tax_savings *= 2 # Double the tax savings if there's a co-purchaser
|
408 |
+
return tax_savings
|
409 |
+
|
410 |
+
def calculate_profit_timeline(total_loan_amount, emi, tax_savings, initial_investment, rental_income, rental_increase_rate, inflation_rate, property_appreciation_rate, years):
|
411 |
+
monthly_rental_income = rental_income
|
412 |
+
cumulative_rental_income = 0
|
413 |
+
cumulative_investment = initial_investment
|
414 |
+
property_value = total_loan_amount + initial_investment # Initial total property value
|
415 |
+
profit_timeline = []
|
416 |
+
|
417 |
+
for year in range(1, years + 1):
|
418 |
+
annual_rental_income = 0
|
419 |
+
property_value *= (1 + property_appreciation_rate) # Update property value for the year
|
420 |
+
|
421 |
+
for month in range(1, 13):
|
422 |
+
adjusted_rental_income = monthly_rental_income / ((1 + inflation_rate) ** (year - 1))
|
423 |
+
annual_rental_income += adjusted_rental_income
|
424 |
+
cumulative_rental_income += adjusted_rental_income
|
425 |
+
cumulative_investment += emi - tax_savings / 12
|
426 |
+
|
427 |
+
# Update rental income for the next year
|
428 |
+
monthly_rental_income *= (1 + rental_increase_rate)
|
429 |
+
|
430 |
+
# Record data for the timeline
|
431 |
+
profit_timeline.append((year, cumulative_rental_income, cumulative_investment, property_value))
|
432 |
+
|
433 |
+
return pd.DataFrame(profit_timeline, columns=["Year", "Cumulative Rental Income", "Cumulative Investment", "Estimated Property Value"])
|
434 |
+
|
435 |
+
|
436 |
+
def loan_eligibility_calculator():
|
437 |
+
st.header("Loan Eligibility Calculator")
|
438 |
+
st.write("Calculate your loan eligibility based on your monthly income and other factors.")
|
439 |
+
|
440 |
+
net_monthly_income = st.number_input("Enter your net monthly income:", min_value=0.0, value=50000.0, format="%.2f")
|
441 |
+
other_emis = st.number_input("Enter total EMI of other existing loans (if any):", min_value=0.0, value=0.0, format="%.2f")
|
442 |
+
interest_rate = st.number_input("Expected loan interest rate (%):", min_value=0.0, value=8.0, format="%.2f")
|
443 |
+
tenure_years = st.number_input("Expected loan tenure (years):", min_value=1, max_value=30, value=20, step=1)
|
444 |
+
|
445 |
+
if st.button('Calculate Loan Eligibility'):
|
446 |
+
loan_eligibility = calculate_loan_eligibility(net_monthly_income, other_emis, interest_rate, tenure_years)
|
447 |
+
st.success(f"Based on the provided details, your estimated loan eligibility is: ₹ {loan_eligibility:.2f}")
|
448 |
+
|
449 |
+
def emi_rental_profit_calculator():
|
450 |
+
# User Inputs
|
451 |
+
cost_of_property = st.number_input("Enter the cost of the property:", min_value=100000.0, value=5000000.0, format="%.2f")
|
452 |
+
renovation_cost = st.number_input("Enter the renovation cost:", min_value=0.0, value=500000.0, format="%.2f")
|
453 |
+
down_payment = st.number_input("Enter the down payment:", min_value=0.0, value=1000000.0, format="%.2f")
|
454 |
+
loan_amount = cost_of_property + renovation_cost - down_payment
|
455 |
+
st.text(f"Total Loan Amount: {loan_amount}")
|
456 |
+
|
457 |
+
interest_rate = st.number_input("Enter the home loan interest rate (%):", min_value=0.0, value=8.0, format="%.2f")
|
458 |
+
years = st.number_input("Enter the number of years for the loan:", min_value=1, max_value=30, value=20, step=1)
|
459 |
+
co_purchaser = st.selectbox("Is there a co-purchaser?", ["No", "Yes"])
|
460 |
+
income_tax_slab = st.number_input("Enter your income tax slab rate (%):", min_value=0.0, max_value=30.0, value=10.0, format="%.2f")
|
461 |
+
initial_rental_income = st.number_input("Enter initial monthly rental income:", min_value=0.0, value=20000.0, format="%.2f")
|
462 |
+
rental_increase_rate = st.number_input("Enter annual rental increase rate (%):", min_value=0.0, max_value=10.0, value=5.0, format="%.2f") / 100
|
463 |
+
inflation_rate = st.number_input("Enter annual inflation rate (%):", min_value=0.0, max_value=10.0, value=4.0, format="%.2f") / 100
|
464 |
+
property_appreciation_rate = st.number_input("Enter annual property value appreciation rate (%):", min_value=0.0, max_value=10.0, value=3.0, format="%.2f") / 100
|
465 |
+
|
466 |
+
# Calculation Button
|
467 |
+
if st.button('Calculate'):
|
468 |
+
emi = calculate_emi(loan_amount, interest_rate, years)
|
469 |
+
st.text(f"Monthly EMI: {emi:.2f}")
|
470 |
+
|
471 |
+
# Assuming the entire EMI is considered for tax savings calculation
|
472 |
+
annual_emi = emi * 12
|
473 |
+
tax_savings = estimate_tax_savings(annual_emi, annual_emi, income_tax_slab, co_purchaser)
|
474 |
+
st.text(f"Annual Tax Savings: {tax_savings:.2f}")
|
475 |
+
|
476 |
+
# Calculate profit timeline
|
477 |
+
profit_df = calculate_profit_timeline(loan_amount, emi, tax_savings, down_payment, initial_rental_income, rental_increase_rate, inflation_rate, property_appreciation_rate, years)
|
478 |
+
st.write(profit_df)
|
479 |
+
|
480 |
+
# Plotting the results
|
481 |
+
plt.figure(figsize=(10, 4))
|
482 |
+
plt.plot(profit_df['Year'], profit_df['Cumulative Rental Income'], label='Cumulative Rental Income')
|
483 |
+
plt.plot(profit_df['Year'], profit_df['Cumulative Investment'], label='Cumulative Investment')
|
484 |
+
plt.plot(profit_df['Year'], profit_df['Estimated Property Value'], label='Estimated Property Value')
|
485 |
+
plt.xlabel('Year')
|
486 |
+
plt.ylabel('Amount')
|
487 |
+
plt.title('Profit Timeline')
|
488 |
+
plt.legend()
|
489 |
+
st.pyplot(plt)
|
490 |
+
|
491 |
+
def main():
|
492 |
+
st.title("Personal Finance Assistance")
|
493 |
+
|
494 |
+
# Sidebar for navigation
|
495 |
+
st.sidebar.title("Navigation")
|
496 |
+
|
497 |
+
options = ["Personal Finance Assistance Tools", "Loan Eligibility Calculator", "EMI and Rental Profit Calculator", "SIP Return Comparator", "How to invest my income?", "FIRE Number Calculator", "Compound Interest Calculator", "Loan EMI Calculator"]
|
498 |
+
options.append("Debt Payoff Calculator")
|
499 |
+
options.append("How are my investments changing over time considering inflation ?")
|
500 |
+
options.append("Should I Shift My Loan Calculator")
|
501 |
+
|
502 |
+
choice = st.sidebar.radio("Choose a Calculator:", options)
|
503 |
+
|
504 |
+
if choice == "Personal Finance Assistance Tools":
|
505 |
+
st.text("This Space container various tools to clarify few personal finances.")
|
506 |
+
st.text("Choose from left sidebar and proceed.")
|
507 |
+
st.text("Suggestion are welcome, please contact at fineasyinc@gmail.com for collaboration!")
|
508 |
+
elif choice == "Loan Eligibility Calculator":
|
509 |
+
loan_eligibility_calculator()
|
510 |
+
elif choice == "EMI and Rental Profit Calculator":
|
511 |
+
emi_rental_profit_calculator()
|
512 |
+
elif choice == "SIP Return Comparator":
|
513 |
+
sip_return_comparator_tab()
|
514 |
+
elif choice == "How to invest my income?":
|
515 |
+
investment_advisor()
|
516 |
+
elif choice == "FIRE Number Calculator":
|
517 |
+
fire_number_calculator()
|
518 |
+
elif choice == "Compound Interest Calculator":
|
519 |
+
compound_interest_calculator()
|
520 |
+
elif choice == "Loan EMI Calculator":
|
521 |
+
emi_calculator_tab()
|
522 |
+
elif choice == "How are my investments changing over time considering inflation ?":
|
523 |
+
inflation_calculator_tab()
|
524 |
+
elif choice == "Should I Shift My Loan Calculator":
|
525 |
+
loan_shift_decision_tab()
|
526 |
+
|
527 |
+
|
528 |
+
if __name__ == "__main__":
|
529 |
+
main()
|