Spaces:
Build error
Build error
| 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.') | |