from fastapi import APIRouter, Depends, HTTPException, Query from typing import List, Dict, Any, Optional from app.services.data_fetcher import MutualFundDataFetcher from app.services.sip_calculator import SIPCalculator from app.models.fund_models import ( FundNAVResponse, FundAnalysisRequest, FundAnalysisResponse ) from app.models.goal_models import ( SIPCalculationRequest, SIPCalculationResponse, RequiredSIPRequest, RequiredSIPResponse ) # Popular mutual fund categories with scheme codes POPULAR_FUNDS = { 'Large Cap Equity': { 'HDFC Top 100 Fund': '120503', 'ICICI Pru Bluechip Fund': '120505', 'SBI Bluechip Fund': '125497', 'Axis Bluechip Fund': '120503', 'Kotak Bluechip Fund': '118989' }, 'Mid Cap Equity': { 'HDFC Mid-Cap Opportunities Fund': '118551', 'ICICI Pru Mid Cap Fund': '120544', 'Kotak Emerging Equity Fund': '118999', 'SBI Magnum Mid Cap Fund': '100281', 'DSP Mid Cap Fund': '112618' }, 'Small Cap Equity': { 'SBI Small Cap Fund': '122639', 'DSP Small Cap Fund': '112618', 'HDFC Small Cap Fund': '118551', 'Axis Small Cap Fund': '125487', 'Kotak Small Cap Fund': '119028' }, 'ELSS (Tax Saving)': { 'Axis Long Term Equity Fund': '125494', 'HDFC Tax Saver': '100277', 'SBI Tax Saver': '125497', 'ICICI Pru ELSS Tax Saver': '120503', 'Kotak Tax Saver': '118989' }, 'Debt Funds': { 'HDFC Corporate Bond Fund': '101762', 'ICICI Pru Corporate Bond Fund': '120503', 'SBI Corporate Bond Fund': '125497', 'Kotak Corporate Bond Fund': '118989', 'Axis Corporate Debt Fund': '125494' }, 'Hybrid Funds': { 'HDFC Hybrid Equity Fund': '118551', 'ICICI Pru Balanced Advantage Fund': '120505', 'SBI Equity Hybrid Fund': '125497', 'Kotak Equity Hybrid Fund': '118999', 'Axis Hybrid Fund': '125494' } } router = APIRouter() @router.get("/schemes") async def get_all_schemes(): """ Get all available mutual fund schemes """ try: fetcher = MutualFundDataFetcher() schemes = fetcher.get_all_schemes() return {"schemes": schemes} except Exception as e: raise HTTPException(status_code=500, detail=f"Error fetching schemes: {str(e)}") @router.get("/nav/{scheme_code}", response_model=FundNAVResponse) async def get_fund_nav_history(scheme_code: str): """ Get NAV history for a specific mutual fund scheme """ try: fetcher = MutualFundDataFetcher() nav_data, fund_meta = fetcher.get_fund_nav_history(scheme_code) return FundNAVResponse( meta=fund_meta, data=nav_data.to_dict('records') ) except Exception as e: raise HTTPException(status_code=500, detail=f"Error fetching NAV data: {str(e)}") @router.get("/popular") async def get_popular_funds(): """ Get list of popular mutual funds by category """ return POPULAR_FUNDS @router.post("/sip-calculate", response_model=SIPCalculationResponse) async def calculate_sip(request: SIPCalculationRequest, include_yearly_breakdown: bool = Query(False, description="Include yearly breakdown in response")): """ Calculate SIP maturity amount based on monthly investment, expected return, and time period """ try: calculator = SIPCalculator() result = calculator.get_sip_calculation(request, include_yearly_breakdown) return result except Exception as e: raise HTTPException(status_code=500, detail=f"Error calculating SIP: {str(e)}") @router.post("/required-sip", response_model=RequiredSIPResponse) async def calculate_required_sip(request: RequiredSIPRequest): """ Calculate required SIP amount to reach a target amount """ try: calculator = SIPCalculator() result = calculator.get_required_sip(request) return result except Exception as e: raise HTTPException(status_code=500, detail=f"Error calculating required SIP: {str(e)}") @router.post("/analyze", response_model=FundAnalysisResponse) async def analyze_funds(request: FundAnalysisRequest): """ Analyze performance of selected mutual funds over a specified period """ try: fetcher = MutualFundDataFetcher() calculator = SIPCalculator() analysis_results = [] for fund_name in request.fund_names: # Find scheme code for the fund scheme_code = None fund_category = None for category, funds in POPULAR_FUNDS.items(): if fund_name in funds: scheme_code = funds[fund_name] fund_category = category break if not scheme_code: continue # Fetch NAV data nav_data, fund_meta = fetcher.get_fund_nav_history(scheme_code) if not nav_data.empty: returns_data = calculator.calculate_fund_returns( nav_data, request.investment_amount, request.start_date, request.end_date ) if returns_data: analysis_results.append({ 'fund_name': fund_name, 'category': fund_category, 'scheme_code': scheme_code, 'fund_house': fund_meta.fund_house, 'returns_data': returns_data, 'nav_data': nav_data.to_dict('records'), 'fund_meta': fund_meta.dict() }) # Prepare comparison data comparison_data = [] for result in analysis_results: returns = result['returns_data'] comparison_data.append({ 'Fund Name': result['fund_name'], 'Category': result['category'], 'Fund House': result['fund_house'], 'Investment': f"₹{returns['investment_amount']:,.0f}", 'Current Value': f"₹{returns['final_value']:,.0f}", 'Total Return': f"{returns['total_return']:.2f}%", 'Absolute Gain': f"₹{returns['final_value'] - returns['investment_amount']:,.0f}" }) return FundAnalysisResponse( results=analysis_results, comparison_data=comparison_data ) except Exception as e: raise HTTPException(status_code=500, detail=f"Error analyzing funds: {str(e)}")