swp / app.py
Saurabh502's picture
Update app.py
6a3b396 verified
import streamlit as st
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
st.title("Investment Calculators")
tab1, tab2 = st.tabs(["Step-up SIP Calculator", "SWP Calculator"])
with tab1:
st.header("Step-up SIP Calculator")
monthly_investment = st.number_input("Monthly Investment", min_value=0, value=1000, key="sip_monthly")
annual_step_up = st.number_input("Annual Step Up (%)", min_value=0, value=10, key="sip_stepup") / 100
expected_return_rate = st.number_input("Expected Return Rate (p.a) (%)", min_value=0, value=10, key="sip_return") / 100
time_period = st.number_input("Time Period (Years)", min_value=1, value=5, key="sip_time")
def calculate_stepup_sip(monthly_investment, annual_step_up, expected_return_rate, time_period):
monthly_rate = expected_return_rate / 12
total_months = time_period * 12
investment_schedule = []
future_values = []
current_investment = monthly_investment
for year in range(time_period):
for month in range(12):
investment_schedule.append(current_investment)
remaining_months = total_months - (year * 12 + month) - 1
if remaining_months >= 0:
fv = current_investment * (1 + monthly_rate) ** (remaining_months + 1)
future_values.append(fv)
current_investment *= (1 + annual_step_up)
total_invested = sum(investment_schedule)
total_future_value = sum(future_values)
returns = total_future_value - total_invested
return total_invested, returns, total_future_value, investment_schedule
def format_currency(amount):
return f"₹{amount:,.2f}"
total_invested, returns, future_value, investment_schedule = calculate_stepup_sip(
monthly_investment, annual_step_up, expected_return_rate, time_period
)
col1, col2 = st.columns([1, 1])
with col1:
st.write(f"Invested amount: {format_currency(total_invested)}")
st.write(f"Est. returns: {format_currency(returns)}")
st.write(f"Total value: {format_currency(future_value)}")
with col2:
labels = ['Invested amount', 'Est. returns']
sizes = [total_invested, returns]
colors = ['#e6f2ff', '#6253e1']
fig1, ax1 = plt.subplots()
ax1.pie(sizes, colors=colors, startangle=90, wedgeprops={'width': 0.4}, pctdistance=0.85)
centre_circle = plt.Circle((0, 0), 0.70, fc='white')
fig = plt.gcf()
fig.gca().add_artist(centre_circle)
ax1.axis('equal')
plt.legend(labels, loc="best")
st.pyplot(fig1)
if st.checkbox("Show Investment Schedule", key="sip_schedule"):
schedule_df = pd.DataFrame({
'Month': range(1, len(investment_schedule) + 1),
'Investment': [format_currency(x) for x in investment_schedule]
})
st.dataframe(schedule_df)
with tab2:
st.header("SWP Calculator")
# Add inflation_rate and withdrawal_increase_rate parameters
# Add inflation_rate and withdrawal_increase_rate parameters
def calculate_swp(initial_investment, monthly_withdrawal, annual_rate, years, inflation_rate, withdrawal_increase_rate):
monthly_rate = annual_rate / 12 / 100
# Convert percentage rate to decimal for calculation
withdrawal_increase_rate_decimal = withdrawal_increase_rate / 100.0
num_months = years * 12
balance = float(initial_investment) # Use float for precision
current_monthly_withdrawal = float(monthly_withdrawal) # Start with the initial withdrawal amount
total_interest_earned = 0.0
total_withdrawn = 0.0
# Lists to store monthly data for accurate yearly summary
# Index 0 = initial state, index 1 = end of month 1, etc.
monthly_balances = [balance]
monthly_interests = [0.0] # Interest earned *during* month i is stored at index i
monthly_withdrawals = [0.0] # Withdrawal made *during* month i is stored at index i
for month in range(1, num_months + 1):
# Increase withdrawal amount at the start of each year (after the first year)
if month > 1 and (month - 1) % 12 == 0:
current_monthly_withdrawal *= (1 + withdrawal_increase_rate_decimal)
# Determine actual withdrawal amount first using the current (potentially increased) amount
actual_withdrawal = current_monthly_withdrawal
# A more robust approach could be: actual_withdrawal = min(balance, current_monthly_withdrawal)
# but we stick closer to the original implicit logic for now.
# Subtract withdrawal from the balance
balance -= actual_withdrawal
total_withdrawn += actual_withdrawal # Record the withdrawal amount
# Calculate interest on the balance *after* withdrawal
interest = balance * monthly_rate if balance > 0 else 0 # Avoid negative interest if balance goes below zero
total_interest_earned += interest
# Add interest to get the end-of-month balance
balance += interest
# Store monthly data (balance is end-of-month)
monthly_balances.append(balance)
monthly_interests.append(interest) # Store interest calculated *during* this month
monthly_withdrawals.append(actual_withdrawal) # Store withdrawal made *during* this month
# Optional: Handle balance depletion if needed in future
# if balance < 0:
# pass
final_balance = balance if balance > 0 else 0.0
# Generate yearly summary DataFrame from monthly data
yearly_data = []
for year in range(1, years + 1):
start_month_index = (year - 1) * 12 # List index for start of year balance
end_month_index = year * 12 # List index for end of year balance
# Ensure indices are within bounds of recorded data
# (-1 because list length is num_months + 1)
end_month_index = min(end_month_index, len(monthly_balances) - 1)
start_month_index = min(start_month_index, end_month_index)
# Opening balance is the balance at the start of the first month (end of previous month)
opening_bal = monthly_balances[start_month_index]
# Closing balance is the balance at the end of the last month of the year
closing_bal = monthly_balances[end_month_index]
# Sum interest and withdrawal for the months of this year (indices 1 to 12 for year 1, etc.)
# Slicing indices: [start_month_index + 1] up to (but not including) [end_month_index + 1]
interest_year = sum(monthly_interests[start_month_index + 1 : end_month_index + 1])
withdrawal_year = sum(monthly_withdrawals[start_month_index + 1 : end_month_index + 1])
yearly_data.append({
'Year': year,
'Opening Balance': round(opening_bal, 2),
'Interest Earned': round(interest_year, 2),
'Withdrawal': round(withdrawal_year, 2),
'Closing Balance': round(closing_bal, 2)
})
df = pd.DataFrame(yearly_data)
# Return all calculated values: final balance, total interest, total withdrawal, and the yearly dataframe
return final_balance, total_interest_earned, total_withdrawn, df
initial_investment = st.number_input('Initial Investment', value=10000000, step=100000, format='%d', key="swp_initial")
monthly_withdrawal = st.number_input('Monthly Withdrawal', value=100000, step=1000, format='%d', key="swp_monthly")
annual_rate = st.number_input('Annual Interest Rate (%)', value=8.0, step=0.1, format='%.1f', key="swp_rate")
years = st.number_input('Investment Period (Years)', value=20, step=1, format='%d', key="swp_years")
# Add new input fields
inflation_rate = st.number_input('Expected Inflation Rate (%)', value=6.0, step=0.1, format='%.1f', key="swp_inflation")
withdrawal_increase_rate = st.number_input('Annual Withdrawal Increase (%)', value=0.0, step=0.1, format='%.1f', key="swp_increase")
if st.button('Calculate SWP'):
# Pass the new input values to the function
final_balance_calc, total_interest_calc, total_withdrawal_calc, df = calculate_swp(
initial_investment, monthly_withdrawal, annual_rate, years, inflation_rate, withdrawal_increase_rate
)
st.subheader('SWP Projection')
st.dataframe(df.style.format({
'Opening Balance': '₹{:,.2f}',
'Interest Earned': '₹{:,.2f}',
'Withdrawal': '₹{:,.2f}',
'Closing Balance': '₹{:,.2f}'
}))
# Use the directly calculated values returned by the function for the summary
st.subheader('Summary')
col1, col2 = st.columns(2)
with col1:
st.metric('Initial Investment', f'₹{float(initial_investment):,.2f}') # Ensure initial is float for formatting consistency
st.metric('Total Interest Earned', f'₹{total_interest_calc:,.2f}')
with col2:
st.metric('Total Withdrawal', f'₹{total_withdrawal_calc:,.2f}')
st.metric('Final Balance', f'₹{final_balance_calc:,.2f}')
st.caption('Note: This is a simulated projection. Actual returns may vary.')