File size: 5,271 Bytes
c04ca05
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
import yfinance as yf
import pandas as pd
from typing import Dict, Optional, Any, List
from config import NIFTY50_COMPANIES, MARKET_INDICES, SECTOR_ETFS
from models.market_data import StockDataResponse, IndexData, SectorPerformance

class IndianMarketDataFetcher:
    """Fetch real-time Indian market data using yfinance"""

    def get_nifty50_companies(self) -> Dict[str, str]:
        """Get Nifty 50 company list"""
        return NIFTY50_COMPANIES

    def get_market_indices(self) -> Dict[str, IndexData]:
        """Fetch Indian market indices data"""
        indices_data = {}
        for symbol, name in MARKET_INDICES.items():
            try:
                ticker = yf.Ticker(symbol)
                hist = ticker.history(period="5d")

                if not hist.empty:
                    current_price = hist['Close'].iloc[-1]
                    previous_close = hist['Close'].iloc[-2] if len(hist) > 1 else current_price
                    change = current_price - previous_close
                    change_pct = (change / previous_close) * 100

                    indices_data[name] = IndexData(
                        current_price=current_price,
                        change=change,
                        change_pct=change_pct,
                        volume=hist['Volume'].iloc[-1] if 'Volume' in hist else 0
                    )
            except Exception as e:
                print(f"Could not fetch data for {name}: {e}")
        return indices_data

    def _process_financial_df(self, df: pd.DataFrame, date_col_name: str = 'Date') -> List[Dict[str, Any]]:
        """

        Helper to process yfinance financial DataFrames (financials, balance_sheet, cashflow).

        It transposes the DataFrame, resets the index, and converts the date column

        to string format, then returns a list of dictionaries.

        """
        if df.empty:
            return []
        
        # Transpose the DataFrame so dates become the index, and metrics become columns
        df_transposed = df.T
        
        # Reset the index to turn the date index into a regular column,
        # then convert that column to string format.
        df_processed = df_transposed.reset_index()
        df_processed.rename(columns={'index': date_col_name}, inplace=True)
        
        # Ensure the date column is explicitly converted to string type (YYYY-MM-DD)
        if pd.api.types.is_datetime64_any_dtype(df_processed[date_col_name]):
            df_processed[date_col_name] = df_processed[date_col_name].dt.strftime('%Y-%m-%d')
        
        # Fill any remaining NaN values with 0 to ensure Pydantic doesn't complain about None
        df_processed.fillna(0, inplace=True)
        
        return df_processed.to_dict('records')

    def get_stock_data(self, symbol: str="RELIANCE", period: str = "1y") -> Optional[StockDataResponse]:
        """Fetch stock data for analysis"""
        if not symbol.endswith(".NS"):
            symbol = f"{symbol}.NS"
        try:
            ticker = yf.Ticker(symbol)

            # Get historical data
            hist = ticker.history(period=period)
            if not hist.empty:
                # Reset index to make 'Date' a column, then convert to string
                hist_processed = hist.reset_index()
                hist_processed['Date'] = hist_processed['Date'].dt.strftime('%Y-%m-%d')
                hist_dict = hist_processed.to_dict(orient='list')
            else:
                hist_dict = {}

            # Get company info
            info = ticker.info

            # Process financials, balance sheet, and cash flow using the helper function
            financials_list = self._process_financial_df(ticker.financials)
            balance_sheet_list = self._process_financial_df(ticker.balance_sheet)
            cash_flow_list = self._process_financial_df(ticker.cashflow)

            return StockDataResponse(
                history=hist_dict,
                info=info,
                financials=financials_list,
                balance_sheet=balance_sheet_list,
                cash_flow=cash_flow_list
            )
        except Exception as e:
            print(f"Error fetching data for {symbol}: {e}")
            return None

    def get_sector_performance(self) -> Dict[str, SectorPerformance]:
        """Get sector-wise performance"""
        sector_data = {}
        for etf, sector in SECTOR_ETFS.items():
            try:
                ticker = yf.Ticker(etf)
                hist = ticker.history(period="5d")
                if not hist.empty:
                    current = hist['Close'].iloc[-1]
                    prev = hist['Close'].iloc[-2] if len(hist) > 1 else current
                    change_pct = ((current - prev) / prev) * 100
                    sector_data[sector] = SectorPerformance(sector=sector, change_pct=change_pct)
            except Exception as e:
                print(f"Could not fetch sector data for {etf} ({sector}): {e}")
        return sector_data

    def get_company_name(self, symbol: str) -> Optional[str]:
        """Get company name from symbol"""
        return NIFTY50_COMPANIES.get(symbol)