Spaces:
Sleeping
Sleeping
| import datetime | |
| import math | |
| # --- Helper Functions (mostly unchanged) --- | |
| def get_float(prompt): | |
| """Helper to get a non-negative float from the user.""" | |
| while True: | |
| try: | |
| val_str = input(prompt).strip() | |
| if not val_str: | |
| raise ValueError("Input cannot be empty.") | |
| val = float(val_str) | |
| if val < 0: | |
| raise ValueError("Please enter a non-negative number.") | |
| return val | |
| except ValueError as e: | |
| print(f"Invalid input: {e}") | |
| def get_int(prompt): | |
| """Helper to get a non-negative integer from the user.""" | |
| while True: | |
| try: | |
| val_str = input(prompt).strip() | |
| if not val_str: | |
| raise ValueError("Input cannot be empty.") | |
| val = int(val_str) | |
| if val < 0: | |
| raise ValueError("Please enter a non-negative whole number.") | |
| return val | |
| except ValueError as e: | |
| print(f"Invalid input: {e}") | |
| def yes_no(prompt): | |
| """Helper to get a yes/no response.""" | |
| while True: | |
| resp = input(prompt + " (y/n): ").strip().lower() | |
| if resp in ("y", "yes"): | |
| return True | |
| if resp in ("n", "no"): | |
| return False | |
| print("Please answer 'y' or 'n'.") | |
| # --- Simplified Profile and Financials Gathering --- | |
| def get_user_profile(): | |
| """Gathers lifecycle stage, risk appetite, and investment horizon.""" | |
| print("\n--- Let's Understand Your Investor Profile ---") | |
| # 1. Lifecycle Stage | |
| print("\nWhich of these best describes your current life stage?") | |
| lifecycle_options = { | |
| "1": "Student (Focus: Learning, initial savings)", | |
| "2": "Early Career (20s-early 30s, Focus: Growth, accumulation)", | |
| "3": "Mid-Career (Mid 30s-late 40s, Focus: Balancing growth & responsibilities)", | |
| "4": "Late Career/Pre-Retirement (50s+, Focus: Capital preservation, income generation)", | |
| "5": "Retired (Focus: Sustainable income, capital preservation)" | |
| } | |
| for key, value in lifecycle_options.items(): | |
| print(f"{key}. {value}") | |
| while True: | |
| choice = input("Enter number (1-5): ").strip() | |
| if choice in lifecycle_options: | |
| lifecycle_stage = lifecycle_options[choice].split('(')[0].strip() # Get "Student", "Early Career" etc. | |
| break | |
| else: | |
| print("Invalid choice. Please enter a number between 1 and 5.") | |
| # 2. Risk Appetite | |
| print("\nHow would you describe your risk tolerance for investments?") | |
| risk_options = { | |
| "1": "Low (Prefer safety and capital preservation, okay with lower returns)", | |
| "2": "Medium (Willing to take some risk for moderate growth, comfortable with some fluctuations)", | |
| "3": "High (Willing to take significant risk for potentially high returns, can handle large fluctuations)" | |
| } | |
| for key, value in risk_options.items(): | |
| print(f"{key}. {value}") | |
| while True: | |
| choice = input("Enter number (1-3): ").strip() | |
| if choice == "1": risk_appetite = "low"; break | |
| elif choice == "2": risk_appetite = "medium"; break | |
| elif choice == "3": risk_appetite = "high"; break | |
| else: | |
| print("Invalid choice. Please enter 1, 2, or 3.") | |
| # 3. Investment Horizon | |
| print("\nWhat is your general investment time horizon for the majority of your savings?") | |
| horizon_options = { | |
| "1": "Short-term (Less than 3 years)", | |
| "2": "Medium-term (3-7 years)", | |
| "3": "Long-term (More than 7 years)" | |
| } | |
| for key, value in horizon_options.items(): | |
| print(f"{key}. {value}") | |
| while True: | |
| choice = input("Enter number (1-3): ").strip() | |
| if choice == "1": investment_horizon = "short-term"; break | |
| elif choice == "2": investment_horizon = "medium-term"; break | |
| elif choice == "3": investment_horizon = "long-term"; break | |
| else: | |
| print("Invalid choice. Please enter 1, 2, or 3.") | |
| return lifecycle_stage, risk_appetite, investment_horizon | |
| def get_financial_details(): | |
| """Gets annual package, monthly in-hand salary, and total monthly expenses.""" | |
| print("\n--- Let's Get Your Financial Details ---") | |
| annual_package = get_float("What is your approximate annual salary package (CTC)? \u20B9 ") | |
| # Simplified monthly in-hand: Ask directly or provide a rough estimate and ask for correction | |
| print(f"\nBased on an annual package of \u20B9 {annual_package:.2f}, your monthly in-hand salary might be around \u20B9 {annual_package / 14:.2f} to \u20B9 {annual_package / 13:.2f} (this is a rough estimate).") | |
| monthly_in_hand_salary = get_float("What is your actual average monthly in-hand salary? \u20B9 ") | |
| total_monthly_expenses = get_float("What are your total estimated monthly expenses (all inclusive)? \u20B9 ") | |
| monthly_savings = monthly_in_hand_salary - total_monthly_expenses | |
| print(f"\nBased on your input:") | |
| print(f" Monthly In-hand Salary: \u20B9 {monthly_in_hand_salary:.2f}") | |
| print(f" Total Monthly Expenses: \u20B9 {total_monthly_expenses:.2f}") | |
| if monthly_savings > 0: | |
| print(f" Calculated Monthly Savings: \u20B9 {monthly_savings:.2f}") | |
| else: | |
| print(f" Calculated Monthly Deficit: \u20B9 {abs(monthly_savings):.2f}") | |
| print(" It seems your expenses exceed your income. Please review your budget.") | |
| return monthly_in_hand_salary, total_monthly_expenses, monthly_savings | |
| # --- Simplified Investment Allocation Logic --- | |
| def allocate_savings_simplified(savings, risk_profile, horizon, lifecycle): | |
| """ | |
| Determines investment allocation percentages based on simplified profile. | |
| Returns a dictionary of { "Asset Class": percentage, ... } | |
| """ | |
| allocations = {} | |
| justification_points = [ | |
| f"This allocation considers your {risk_profile} risk profile, {horizon} horizon, and {lifecycle} stage." | |
| ] | |
| # Prioritize Emergency Fund if not explicitly covered or if savings are first-time | |
| # For simplicity, this version assumes user will manage EF separately or this is for surplus post-EF. | |
| # A more robust version would inquire about EF status. | |
| if risk_profile == "low": | |
| allocations = { | |
| "Fixed Deposits / Recurring Deposits (Safety & Stability)": 0.35, | |
| "Debt Mutual Funds (Liquid/Short Duration - Better than savings account returns)": 0.30, | |
| "Gold (SGBs/ETFs - Inflation Hedge, Diversification)": 0.10, | |
| "Equity MFs (Large Cap/Index Funds - Long-term inflation beating, low volatility equity)": 0.15, | |
| "Cash / Savings Account (Immediate Liquidity)": 0.10 | |
| } | |
| justification_points.append("- Focus on capital preservation and stable returns.") | |
| justification_points.append("- Suitable for short-term goals or very conservative investors.") | |
| if horizon != "short-term": | |
| justification_points.append("- Even with a longer horizon, a 'low' risk choice emphasizes safety above all.") | |
| elif risk_profile == "medium": | |
| allocations = { | |
| "Equity MFs (Diversified - Large & Mid Cap/Flexi Cap SIPs for growth)": 0.45, | |
| "Debt Mutual Funds (For stability and portfolio balance)": 0.25, | |
| "Fixed Deposits / PPF (Secure, long-term component)": 0.10, | |
| "Gold (SGBs/ETFs - Diversification)": 0.10, | |
| "Equity MFs (International - For global diversification, if comfortable)": 0.05, # Optional | |
| "Cash / Savings Account (Buffer)": 0.05 | |
| } | |
| justification_points.append("- Aims for a balance between growth (equity) and stability (debt, gold).") | |
| justification_points.append("- Suitable for medium to long-term goals.") | |
| if lifecycle in ["Early Career", "Student"] and horizon == "long-term": | |
| justification_points.append("- Your stage and horizon allow for good equity exposure for wealth creation.") | |
| # Could slightly increase equity for very young, long-term, medium risk. | |
| # allocations["Equity MFs (Diversified - Large & Mid Cap/Flexi Cap SIPs for growth)"] = 0.50 | |
| # allocations["Debt Mutual Funds (For stability and portfolio balance)"] = 0.20 | |
| elif risk_profile == "high": | |
| allocations = { | |
| "Equity MFs (Aggressive Growth - Mid/Small Cap, Thematic SIPs, with research)": 0.60, | |
| "Equity MFs (International - Global growth opportunities)": 0.15, | |
| "Direct Stocks (If experienced & well-researched, otherwise add to Equity MFs)": 0.10, # User needs to self-assess this. | |
| "Debt Mutual Funds (Strategic, for some diversification)": 0.05, | |
| "Gold (SGBs/ETFs - Tactical Diversification)": 0.05, | |
| "Alternative Inv. (REITs/InvITs - very small, if understood & suitable, else to Equity)": 0.05 | |
| } | |
| justification_points.append("- Focuses on maximizing long-term growth potential, accepting higher volatility.") | |
| justification_points.append("- Best suited for long-term goals and investors comfortable with significant market swings.") | |
| if lifecycle not in ["Early Career", "Mid-Career"] and horizon == "long-term": | |
| justification_points.append(f"- CAUTION: High risk at {lifecycle} stage needs careful consideration of your overall financial stability and nearness to needing funds.") | |
| if horizon != "long-term": | |
| justification_points.append(f"- CAUTION: High risk for a {horizon} horizon is generally not advisable. Ensure goals truly allow for this risk.") | |
| # Normalize percentages to ensure they sum to 100% | |
| current_total_percentage = sum(allocations.values()) | |
| if abs(current_total_percentage - 1.0) > 0.001: # If not already 100% | |
| factor = 1.0 / current_total_percentage | |
| normalized_allocations = {k: v * factor for k, v in allocations.items()} | |
| # Small check to ensure the largest component doesn't become negative if factor is weird (shouldn't happen with positive inputs) | |
| # And ensure no tiny values are left that make no sense, e.g. less than 0.5% could be merged. | |
| # For simplicity, we'll assume initial definitions are close enough. | |
| final_allocations = {} | |
| temp_sum = 0 | |
| for asset, perc in normalized_allocations.items(): | |
| # Round to sensible points e.g. 1 decimal for percentage display | |
| # but use more precision for calculation | |
| final_allocations[asset] = perc | |
| temp_sum += perc | |
| # Final check and adjustment of the largest item if sum isn't perfect due to rounding during normalization. | |
| if abs(temp_sum - 1.0) > 0.0001: | |
| diff = 1.0 - temp_sum | |
| if final_allocations: # Check if dict is not empty | |
| # Find largest item to adjust | |
| largest_item_key = max(final_allocations, key=final_allocations.get) | |
| final_allocations[largest_item_key] += diff | |
| allocations = final_allocations | |
| return allocations, justification_points | |
| def display_investment_plan(monthly_savings, allocations, justification): | |
| """Displays the final investment plan and justification.""" | |
| print("\n\n--- Your Personalized Investment Allocation Plan ---") | |
| print(f"Based on your monthly savings of \u20B9 {monthly_savings:.2f}:\n") | |
| print("Suggested Allocation:") | |
| print("---------------------------------------------------------------------------") | |
| print(f"{'Asset Class/Instrument':<50} | {'Percentage':>12} | {'Amount (βΉ)':>12}") | |
| print("---------------------------------------------------------------------------") | |
| if not allocations: # Should not happen if logic is correct | |
| print("No specific allocation generated. Please review inputs or consult an advisor.") | |
| return | |
| total_allocated_amount_check = 0 | |
| for asset, percentage in allocations.items(): | |
| amount = monthly_savings * percentage | |
| total_allocated_amount_check += amount | |
| print(f"{asset:<50} | {percentage*100:>11.1f}% | {amount:>11.2f}") | |
| print("---------------------------------------------------------------------------") | |
| print(f"{'TOTAL':<50} | {'100.0%':>12} | {total_allocated_amount_check:>11.2f}") | |
| print("\nWhy these allocations?") | |
| for point in justification: | |
| print(f"- {point}") | |
| print("\n- Learn more about general investing principles at: https://www.investopedia.com/financial-advisor/asset-allocation/\n" | |
| " and for Indian context: https://www.amfiindia.com (Investor Education section)") | |
| def provide_general_financial_tips(lifecycle_stage, monthly_savings, original_salary): | |
| """Provides general financial tips.""" | |
| print("\n--- General Financial Tips ---") | |
| tips = [] | |
| if monthly_savings <= 0 and original_salary > 0 : | |
| tips.append("- Your expenses currently meet or exceed your income. Focus on creating a budget to identify areas to cut back or explore ways to increase your income.") | |
| elif original_salary > 0: | |
| savings_rate = (monthly_savings / original_salary) * 100 | |
| tips.append(f"- Your current savings rate is approximately {savings_rate:.1f}%. Aim for at least 20-30% if possible, especially in accumulation stages.") | |
| if savings_rate < 15: | |
| tips.append("- Consider reviewing discretionary spending to boost your savings rate.") | |
| tips.append("- Build & Maintain an Emergency Fund: Aim for 3-6 months of essential living expenses in a safe, liquid account (e.g., savings account, liquid mutual fund). This is your top priority before aggressive investing.") | |
| tips.append("- Get Adequately Insured: Ensure you have sufficient health insurance for yourself and your family. If you have dependents, a term life insurance policy is crucial.") | |
| tips.append("- Invest Regularly & Be Disciplined: Consistency through SIPs (Systematic Investment Plans) is key, especially for long-term goals. Don't try to time the market.") | |
| tips.append("- Review Periodically: Revisit your financial plan and investments at least annually, or when major life events occur (marriage, new job, child, etc.).") | |
| tips.append("- Understand Your Investments: Before investing in any product, understand its risks, costs (like expense ratios for MFs), and how it fits your goals.") | |
| if lifecycle_stage == "Student" or lifecycle_stage == "Early Career": | |
| tips.append("- Focus on upskilling and career growth to increase your earning potential. Your human capital is your biggest asset at this stage.") | |
| if lifecycle_stage == "Late Career/Pre-Retirement" or lifecycle_stage == "Retired": | |
| tips.append("- Plan for healthcare expenses in retirement. Consider if your current investments align with generating regular income if needed.") | |
| for tip in tips: | |
| print(f"* {tip}") | |
| # --- Main Program Flow (Simplified) --- | |
| def main_simplified(): | |
| print("ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ") | |
| print("β Simplified Monthly Savings Allocator β") | |
| print(f"β Today's Date: {datetime.date.today().strftime('%Y-%m-%d')} β") | |
| print("ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ") | |
| print("\nWelcome! This tool will help you allocate your monthly savings.") | |
| print("This is for educational purposes and NOT financial advice.\n") | |
| # 1. Get User Profile | |
| lifecycle, risk, horizon = get_user_profile() | |
| print(f"\nYour Profile Summary: Lifecycle: {lifecycle}, Risk: {risk.capitalize()}, Horizon: {horizon.capitalize()}") | |
| # 2. Get Financial Details | |
| salary, expenses, savings = get_financial_details() | |
| if savings <= 0: | |
| print("\nSince you don't have a monthly surplus, investment allocation is not applicable now.") | |
| print("Focus on budgeting and increasing savings first.") | |
| else: | |
| # 3. Allocate Savings | |
| allocations_dict, justification_list = allocate_savings_simplified(savings, risk, horizon, lifecycle) | |
| # 4. Display Plan | |
| display_investment_plan(savings, allocations_dict, justification_list) | |
| # 5. Provide General Tips | |
| provide_general_financial_tips(lifecycle, savings, salary) | |
| # 6. Disclaimer | |
| print("\n\n--- Disclaimer ---") | |
| print("The information and suggestions provided by this script are for general guidance and educational purposes ONLY.") | |
| print("This does NOT constitute financial, investment, tax, or legal advice.") | |
| print("Investment decisions involve risks. Past performance is not indicative of future results.") | |
| print("Asset allocation models are generalized and may not be suitable for your individual circumstances.") | |
| print("It is strongly recommended to consult with a SEBI-registered Investment Adviser or a qualified financial professional for personalized advice.") | |
| print("\nBudget calculation and investment suggestions complete. Plan wisely!\n") | |
| if __name__ == "__main__": | |
| main_simplified() |