""" Data models for MF Portfolio Analysis Tool. """ from dataclasses import dataclass, field from typing import Optional @dataclass class Fund: """Represents a single mutual fund scheme from the fund universe CSV.""" name: str category: str benchmark: str # Cost ter: Optional[float] = None # Total Expense Ratio (%) turnover: Optional[float] = None # Portfolio Turnover (%) # Returns mean: Optional[float] = None cagr_1y: Optional[float] = None cagr_1y_cat: Optional[float] = None cagr_1y_bm: Optional[float] = None cagr_3y: Optional[float] = None cagr_3y_cat: Optional[float] = None cagr_3y_bm: Optional[float] = None cagr_5y: Optional[float] = None cagr_5y_cat: Optional[float] = None cagr_5y_bm: Optional[float] = None cagr_10y: Optional[float] = None cagr_10y_cat: Optional[float] = None cagr_10y_bm: Optional[float] = None cagr_inception: Optional[float] = None nav: Optional[float] = None # Valuation pe_ratio: Optional[float] = None pb_ratio: Optional[float] = None # Risk metrics alpha: Optional[float] = None beta: Optional[float] = None std_dev: Optional[float] = None sharpe: Optional[float] = None volatility: Optional[float] = None sortino: Optional[float] = None up_capture: Optional[float] = None down_capture: Optional[float] = None max_drawdown: Optional[float] = None r_squared: Optional[float] = None info_ratio: Optional[float] = None aum: Optional[float] = None fill_status: Optional[str] = None # Scoring (computed) score: Optional[float] = None rank_in_category: Optional[int] = None is_top_quartile: bool = False weightage: Optional[int] = None # Number of periods beating benchmark order: int = 0 # Preserves original CSV insertion order for sort tiebreaker @dataclass class ClientHolding: """Represents a single mutual fund holding in a client's portfolio.""" scheme_name: str current_value: float invested_amount: Optional[float] = None sip_amount: Optional[float] = None sip_frequency: Optional[str] = None # Monthly / Quarterly etc. # Matched fund data fund: Optional[Fund] = None # Computed allocation_pct: float = 0.0 xirr: Optional[float] = None is_underperforming: bool = False # Advisory suggested_fund: Optional[Fund] = None switch_reason: Optional[str] = None @dataclass class Client: """Client details.""" name: str age: Optional[int] = None email: Optional[str] = None mobile: Optional[str] = None pan: Optional[str] = None @dataclass class Advisor: """Financial advisor details.""" name: str = "RAVICHANDRAN" phone: str = "9281364703" email: str = "c4c.ravi@gmail.com" arn: str = "ARN-243354" location: str = "Chennai" @dataclass class PortfolioReport: """The complete portfolio analysis report for a client.""" client: Client advisor: Advisor holdings: list = field(default_factory=list) # Portfolio-level metrics total_current_value: float = 0.0 total_invested: float = 0.0 unrealized_gain: float = 0.0 portfolio_xirr: Optional[float] = None sharpe: Optional[float] = None alpha: Optional[float] = None beta: Optional[float] = None std_dev: Optional[float] = None # Exposure warnings amc_exposure: dict = field(default_factory=dict) # AMC -> pct scheme_exposure: dict = field(default_factory=dict) # scheme -> pct exposure_warnings: list = field(default_factory=list) # list of warning strings # Allocation market_cap_allocation: dict = field(default_factory=dict) # Large/Mid/Small/Other -> pct sector_allocation: dict = field(default_factory=dict) # sector -> pct # Wealth projection wealth_projection: dict = field(default_factory=dict) # years -> projected value