# libary for Vietcap trading platform
import requests
import pandas as pd
import json
# from .stocklist import *
from pandas import json_normalize
from datetime import datetime, timedelta
import pytz
from bs4 import BeautifulSoup
from concurrent.futures import ThreadPoolExecutor, as_completed

class StockMarket:
    def __init__(self, symbol):
        self.symbol = symbol

    def stock_info(self,exchange=None):
        try:
            headers={
                'content-type': 'application/json',
                'referer': 'https://trading.vietcap.com.vn/',
                'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36'
            }
            payload = {
                "pageSize": 50000
            }
            url=f'https://iq.vietcap.com.vn/api/iq-insight-service/v1/screening/paging'
            response=requests.post(url,headers=headers,data=json.dumps(payload))
            data=pd.json_normalize(response.json()['data']['content'])
            cols=['ticker','exchange','viSector','viOrganName','enSector','enOrganName']
            data=data[cols]
            rename_cols = {
                "ticker": "Mã CP",
                "exchange": "Sàn",
                "viSector": "Ngành (VI)",
                "enSector": "Ngành (EN)",
                "viOrganName": "Tên công ty (VI)",
                "enOrganName": "Tên công ty (EN)"
            }
            data=data.rename(columns=rename_cols)
            data["Mã CP"] = data["Mã CP"].astype(str).str.upper()
            data["Sàn"] = data["Sàn"].astype(str).str.upper()

            if exchange is None:
                return data.loc[data["Mã CP"] == self.symbol.upper()].reset_index(drop=True)

            return data.loc[
                (data["Mã CP"] == self.symbol.upper()) &
                (data["Sàn"] == exchange.upper())
            ].reset_index(drop=True)
        except Exception as e :
                print(f"Lỗi: {e}")
                return pd.DataFrame() 

    def history(self,time="days" , start ,end):
        headers = {
        'content-type': 'application/json',
        'referer': 'https://trading.vietcap.com.vn/?filter-group=HOSE&filter-value=HOSE&view-type=FLAT&type=stock',
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36'
        }

        end_dt = datetime.strptime(end, '%Y-%m-%d') + timedelta(days=1)
        end_timestamp = end_dt.timestamp()

        time_dict= {
            'days': 'ONE_DAY',
            'months': 'ONE_MONTH',
            'minutes': 'ONE_MINUTE',
            'hours': 'ONE_HOUR'
            }

        payload = {
            "timeFrame": time_dict[time],
            "symbols": [self.symbol],
            "countBack": 30_000,
            "to": end_timestamp
        }

        url = "https://trading.vietcap.com.vn/api/chart/OHLCChart/gap-chart"

        session = requests.Session()  
        response = session.post(url, headers=headers, data=json.dumps(payload))
        json_data = response.json()

        def is_stock(symbol):
            return len(symbol) <= 3


        if not json_data or not isinstance(json_data, list) or len(json_data) ==0:
            print(f"Không có dữ liệu cho mã {self.symbol}.")
            return pd.DataFrame()

        data = json_data[0]

        df = pd.DataFrame(data)
        df = df[["symbol", "t", "o","c", "h", "l", "v"]]
        df["t"] = pd.to_numeric(df['t'], errors='coerce')
        df["t"] = df['t'].apply(lambda x: datetime.fromtimestamp(x))
        if time in ['minutes','hours']:
            df["t"] = pd.to_datetime(df["t"], errors='coerce').dt.tz_localize(None).dt.floor("s")
        if time in ['days','months']:
            df["t"] = pd.to_datetime(df["t"], errors='coerce').dt.tz_localize(None).dt.floor("d")
        df=df.sort_values(by='t',ascending=True).reset_index(drop=True)

        if is_stock(self.symbol):
            df[["o", "h", "l", "c"]] = df[["o", "h", "l", "c"]].apply(lambda x: round(x / 1000,2))
    
        df.rename(columns={"symbol": "symbol",
                "o": "open",
                "h": "high",
                "l": "low",
                "c": "close",
                "t": "time",
                "v": "volume"
            }, inplace=True)
        return df[df["time"] >= start].reset_index(drop=True)

    def intraday(self):
        headers = {
            'content-type': 'application/json',
            'referer': 'https://trading.vietcap.com.vn/?filter-group=HOSE&filter-value=HOSE&view-type=FLAT',
            'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36'
        }
    
        payload = {
            "symbol": self.symbol.upper(),
            "limit": 50_000,
            "truncTime": None,
        }
        url = "https://trading.vietcap.com.vn/api/market-watch/LEData/getAll"

        try: 
            session = requests.Session()
            response = session.post(url, headers=headers, data=json.dumps(payload))
            data = response.json()
            data = json_normalize(data)
            data = data[[#"id",
                         "symbol",
                         "matchType",
                         "matchVol",
                         "matchPrice",
                         "truncTime"]]
            data.rename(columns={
            "symbol": "Mã",
            "matchType": "Mua/Bán",
            "matchVol": "Khối lượng",
            "matchPrice": "Giá",
            "truncTime": "Thời gian"
            },inplace=True)
            data[["Giá","Khối lượng"]] = data[["Giá","Khối lượng"]].apply(pd.to_numeric, errors='coerce').astype("Int64")
            data["Giá"]= data["Giá"].apply(lambda x: x / 1000)
            data["Mua/Bán"] = data["Mua/Bán"].replace({"b": "Mua", "s": "Bán", "unknown": "ATO/ATC"})
            data["Thời gian"] = (pd.to_datetime(pd.to_numeric(data["Thời gian"], errors="coerce"),
                                                    unit="s",
                                                    utc=True,
                                                    errors="coerce"
                                                )
                                    .dt.tz_convert("Asia/Ho_Chi_Minh")
                                    .dt.tz_localize(None)
                                    .dt.floor("s")
                                )
            data = data.sort_values("Thời gian", ascending=True).reset_index(drop=True)
            return data
        except Exception as e :
            print(f"Lỗi sổ lệnh: {e}")
            return pd.DataFrame()

    def intraday_order(self):
        headers = {
            'content-type': 'application/json',
            'referer': 'https://trading.vietcap.com.vn/?filter-group=HOSE&filter-value=HOSE&view-type=FLAT',
            'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36'
        }
        payload = {
            "symbol": self.symbol.upper(),
            "limit": 30_000,
            "truncTime": None,
            "timeFrame": "ONE_SECOND"
        }
        url = "https://trading.vietcap.com.vn/api/sts-computation/BigOrder/getAll"
        
        try: 
            session = requests.Session()
            response = session.post(url, headers=headers, data=json.dumps(payload))
            data = response.json()
            data = json_normalize(data)
            data = data[[ "symbol", "matchType", "matchVol", "price",  "total", "truncTime",  "type"]]
            data.rename(columns={
                "symbol": "Mã",
                "price": "Giá",
                "matchVol": "Khối lượng",
                "total": "Giá trị giao dịch",
                "matchType": "Mua/Bán",
                "type": "Phân loại",
                "truncTime": "Thời gian"
            }, inplace=True)
            data["Mua/Bán"] = data["Mua/Bán"].replace({"b": "Mua", "s": "Bán"})
            data["Phân loại"] = data["Phân loại"].replace({"sheep": "Cừu non", "wolf": "Sói già", "shark": "Cá mập"})
            data["Giá"] = data["Giá"].astype(float)
            data["Giá"] = data["Giá"].apply(lambda x: round(x / 1000, 2))
            data["Thời gian"] = (pd.to_datetime(data["Thời gian"], unit="s", utc=True, errors="coerce")
                                .dt.tz_convert("Asia/Ho_Chi_Minh")
                                .dt.tz_localize(None)
                                .dt.floor("s")
                            )
            int_cols = ["Khối lượng", "Giá trị giao dịch"]
            data[int_cols] = data[int_cols].apply(pd.to_numeric, errors='coerce').astype("Int64")
            data = data.sort_values("Thời gian", ascending=True).reset_index(drop=True)
            return data
        except Exception as e :
            print(f"Lỗi sổ lệnh: {e}")
            return pd.DataFrame()
    
    def price_history(self, time, start=None, end=None):
        try:
            headers = {
                'content-type': 'application/json',
                'referer': 'https://trading.vietcap.com.vn/',
                'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36'
                }

            time_dict= {
                'days': 'ONE_DAY',
                'months': 'ONE_MONTH',
                'quarters': 'ONE_QUARTER',
                'years': 'ONE_YEAR'
                }

            if time=='months':
                start = start + '-01'
                end = end + '-01'
            elif time=='quarters':
                start = start + '-01-01'
                end = end + '-12-31'
            elif time=='years':
                start = start + '-01-01'
                end = end + '-01-01'

            start = datetime.strptime(start, '%Y-%m-%d')
            end = datetime.strptime(end, '%Y-%m-%d')

            start_date = start.strftime('%Y%m%d')
            end_date = end.strftime('%Y%m%d')

            params = {
                "timeFrame": time_dict[time] ,
                "fromDate": start_date,
                "toDate": end_date,
                "size": 50000
            }
            url=f'https://iq.vietcap.com.vn/api/iq-insight-service/v1/company/{self.symbol.upper()}/price-history'
            response=requests.get(url,headers=headers,params=params)
            data=json_normalize(response.json()['data']['content'])
            cols_price=['closePriceAdjusted',
                        'openPriceAdjusted',
                        'highestPriceAdjusted',
                        'lowestPriceAdjusted']
            col_volume=['totalMatchVolume',
                        'totalMatchValue',
                        'totalDealVolume',
                        'totalDealValue',
                        'totalVolume',
                        'totalValue',
                        'totalBuyUnmatchedVolume',
                        'totalSellUnmatchedVolume',    
                        'marketCap']
            cols_pricehis=['ticker','tradingDate','priceChange','percentPriceChangeAdjusted'] +cols_price + col_volume
            data=data[cols_pricehis]
            data['tradingDate'] = pd.to_datetime(data['tradingDate'])
            quy={'1': 'Q1',
                '4': 'Q2',
                '7': 'Q3',
                '10': 'Q4'}
            if time=='months':
                data['tradingDate'] = data['tradingDate'].dt.strftime('%Y-%m')
            elif time=='quarters':
                data['tradingDate']=(data['tradingDate'].dt.month.map(lambda m:quy.get(str(m),'')))+' '+data['tradingDate'].dt.year.astype(str)
            elif time=='years':
                data['tradingDate'] = data['tradingDate'].dt.strftime('%Y').astype(int)
            # data [['priceChange']+ cols_price] = data [['priceChange'] + cols_price].apply(lambda x:round(x/1000,2), axis=1)
            price_cols = ['priceChange'] + cols_price
            data[price_cols] = (data[price_cols] / 1000).round(2)
            data['percentPriceChangeAdjusted'] = data['percentPriceChangeAdjusted'].apply(lambda x: round(x*100,2))
            data [col_volume] = data [col_volume].fillna(0).round(0).astype(int)
            rename_his={
                'ticker': 'Mã CP',
                'tradingDate': 'Thời điểm GD',
                'priceChange': 'Thay đổi giá',
                'percentPriceChangeAdjusted': 'Thay đổi (%)',
                'closePriceAdjusted': 'Giá đóng cửa',
                'openPriceAdjusted': 'Giá mở cửa',
                'highestPriceAdjusted': 'Giá cao nhất',
                'lowestPriceAdjusted': 'Giá thấp nhất',
                'totalMatchVolume': 'KLGD khớp lệnh',
                'totalMatchValue': 'GTGD khớp lệnh',
                'totalDealVolume': 'KLGD thoả thuận',
                'totalDealValue': 'GTGD thoả thuận',
                'totalVolume': 'Tổng KLGD',
                'totalValue': 'Tổng GTGD',
                'totalBuyUnmatchedVolume': 'KLGD mua chờ khớp',
                'totalSellUnmatchedVolume': 'KLGD bán chờ khớp',
                'marketCap': 'Vốn hoá'
            } 
            data=data.rename(columns=rename_his)
            data = data.sort_values("Thời điểm GD", ascending=True).reset_index(drop=True)
            return data
        except Exception as e :
                print(f"Lỗi: {e}")
                return pd.DataFrame()

    def price_history_summary(self,time):
        try:
            headers = {
                'content-type': 'application/json',
                'referer': 'https://trading.vietcap.com.vn/',
                'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36'
                    }

            time_dict= {
                'days': 'ONE_DAY',
                'months': 'ONE_MONTH',
                'quarters': 'ONE_QUARTER',
                'years': 'ONE_YEAR'
                }
            params = {
                    "timeFrame": time_dict[time] ,
                    "size": 50000
                }

            url_summary=f'https://iq.vietcap.com.vn/api/iq-insight-service/v1/company/{self.symbol.upper()}/price-history-summary'
            response=requests.get(url_summary,headers=headers,params=params)
            data_summary=pd.json_normalize(response.json()['data'])
            cols_summary_his_total=['totalMatchVolume','totalMatchValue','totalDealVolume','totalDealValue','totalVolume','totalValue','totalBuyUnmatchedVolume','totalSellUnmatchedVolume']
            cols_summary_his_avg=['averageMatchVolume','averageMatchValue','averageDealVolume','averageDealValue','averageVolume','averageValue','totalBuyUnmatchedVolumeAvg','totalSellUnmatchedVolumeAvg']
            #pd.Series(data_summary.columns.tolist()).to_csv(r'D:\DE\API\vietcap\statistic\data_summary_columns.csv', index=False)

            rename_summary={'totalMatchVolume': 'KLGD khớp lệnh',
                            'totalMatchValue': 'GTGD khớp lệnh',
                            'totalDealVolume': 'KLGD thoả thuận',
                            'totalDealValue': 'GTGD thoả thuận',
                            'totalVolume': 'Tổng KLGD',
                            'totalValue': 'Tổng GTGD',
                            'totalBuyUnmatchedVolume': 'KLGD mua chờ khớp',
                            'totalSellUnmatchedVolume': 'KLGD bán chờ khớp',
                            'averageMatchVolume': 'KLGD khớp lệnh',
                            'averageMatchValue': 'GTGD khớp lệnh',
                            'averageDealVolume': 'KLGD thoả thuận',
                            'averageDealValue': 'GTGD thoả thuận',
                            'averageVolume': 'Tổng KLGD',
                            'averageValue': 'Tổng GTGD',
                            'totalBuyUnmatchedVolumeAvg': 'KLGD mua chờ khớp',
                            'totalSellUnmatchedVolumeAvg': 'KLGD bán chờ khớp'
                            } 

            data_summary_his_total=data_summary[cols_summary_his_total]
            data_summary_his_total.insert(0, 'Mã CP', self.symbol.upper())
            data_summary_his_total.insert(1, 'Phân loại', 'Tổng')
            data_summary_his_total= data_summary_his_total.rename(columns=rename_summary)

            data_summary_his_avg=data_summary[cols_summary_his_avg]
            data_summary_his_avg.insert(0, 'Mã CP', self.symbol.upper())
            data_summary_his_avg.insert(1, 'Phân loại', 'Trung bình')
            data_summary_his_avg = data_summary_his_avg.rename(columns=rename_summary)

            data_summary= pd.concat([data_summary_his_total, data_summary_his_avg], axis=0)
            cols=data_summary.columns[2:]
            data_summary[cols]= data_summary[cols].apply(lambda x : x.round(0).astype(int))
            return data_summary
        except Exception as e :
                print(f"Lỗi: {e}")
                return pd.DataFrame()
    
    def foreign_history(self, time, start=None, end=None):
        try:
            headers = {
                'content-type': 'application/json',
                'referer': 'https://trading.vietcap.com.vn/',
                'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36'
            }

            time_dict= {
                'days': 'ONE_DAY',
                'months': 'ONE_MONTH',
                'quarters': 'ONE_QUARTER',
                'years': 'ONE_YEAR'
                }
            if time=='months':
                start = start + '-01'
                end = end + '-01'
            elif time=='quarters':
                start = start + '-01-01'
                end = end + '-12-31'
            elif time=='years':
                start = start + '-01-01'
                end = end + '-01-01'
            start = datetime.strptime(start, '%Y-%m-%d')
            end = datetime.strptime(end, '%Y-%m-%d')
            start_date = start.strftime('%Y%m%d')
            end_date = end.strftime('%Y%m%d')
            params = {
                "timeFrame": time_dict[time] ,
                "fromDate": start_date,
                "toDate": end_date,
                "size": 50000
            }
            url=f'https://iq.vietcap.com.vn/api/iq-insight-service/v1/company/{self.symbol.upper()}/price-history'
            response=requests.get(url,headers=headers,params=params)
            data=json_normalize(response.json()['data']['content'])
            cols_amount=['foreignNetVolumeMatched',
                        'foreignNetValueMatched',
                        'foreignBuyVolumeMatched',
                        'foreignBuyValueMatched',
                        'foreignSellVolumeMatched',
                        'foreignSellValueMatched',
                        'foreignNetVolumeDeal',
                        'foreignNetValueDeal',
                        'foreignBuyVolumeDeal',
                        'foreignBuyValueDeal',
                        'foreignSellVolumeDeal',
                        'foreignSellValueDeal',
                        'foreignNetVolumeTotal',
                        'foreignNetValueTotal',
                        'foreignBuyVolumeTotal',
                        'foreignBuyValueTotal',
                        'foreignSellVolumeTotal',
                        'foreignSellValueTotal']
            cols_percent=['foreignRoomPercentage',   #(%)
                        'foreignOwnedPercentage',  #(%)
                        'foreignAvailablePercentage'] #(%)
            cols_data=['ticker','tradingDate']+cols_amount+cols_percent+['foreignCurrentRoom']
            data=data[cols_data]
            data['tradingDate'] = pd.to_datetime(data['tradingDate'])
            quy={'1': 'Q1',
                '4': 'Q2',
                '7': 'Q3',
                '10': 'Q4'}
            if time=='months':
                data['tradingDate'] = data['tradingDate'].dt.strftime('%Y-%m')
            elif time=='quarters':
                data['tradingDate']=(data['tradingDate'].dt.month.map(lambda m:quy.get(str(m),'')))+' '+data['tradingDate'].dt.year.astype(str)
            elif time=='years':
                data['tradingDate'] = data['tradingDate'].dt.strftime('%Y').astype(int)
            data [cols_amount+['foreignCurrentRoom']] = data [cols_amount+['foreignCurrentRoom']].astype(int)
            data[cols_percent] = data[cols_percent].apply(lambda x: round(x*100,2))
            rename_foreign = {
                'ticker': 'Mã CP',
                'tradingDate': 'Thời điểm GD',
                'foreignNetVolumeMatched': 'KLGD khớp lệnh ròng ',
                'foreignNetValueMatched': 'GTGD khớp lệnh ròng ',
                'foreignBuyVolumeMatched': 'KLGD khớp lệnh mua ',
                'foreignBuyValueMatched': 'GTGD khớp lệnh mua ',
                'foreignSellVolumeMatched': 'KLGD khớp lệnh bán ',
                'foreignSellValueMatched': 'GTGD khớp lệnh bán ',
                'foreignNetVolumeDeal': 'KLGD thoả thuận ròng ',
                'foreignNetValueDeal': 'GTGD thoả thuận ròng ',
                'foreignBuyVolumeDeal': 'KLGD thoả thuận mua ',
                'foreignBuyValueDeal': 'GTGD thoả thuận mua ',
                'foreignSellVolumeDeal': 'KLGD thoả thuận bán ',
                'foreignSellValueDeal': 'GTGD thoả thuận bán ',
                'foreignNetVolumeTotal': 'Tổng KLGD ròng',
                'foreignNetValueTotal': 'Tổng GTGD ròng',
                'foreignBuyVolumeTotal': 'Tổng KLGD mua',
                'foreignBuyValueTotal': 'Tổng GTGD mua',
                'foreignSellVolumeTotal': 'Tổng KLGD bán',
                'foreignSellValueTotal': 'Tổng GTGD bán',
                'foreignRoomPercentage': '% Khối ngoại tối đa',
                'foreignOwnedPercentage': '% Khối ngoại sở hữu',
                'foreignAvailablePercentage': '% Khối ngoại còn lại',
                'foreignCurrentRoom': 'CP còn lại'
            }
            data=data.rename(columns=rename_foreign)
            data = data.sort_values("Thời điểm GD", ascending=True).reset_index(drop=True)
            return data
        except Exception as e :
                print(f"Lỗi: {e}")
                return pd.DataFrame()

    def foreign_history_summary(self,time):
        try:
            headers = {
                'content-type': 'application/json',
                'referer': 'https://trading.vietcap.com.vn/',
                'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36'
                    }
            time_dict= {
                'days': 'ONE_DAY',
                'months': 'ONE_MONTH',
                'quarters': 'ONE_QUARTER',
                'years': 'ONE_YEAR'
                }
            params = {
                    "timeFrame": time_dict[time] ,
                    "size": 50000
                }
            url_summary=f'https://iq.vietcap.com.vn/api/iq-insight-service/v1/company/{self.symbol.upper()}/price-history-summary'
            response=requests.get(url_summary,headers=headers,params=params)
            data_summary=pd.json_normalize(response.json()['data'])
            cols_summary_foreign_total=['foreignNetVolumeMatched',
                                    'foreignNetValueMatched',
                                    'foreignBuyVolumeMatched',
                                    'foreignBuyValueMatched',
                                    'foreignSellVolumeMatched',
                                    'foreignSellValueMatched',
                                    'foreignNetVolumeDeal',
                                    'foreignNetValueDeal',
                                    'foreignBuyVolumeDeal',
                                    'foreignBuyValueDeal',
                                    'foreignSellVolumeDeal',
                                    'foreignSellValueDeal',
                                    'foreignNetVolumeTotal',
                                    'foreignNetValueTotal',
                                    'foreignBuyVolumeTotal',
                                    'foreignBuyValueTotal',
                                    'foreignSellVolumeTotal',
                                    'foreignSellValueTotal'
                                    ]
            cols_summary_foreign_avg=['foreignNetVolumeMatchedAvg',
                                    'foreignNetValueMatchedAvg',
                                    'foreignBuyVolumeMatchedAvg',
                                    'foreignBuyValueMatchedAvg',
                                    'foreignSellVolumeMatchedAvg',
                                    'foreignSellValueMatchedAvg',
                                    'foreignNetVolumeDealAvg',
                                    'foreignNetValueDealAvg',
                                    'foreignBuyVolumeDealAvg',
                                    'foreignBuyValueDealAvg',
                                    'foreignSellVolumeDealAvg',
                                    'foreignSellValueDealAvg',
                                    'foreignNetVolumeTotalAvg',
                                    'foreignNetValueTotalAvg',
                                    'foreignBuyVolumeTotalAvg',
                                    'foreignBuyValueTotalAvg',
                                    'foreignSellVolumeTotalAvg',
                                    'foreignSellValueTotalAvg'
                                    ]

            rename_summary={
                'foreignNetVolumeMatched': 'KLGD khớp lệnh ròng',
                'foreignNetValueMatched': 'GTGD khớp lệnh ròng',
                'foreignBuyVolumeMatched': 'KLGD khớp lệnh mua',
                'foreignBuyValueMatched': 'GTGD khớp lệnh mua',
                'foreignSellVolumeMatched': 'KLGD khớp lệnh bán',
                'foreignSellValueMatched': 'GTGD khớp lệnh bán',

                'foreignNetVolumeDeal': 'KLGD thoả thuận ròng',
                'foreignNetValueDeal': 'GTGD thoả thuận ròng',
                'foreignBuyVolumeDeal': 'KLGD thoả thuận mua',
                'foreignBuyValueDeal': 'GTGD thoả thuận mua',
                'foreignSellVolumeDeal': 'KLGD thoả thuận bán',
                'foreignSellValueDeal': 'GTGD thoả thuận bán',

                'foreignNetVolumeTotal': 'Tổng KLGD ròng',
                'foreignNetValueTotal': 'Tổng GTGD ròng',
                'foreignBuyVolumeTotal': 'Tổng KLGD mua',
                'foreignBuyValueTotal': 'Tổng GTGD mua',
                'foreignSellVolumeTotal': 'Tổng KLGD bán',
                'foreignSellValueTotal': 'Tổng GTGD bán',

                'foreignNetVolumeMatchedAvg': 'KLGD khớp lệnh ròng',
                'foreignNetValueMatchedAvg': 'GTGD khớp lệnh ròng',
                'foreignBuyVolumeMatchedAvg': 'KLGD khớp lệnh mua',
                'foreignBuyValueMatchedAvg': 'GTGD khớp lệnh mua',
                'foreignSellVolumeMatchedAvg': 'KLGD khớp lệnh bán',
                'foreignSellValueMatchedAvg': 'GTGD khớp lệnh bán',

                'foreignNetVolumeDealAvg': 'KLGD thoả thuận ròng',
                'foreignNetValueDealAvg': 'GTGD thoả thuận ròng',
                'foreignBuyVolumeDealAvg': 'KLGD thoả thuận mua',
                'foreignBuyValueDealAvg': 'GTGD thoả thuận mua',
                'foreignSellVolumeDealAvg': 'KLGD thoả thuận bán',
                'foreignSellValueDealAvg': 'GTGD thoả thuận bán',

                'foreignNetVolumeTotalAvg': 'Tổng KLGD ròng',
                'foreignNetValueTotalAvg': 'Tổng GTGD ròng',
                'foreignBuyVolumeTotalAvg': 'Tổng KLGD mua',
                'foreignBuyValueTotalAvg': 'Tổng GTGD mua',
                'foreignSellVolumeTotalAvg': 'Tổng KLGD bán',
                'foreignSellValueTotalAvg': 'Tổng GTGD bán',
            }
            data_summary_his_total=data_summary[cols_summary_foreign_total]
            data_summary_his_total.insert(0, 'Mã CP', self.symbol.upper())
            data_summary_his_total.insert(1, 'Phân loại', 'Tổng')
            data_summary_his_total= data_summary_his_total.rename(columns=rename_summary)
            data_summary_his_avg=data_summary[cols_summary_foreign_avg]
            data_summary_his_avg.insert(0, 'Mã CP', self.symbol.upper())
            data_summary_his_avg.insert(1, 'Phân loại', 'Trung bình')
            data_summary_his_avg = data_summary_his_avg.rename(columns=rename_summary)
            data_summary= pd.concat([data_summary_his_total, data_summary_his_avg], axis=0)
            cols=data_summary.columns[2:]
            data_summary[cols]= data_summary[cols].apply(lambda x : x.round(0).astype(int))
            return data_summary
        except Exception as e :
                print(f"Lỗi: {e}")
                return pd.DataFrame()
        
    def proprietary_history(self,time,start=None,end=None):
        try:
            headers = {
                'content-type': 'application/json',
                'referer': 'https://trading.vietcap.com.vn/',
                'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36'
                }

            time_dict= {
                'days': 'ONE_DAY',
                'months': 'ONE_MONTH',
                'quarters': 'ONE_QUARTER',
                'years': 'ONE_YEAR'
                }
            if time=='months':
                start = start + '-01'
                end = end + '-01'
            elif time=='quarters':
                start = start + '-01-01'
                end = end + '-12-31'
            elif time=='years':
                start = start + '-01-01'
                end = end + '-01-01'
            start = datetime.strptime(start, '%Y-%m-%d')
            end = datetime.strptime(end, '%Y-%m-%d')
            start_date = start.strftime('%Y%m%d')
            end_date = end.strftime('%Y%m%d')
            params = {
                "timeFrame": time_dict[time] ,
                "fromDate": start_date,
                "toDate": end_date,
                "size": 50000
            }
            url=f'https://iq.vietcap.com.vn/api/iq-insight-service/v1/company/{self.symbol.upper()}/proprietary-history'
            response=requests.get(url,headers=headers,params=params)
            data=json_normalize(response.json()['data']['content'])
            cols_volval=['totalMatchTradeNetVolume',
                            'totalMatchTradeNetValue',
                            'totalMatchBuyTradeVolume',
                            'totalMatchBuyTradeValue',
                            'totalMatchSellTradeVolume',
                            'totalMatchSellTradeValue',
                            'totalDealTradeNetVolume',
                            'totalDealTradeNetValue',
                            'totalDealBuyTradeVolume',
                            'totalDealBuyTradeValue',
                            'totalDealSellTradeVolume',
                            'totalDealSellTradeValue',
                            'totalTradeNetVolume',
                            'totalTradeNetValue',
                            'totalBuyTradeVolume',
                            'percentBuyTradeVolume',
                            'totalBuyTradeValue',
                            'percentBuyTradeValue',
                            'totalSellTradeVolume',
                            'percentSellTradeVolume',
                            'totalSellTradeValue',
                            'percentSellTradeValue'
                            ]
            cols_percent=['percentBuyTradeVolume',
                        'percentBuyTradeValue',
                        'percentSellTradeVolume',
                        'percentSellTradeValue'
                        ]
            int_cols=list(set(cols_volval)-set(cols_percent))
            cols_prop=['ticker','tradingDate'] + cols_volval
            data=data[cols_prop]
            data['tradingDate'] = pd.to_datetime(data['tradingDate'])
            quy={'1': 'Q1',
                '4': 'Q2',
                '7': 'Q3',
                '10': 'Q4'}
            if time=='months':
                data['tradingDate'] = data['tradingDate'].dt.strftime('%Y-%m')
            elif time=='quarters':
                data['tradingDate']=(data['tradingDate'].dt.month.map(lambda m:quy.get(str(m),'')))+' '+data['tradingDate'].dt.year.astype(str)
            elif time=='years':
                data['tradingDate'] = data['tradingDate'].dt.strftime('%Y').astype(int)
            data [cols_percent] = data [cols_percent].apply(lambda x:round(x*100,2))
            data [int_cols] = data [int_cols].fillna(0).round(0).astype(int)
            rename_prop={
                'ticker':'Mã CP',
                'tradingDate':'Thời điểm GD',
                'totalMatchTradeNetVolume': 'KLGD khớp lệnh ròng',
                'totalMatchTradeNetValue': 'GTGD khớp lệnh ròng',
                'totalMatchBuyTradeVolume': 'KLGD khớp lệnh mua',
                'totalMatchBuyTradeValue': 'GTGD khớp lệnh mua',
                'totalMatchSellTradeVolume': 'KLGD khớp lệnh bán',
                'totalMatchSellTradeValue': 'GTGD khớp lệnh bán',

                'totalDealTradeNetVolume': 'KLGD thoả thuận ròng',
                'totalDealTradeNetValue': 'GTGD thoả thuận ròng',
                'totalDealBuyTradeVolume': 'KLGD thoả thuận mua',
                'totalDealBuyTradeValue': 'GTGD thoả thuận mua',
                'totalDealSellTradeVolume': 'KLGD thoả thuận bán',
                'totalDealSellTradeValue': 'GTGD thoả thuận bán',

                'totalTradeNetVolume': 'Tổng KLGD ròng',
                'totalTradeNetValue': 'Tổng GTGD ròng',
                'totalBuyTradeVolume': 'Tổng KLGD mua',
                'percentBuyTradeVolume': 'Tỷ lệ KLGD mua (%)',
                'totalBuyTradeValue': 'Tổng GTGD mua',
                'percentBuyTradeValue': 'Tỷ lệ GTGD mua (%)',
                'totalSellTradeVolume': 'Tổng KLGD bán',
                'percentSellTradeVolume': 'Tỷ lệ KLGD bán (%)',
                'totalSellTradeValue': 'Tổng GTGD bán',
                'percentSellTradeValue': 'Tỷ lệ GTGD bán (%)'
            }
            data=data.rename(columns=rename_prop)
            data = data.sort_values("Thời điểm GD", ascending=True).reset_index(drop=True)
            return data
        except Exception as e :
                print(f"Lỗi: {e}")
                return pd.DataFrame()
        
    def proprietary_history_summary(self,time):
        try:
            headers = {
                'content-type': 'application/json',
                'referer': 'https://trading.vietcap.com.vn/',
                'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36'
                }

            time_dict= {
                    'days': 'ONE_DAY',
                    'months': 'ONE_MONTH',
                    'quarters': 'ONE_QUARTER',
                    'years': 'ONE_YEAR'
                    }
            params = {
                    "timeFrame": time_dict[time] ,
                    "size": 50000
                }
            url_sumary=f'https://iq.vietcap.com.vn/api/iq-insight-service/v1/company/{self.symbol.upper()}/proprietary-history-summary'
            response=requests.get(url_sumary,headers=headers,params=params)
            data_sumary=pd.json_normalize(response.json()['data'])
            cols_sumary_prop_total=["totalMatchTradeNetVolume",
                                    "totalMatchTradeNetValue",
                                    "totalMatchBuyTradeVolume",
                                    "totalMatchBuyTradeValue",
                                    "totalMatchSellTradeVolume",
                                    "totalMatchSellTradeValue",
                                    "totalDealTradeNetVolume",
                                    "totalDealTradeNetValue",
                                    "totalDealBuyTradeVolume",
                                    "totalDealBuyTradeValue",
                                    "totalDealSellTradeVolume",
                                    "totalDealSellTradeValue",
                                    "totalTradeNetVolume",
                                    "totalTradeNetValue",
                                    "totalBuyTradeVolume",
                                    "percentBuyTradeVolume",
                                    "totalBuyTradeValue",
                                    "percentBuyTradeValue",
                                    "totalSellTradeVolume",
                                    "percentSellTradeVolume",
                                    "totalSellTradeValue",
                                    "percentSellTradeValue"
                                    ]

            cols_sumary_prop_avg=["averageTotalMatchNetVolume",
                                "averageTotalMatchNetValue",
                                "averageTotalMatchBuyTradeVolume",
                                "averageTotalMatchBuyTradeValue",
                                "averageTotalMatchSellTradeVolume",
                                "averageTotalMatchSellTradeValue",
                                "averageTotalDealNetVolume",
                                "averageTotalDealNetValue",
                                "averageTotalDealBuyTradeVolume",
                                "averageTotalDealBuyTradeValue",
                                "averageTotalDealSellTradeVolume",
                                "averageTotalDealSellTradeValue",
                                "averageTotalTradeNetVolume",
                                "averageTotalTradeNetValue",
                                "averageTotalBuyTradeVolume",
                                "averagePercentBuyTradeVolume",
                                "averageTotalBuyTradeValue",
                                "averagePercentBuyTradeValue",
                                "averageTotalSellTradeVolume",
                                "averagePercentSellTradeVolume",
                                "averageTotalSellTradeValue",
                                "averagePercentSellTradeValue"
                                ]
            rename_summary = {
                # Khớp lệnh
                'totalMatchTradeNetVolume': 'KLGD ròng khớp lệnh',
                'totalMatchTradeNetValue': 'GTGD ròng khớp lệnh',
                'totalMatchBuyTradeVolume': 'KLGD mua khớp lệnh',
                'totalMatchBuyTradeValue': 'GTGD mua khớp lệnh',
                'totalMatchSellTradeVolume': 'KLGD bán khớp lệnh',
                'totalMatchSellTradeValue': 'GTGD bán khớp lệnh',

                'averageTotalMatchNetVolume': 'KLGD ròng khớp lệnh',
                'averageTotalMatchNetValue': 'GTGD ròng khớp lệnh',
                'averageTotalMatchBuyTradeVolume': 'KLGD mua khớp lệnh',
                'averageTotalMatchBuyTradeValue': 'GTGD mua khớp lệnh',
                'averageTotalMatchSellTradeVolume': 'KLGD bán khớp lệnh',
                'averageTotalMatchSellTradeValue': 'GTGD bán khớp lệnh',

                # Thỏa thuận
                'totalDealTradeNetVolume': 'KLGD ròng thoả thuận',
                'totalDealTradeNetValue': 'GTGD ròng thoả thuận',
                'totalDealBuyTradeVolume': 'KLGD mua thoả thuận',
                'totalDealBuyTradeValue': 'GTGD mua thoả thuận',
                'totalDealSellTradeVolume': 'KLGD bán thoả thuận',
                'totalDealSellTradeValue': 'GTGD bán thoả thuận',

                'averageTotalDealNetVolume': 'KLGD ròng thoả thuận',
                'averageTotalDealNetValue': 'GTGD ròng thoả thuận',
                'averageTotalDealBuyTradeVolume': 'KLGD mua thoả thuận',
                'averageTotalDealBuyTradeValue': 'GTGD mua thoả thuận',
                'averageTotalDealSellTradeVolume': 'KLGD bán thoả thuận',
                'averageTotalDealSellTradeValue': 'GTGD bán thoả thuận',

                # Tổng mua bán ròng
                'totalTradeNetVolume': 'Tổng KLGD ròng',
                'totalTradeNetValue': 'Tổng GTGD ròng',
                'totalBuyTradeVolume': 'Tổng KLGD mua',
                'percentBuyTradeVolume': 'Tỷ trọng KLGD mua (%)',
                'totalBuyTradeValue': 'Tổng GTGD mua',
                'percentBuyTradeValue': 'Tỷ trọng GTGD mua (%)',
                'totalSellTradeVolume': 'Tổng KLGD bán',
                'percentSellTradeVolume': 'Tỷ trọng KLGD bán (%)',
                'totalSellTradeValue': 'Tổng GTGD bán',
                'percentSellTradeValue': 'Tỷ trọng GTGD bán (%)',

                'averageTotalTradeNetVolume': 'Tổng KLGD ròng',
                'averageTotalTradeNetValue': 'Tổng GTGD ròng',
                'averageTotalBuyTradeVolume': 'Tổng KLGD mua',
                'averagePercentBuyTradeVolume': 'Tỷ trọng KLGD mua (%)',
                'averageTotalBuyTradeValue': 'Tổng GTGD mua',
                'averagePercentBuyTradeValue': 'Tỷ trọng GTGD mua (%)',
                'averageTotalSellTradeVolume': 'Tổng KLGD bán',
                'averagePercentSellTradeVolume': 'Tỷ trọng KLGD bán (%)',
                'averageTotalSellTradeValue': 'Tổng GTGD bán',
                'averagePercentSellTradeValue': 'Tỷ trọng GTGD bán (%)'
            }
            timevie_dict={
                    'days': 'ngày',
                    'months': 'tháng',
                    'quarters': 'quý',
                    'years': 'năm'
                    }
            data_sumary_prop_total=data_sumary[cols_sumary_prop_total]
            data_sumary_prop_total.insert(0, 'Mã CP', self.symbol.upper())
            data_sumary_prop_total.insert(1, 'Phân loại', 'Tổng đến hiện tại')
            data_sumary_prop_total= data_sumary_prop_total.rename(columns=rename_summary)
            data_sumary_prop_avg=data_sumary[cols_sumary_prop_avg]
            data_sumary_prop_avg.insert(0, 'Mã CP', self.symbol.upper())
            data_sumary_prop_avg.insert(1, 'Phân loại', f'Trung bình {timevie_dict[time]}')
            data_sumary_prop_avg = data_sumary_prop_avg.rename(columns=rename_summary)
            data_sumary= pd.concat([data_sumary_prop_total, data_sumary_prop_avg], axis=0)
            cols_percent=['Tỷ trọng KLGD mua (%)',
                        'Tỷ trọng GTGD mua (%)',              
                        'Tỷ trọng KLGD bán (%)',              
                        'Tỷ trọng GTGD bán (%)'
                        ]
            int_cols=list(set(data_sumary.columns[2:])-set(cols_percent))
            data_sumary[cols_percent]=data_sumary[cols_percent].apply(lambda x : round(x*100,2))
            data_sumary[int_cols]= data_sumary[int_cols].apply(lambda x : x.round(0).astype(int))
            return data_sumary
        except Exception as e :
                print(f"Lỗi: {e}")
                return pd.DataFrame()

    def demand_history(self,time,start,end):
        try:
            headers = {
                'content-type': 'application/json',
                'referer': 'https://trading.vietcap.com.vn/',
                'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36'
                }

            time_dict= {
                'days': 'ONE_DAY',
                'months': 'ONE_MONTH',
                'quarters': 'ONE_QUARTER',
                'years': 'ONE_YEAR'
                }
            if time=='months':
                start = start + '-01'
                end = end + '-01'
            elif time=='quarters':
                start = start + '-01-01'
                end = end + '-12-31'
            elif time=='years':
                start = start + '-01-01'
                end = end + '-01-01'
            start = datetime.strptime(start, '%Y-%m-%d')
            end = datetime.strptime(end, '%Y-%m-%d')
            start_date = start.strftime('%Y%m%d')
            end_date = end.strftime('%Y%m%d')
            params = {
                "timeFrame": time_dict[time] ,
                "fromDate": start_date,
                "toDate": end_date,
                "size": 50000
            }
            url=f'https://iq.vietcap.com.vn/api/iq-insight-service/v1/company/{self.symbol.upper()}/price-history'
            response=requests.get(url,headers=headers,params=params)
            data=json_normalize(response.json()['data']['content'])
            cols_demand=['ticker',
                        'tradingDate',
                        'totalBuyUnmatchedVolume',
                        'totalSellUnmatchedVolume',
                        'totalBuyTrade',
                        'totalSellTrade',
                        'totalBuyTradeVolume',
                        'totalSellTradeVolume',
                        'averageBuyTradeVolume',
                        'averageSellTradeVolume',
                        'totalNetTradeVolume']
            data=data[cols_demand]
            data['tradingDate'] = pd.to_datetime(data['tradingDate'])
            quy={'1': 'Q1',
                '4': 'Q2',
                '7': 'Q3',
                '10': 'Q4'}
            if time=='months':
                data['tradingDate'] = data['tradingDate'].dt.strftime('%Y-%m')
            elif time=='quarters':
                data['tradingDate']=(data['tradingDate'].dt.month.map(lambda m:quy.get(str(m),'')))+' '+data['tradingDate'].dt.year.astype(str)
            elif time=='years':
                data['tradingDate'] = data['tradingDate'].dt.strftime('%Y').astype(int)
            rename_his={
                'ticker': 'Mã CP',
                'tradingDate': 'Thời điểm GD',
                'totalBuyUnmatchedVolume': 'Khối lượng CP Mua chưa khớp',
                'totalSellUnmatchedVolume': 'Khối lượng CP Bán chưa khớp',
                'totalBuyTrade': 'Số lệnh đặt Mua',
                'totalSellTrade': 'Số lệnh đặt Bán',
                'totalBuyTradeVolume': 'Khối lượng CP Mua',
                'totalSellTradeVolume': 'Khối lượng CP Bán',
                'averageBuyTradeVolume': 'KLTB 1 lệnh Mua',
                'averageSellTradeVolume': 'KLTB 1 lệnh Bán',
                'totalNetTradeVolume': 'Chênh lệch KL đặt mua - đặt bán'
            } 
            data=data.rename(columns=rename_his)
            cols=data.columns[2:]
            data[cols] = data[cols].apply(lambda x : x.round(0).astype(int))
            data = data.sort_values("Thời điểm GD", ascending=True).reset_index(drop=True)
            return data
        except Exception as e :
                print(f"Lỗi: {e}")
                return pd.DataFrame()

class StockFinancial:
    def __init__(self, symbol):
        self.symbol = symbol

    def finance_ratio(self,time):
      try:
        headers={
          'content-type': 'application/json',
          'referer': 'https://trading.vietcap.com.vn/',
          'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36'
        }

        url=f'https://iq.vietcap.com.vn/api/iq-insight-service/v1/company/{self.symbol.upper()}/statistics-financial'
        response=requests.get(url,headers=headers)
        data=response.json()['data']
        data=pd.json_normalize(data)
        cols=['dividendYield',
              'cashRatio',
              'quickRatio',
              'currentRatio',
              'roe',
              'roa',
              'grossMargin',
              'ebitMargin',
              'preTaxProfitMargin',
              'afterTaxProfitMargin',
              'netInterestMargin',
              'averageYieldOnEarningAssets',
              'averageCostOfFinancing',
              'nonAndInterestIncome',
              'costToIncome',
              'loansGrowth',
              'depositGrowth',
              'ldrLoanDepositRatio',
              'npl',
              'loansLossReservesToNPLs',
              'loansLossReserveToLoans',
              'provisionToOutstandingLoans',
              'roic',
              'car',
              'casaRatio',
        ]
        data[cols]= round(data[cols]*100,2)

        if time=='quarters':
          data=data.loc[data['quarter']!=5]
          data['Quý']='Q'+ data['quarter'].astype(str) +" "+ data['year'].astype(str)
          quater=data.pop('Quý')
          data.insert(1,'Quý',quater)
          data=data.loc[:,data.sum()!=0]
          drop_cols=['year','quarter','ratioTTMId','ratioType','organCode','yearReport','cir']
          exsit_cols=[col for col in drop_cols if col in data.columns]
          data=data.drop(columns=exsit_cols)
        else:
          data=data.loc[data['quarter']==5]
          data=data.loc[:,data.sum()!=0]
          drop_cols=['quarter','ratioTTMId','ratioType','organCode','yearReport','cir','ratioYearId']
          exsit_cols=[col for col in drop_cols if col in data.columns]
          data=data.drop(columns=exsit_cols)


        data=data.rename(columns={
          'year':'Năm',
          'Quý':'Quý',
          'numberOfSharesMktCap':'Số cp lưu hành (triệu cp)',
          'marketCap':'Vốn hóa',
          'dividendYield':'Tỷ suất cổ tức(%)',
          'pe':'Chỉ số Giá trên Lợi nhuận',
          'pb':'Chỉ số Giá trên Giá trị sổ sách',
          'ps':'Chỉ số Giá trên Doanh thu',
          'priceToCashFlow':'Tỷ giá trên dòng tiền',
          'evToEbitda':'Chỉ số Giá trị doanh nghiệp trên lợi nhuận trước lãi vay, thuế và khấu hao',
          'cashRatio':'Thanh khoản tiền mặt (%)',
          'quickRatio':'Thanh khoản linh động (%)',
          'currentRatio':'Thanh khoản hiện tại (%)',
          'ownersEquity':'Vốn chủ sở hữu',
          'debtPerEquity':'Vay ngắn và dài hạn trên vốn chủ sở hữu',
          'debtToEquity':'Nợ trên vốn chủ sở hữu',
          'roe':'Chỉ số lợi nhuận trên vốn chủ sở hữu (%)',
          'roa':'Chỉ số lợi nhuận trên tổng tài sản (%)',
          'daySaleOutstanding':'Số ngày thu tiền bình quân',
          'daysInventoryOutstanding':'Số ngày tồn kho bình quân',
          'daysPayableOutstanding':'Số ngày thanh toán bình quân',
          'grossMargin':'Biên lợi nhuận gộp (%)',
          'ebitMargin':'Biên lợi nhuận (%)',
          'preTaxProfitMargin':'Biên lợi nhuận trước thuế (%)',
          'afterTaxProfitMargin':'Biên lợi nhuận ròng (%)',
          'assetTurnover':'Vòng quay tài sản',
          'netInterestMargin':'Tỷ suất lợi nhuận ròng(%)',
          'averageYieldOnEarningAssets':'Tỷ suất sinh lời từ tài sản có sinh lãi (%)',
          'averageCostOfFinancing':'Chi phí tài chính trung bình (%)',
          'nonAndInterestIncome':'Thu nhập ngoài lãi và từ lãi (%)',
          'costToIncome':'Chi phí trên thu nhập(%)',
          'loansGrowth':'Tăng trưởng tín dụng (%)',
          'depositGrowth':'Tăng trưởng tiền gửi(%)',
          'equityToLiabilities':'Vốn chủ trên tổng nợ',
          'equityToLoans':'Vốn chủ trên tổng vay',
          'totalEquityTotalAsset':'Vốn chủ trên tài sản',
          'ldrLoanDepositRatio':'Tỷ lệ dư nợ cho vay so với tiền gửi(%)',
          'npl':'Tỷ lệ nợ xấu(%)',
          'loansLossReservesToNPLs':'Dự phòng rủi ro tín dụng trên nợ xấu (%)',
          'loansLossReserveToLoans':'Dự phòng rủi ro tín dụng trên cho vay(%)',
          'provisionToOutstandingLoans':'Trích lập dự phòng trên cho vay (%)',
          'ebit':'Lợi nhuận trước lãi vay và thuế',
          'ebitda':'Lợi nhuận trước lãi vay, thuế và khấu hao tài sản',
          'roic':'Tỷ suất sinh lợi trên vốn đầu tư (%)',
          'cashCycle':'Chu kỳ tiền',
          'fixedAssetTurnover':'Vòng quay tài sản cố định',
          'financialLeverage':'Đòng bẩy tài chính',
          'car':'CAR(%)',
          #'equity':'kệ',
          'casaRatio':'Tiền gửi không kỳ hạn(%)',
          'nob66':'Tiền gửi không kỳ hạn',
          'nob69':'Tiền gửi ký quỹ',
          'nob70':'Tiền gửi mục đích riêng',
          'bsb113':'Tiền gửi của khách hàng'
          }
        )

        if time == 'quarters':
            datat = data.set_index("Quý").T
            datat.index.name = "Quý"
            datat = datat.reset_index()
            datat.columns.name = None

        else:
          datat = data.set_index("Năm").T
          datat.index.name = "Năm"
          datat = datat.reset_index()
          datat.columns.name = None

        for col in datat.columns[1:]:
            datat[col] = pd.to_numeric(datat[col], errors="coerce").astype("float64")
        return datat
      except Exception as e:
        print(f"❌ Không có dữ liệu '{self.symbol}': {e}")
        return pd.DataFrame()

    def balance_sheet(self,time):
      try:  
        headers = {
        'content-type': 'application/json',
        'referer': 'https://trading.vietcap.com.vn/?filter-group=HOSE&filter-value=HOSE&view-type=FLAT&type=stock',
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36'
        }
        url = f"https://iq.vietcap.com.vn/api/iq-insight-service/v1/company/{self.symbol.upper()}/financial-statement?section=BALANCE_SHEET"
        response = requests.get(url, headers=headers)

        data = response.json()['data'][time]
        data= json_normalize(data)
        data=data.loc[:,data.sum()!=0]
        if time == "quarters":
            data['Quý']='Q'+ data['lengthReport'].astype(str) +" "+ data['yearReport'].astype(str)
            quater=data.pop('Quý')
            data.insert(1,'Quý',quater)
            data.drop(["organCode","ticker","updateDate","publicDate",'lengthReport','yearReport'],axis=1,inplace=True)
        else:
            data.drop(["organCode","ticker","updateDate","lengthReport","publicDate"],axis=1,inplace=True)
            data['yearReport']=data['yearReport'].astype(str)

        # ==== Từ điển rename chính (cơ bản) ====
        rename_common = {
            'yearReport':'Năm',
            'Quý':'Quý',
            'bsa1':'TÀI SẢN NGẮN HẠN',
            'bsa10':'Trả trước người bán',
            'bsa11':'Phải thu nội bộ',
            'bsa120':'Cổ phiếu ưu đãi',
            'bsa13':'Phải thu khác',
            'bsa160':'Giao dịch mua bán lại trái phiếu Chính phủ',
            'bsa163':'Tài sản dở dang dài hạn',
            'bsa164':'Chi phí sản xuất, kinh doanh dở dang dài hạn',
            'bsa165':'Đầu tư dài hạn nắm giữ đến ngày đáo hạn',
            'bsa166':'Thiết bị, vật tư, phụ tùng thay thế dài hạn',
            'bsa167':'Doanh thu chưa thực hiện ngắn hạn',
            'bsa169':'Giao dịch mua bán lại trái phiếu chính phủ',
            'bsa170':'Người mua trả tiền trước dài hạn',
            'bsa171':'Chi phí phải trả dài hạn',
            'bsa177':'LNST chưa phân phối lũy kế đến cuối kỳ trước',
            'bsa178':'LNST chưa phân phối kỳ này',
            'bsa18':'Tài sản lưu động khác (tổng)',
            'bsa188':'Xây dựng cơ bản đang dở dang',
            'bsa19':'Chi phí trả trước ngắn hạn',
            'bsa2':'Tiền và tương đương tiền',
            'bsa20':'Thuế GTGT được khấu trừ',
            'bsa209':'Lợi thế thương mại',
            'bsa21':'Phải thu thuế khác',
            'bsa211':'Nguồn kinh phí đã hình thành TSCĐ',
            'bsa23':'TÀI SẢN DÀI HẠN',
            'bsa24':'Phải thu dài hạn',
            'bsa25':'Phải thu khách hàng dài hạn',
            'bsa276':'Vốn Góp liên doanh',
            'bsa277':'Đầu tư vào công ty liên kết',
            'bsa29':'Tài sản cố định',
            'bsa3':'Tiền',
            'bsa31':'Nguyên giá TSCĐ hữu hình',
            'bsa32':'Khấu hao lũy kế TSCĐ hữu hình',
            'bsa33':'GTCL tài sản thuê tài chính',
            'bsa34':'Nguyên giá tài sản thuê tài chính',
            'bsa35':'Khấu hao lũy kế tài sản thuê tài chính',
            'bsa36':'GTCL tài sản cố định vô hình',
            'bsa37':'Nguyên giá TSCĐ vô hình',
            'bsa38':'Khấu hao lũy kế TSCĐ vô hình',
            'bsa39':'Xây dựng cơ bản đang dang dở (trước 2015)',
            'bsa4':'Các khoản tương đương tiền',
            'bsa43':'Đầu tư dài hạn',
            'bsa44':'Đầu tư vào các công ty con',
            'bsa45':'Đầu tư vào các công ty liên kết',
            'bsa46':'Đầu tư dài hạn khác',
            'bsa47':'Dự phòng giảm giá đầu tư dài hạn',
            'bsa48':'Lợi thế thương mại (trước 2015)',
            'bsa49':'Tài sản dài hạn khác',
            'bsa5':'Đầu tư ngắn hạn (tổng)',
            'bsa50':'Trả trước dài hạn',
            'bsa51':'Thuế thu nhập hoãn lại (tài sản)',
            'bsa52':'Các tài sản dài hạn khác',
            'bsa53':'TỔNG TÀI SẢN',
            'bsa54':'NỢ PHẢI TRẢ',
            'bsa55':'Nợ ngắn hạn',
            'bsa57':'Phải trả người bán',
            'bsa58':'Người mua trả tiền trước',
            'bsa59':'Thuế và các khoản phải trả Nhà nước',
            'bsa60':'Phải trả người lao động',
            'bsa61':'Chi phí phải trả',
            'bsa62':'Phải trả nội bộ',
            'bsa64':'Phải trả khác',
            'bsa65':'Dự phòng các khoản phải trả ngắn hạn',
            'bsa66':'Quỹ khen thưởng, phúc lợi',
            'bsa67':'Nợ dài hạn',
            'bsa68':'Phải trả nhà cung cấp dài hạn',
            'bsa69':'Phải trả nội bộ dài hạn',
            'bsa7':'Dự phòng giảm giá',
            'bsa70':'Phải trả dài hạn khác',

            'bsa72':'Thuế thu nhập hoãn lại (nợ dài hạn)',
            'bsa76':'Doanh thu chưa thực hiện',
            'bsa77':'Quỹ phát triển khoa học công nghệ',
            'bsa78':'Vốn chủ sở hữu',
            'bsa79':'Vốn và các quỹ',
            'bsa8':'Các khoản phải thu',
            'bsa81':'Thặng dư vốn cổ phần',
            'bsa82':'Vốn khác',
            'bsa83':'Cổ phiếu quỹ',
            'bsa84':'Chênh lệch đánh giá lại tài sản',
            'bsa85':'Chênh lệch tỷ giá',
            'bsa87':'Quỹ dự phòng tài chính',
            'bsa89':'Quỹ khác',
            'bsa90':'Lợi nhuận chưa phân phối',
            'bsa91':'Quỹ hỗ trợ sắp xếp doanh nghiệp',
            'bsa93':'Quỹ khen thưởng, phúc lợi (trước 2010)',
            'bsa94':'Vốn ngân sách nhà nước và quỹ khác',
            'bsa96':'Tổng cộng nguồn vốn',
            'bsb100':'Chứng khoán kinh doanh',
            'bsb101':'Dự phòng giảm giá chứng khoán kinh doanh',
            'bsb102':'Các công cụ tài chính phái sinh và các tài sản tài chính khác',
            'bsb103':'Cho vay khách hàng (tổng)',
            'bsb104':'Cho vay khách hàng',
            'bsb105':'Dự phòng rủi ro cho vay khách hàng',
            'bsb106':'Chứng khoán đầu tư',
            'bsb107':'Chứng khoán đầu tư sẵn sàng để bán',
            'bsb108':'Đầu tư ngắn hạn nắm giữ đến ngày đáo hạn',
            'bsb109':'Dự phòng giảm giá chứng khoán đầu tư',
            'bsb110':'Tài sản Có khác (tổng)',
            'bsb111':'Các khoản nợ chính phủ và NHNN Việt Nam',
            'bsb112':'Tiền gửi và vay các Tổ chức tín dụng khác',
            'bsb113':'Tiền gửi của khách hàng',
            'bsb114':'Các công cụ tài chính phái sinh và các khoản nợ tài chính khác',
            'bsb115':'Vốn tài trợ, uỷ thác đầu tư của Chính phủ và các tổ chức tín dụng khác',
            'bsb116':'Phát hành giấy tờ có giá',
            'bsb117':'Các khoản nợ khác',
            'bsb118':'Vốn của tổ chức tín dụng',
            'bsb119':'Vốn đầu tư XDCB',
            'bsb120':'Cổ phiếu ưu đãi',
            'bsb121':'Quỹ của tổ chức tín dụng',
            'bsb131':'Bảo lãnh khác',
            'bsb158':'Bảo lãnh vay vốn',
            'bsb179':'Cam kết giao dịch hối đoái',
            'bsb180':'Cam kết mua ngoại tệ',
            'bsb181':'Cam kết bán ngoại tệ',
            'bsb182':'Cam kết giao dịch hoán đổi',
            'bsb183':'Cam kết giao dịch tương lai',
            'bsb184':'Cam kết cho vay không hủy ngang',
            'bsb185':'Cam kết trong nghiệp vụ L/C',
            'bsb186':'Cam kết khác',
            'bsb258':'Tiền gửi tại các TCTD khác',
            'bsb259':'Cho vay các TCTD khác',
            'bsb260':'Dự phòng rủi ro',
            'bsb261':'Hoạt động mua nợ',
            'bsb262':'Mua nợ',
            'bsb263':'Dự phòng rủi ro hoạt động mua nợ',
            'bsb264':'Các khoản phải thu',
            'bsb265':'Các khoản lãi và phí phải thu',
            'bsb266':'Tài sản thuế TNDN hoãn lại',
            'bsb267':'Tài sản Có khác',
            'bsb268':'Trong đó: Lợi thế thương mại',
            'bsb269':'Các khoản dự phòng rủi ro cho các tài sản Có nội bảng khác',
            'bsb270':'Tiền gửi của các tổ chức tín dụng khác',
            'bsb271':'Vay các tổ chức tín dụng khác',
            'bsb272':'Các khoản lãi, phí phải trả',
            'bsb273':'Thuế TNDN hoãn lại phải trả',
            'bsb274':'Các khoản phải trả và công nợ khác',
            'bsb275':'Dự phòng rủi ro khác',
            'bsb97':'Tiền gửi tại Ngân hàng nhà nước Việt Nam',
            'bsb98':'Tiền gửi tại các TCTD khác và cho vay các TCTD khác',
            'bsb99':'Chứng khoán kinh doanh (tổng)',
            'bss133':'Phải thu về hoạt động giao dịch chứng khoán (Trước năm 2016)',
            'bss135':'Phải trả hoạt động giao dịch chứng khoán',
            'bss136':'Phải trả cổ tức, gốc và lãi trái phiếu (Trước năm 2016)',
            'bss137':'Phải trả tổ chức phát hành chứng khoán (Trước năm 2016)',
            'bss138':'Quỹ bảo vệ Nhà đầu tư',
            'bss212':'Tiền chi nộp Quỹ Hỗ trợ thanh toán',
            'bss214':'Tài sản tài chính ngắn hạn',
            'bss215':'Các khoản cho vay',
            'bss216':'Các khoản tài chính sẵn sàng để bán (AFS)',
            'bss217':'Các khoản phải thu (từ 2016)',
            'bss218':'Phải thu bán các tài sản tài chính',
            'bss219':'Phải thu và dự thu cổ tức, tiền lãi các tài sản tài chính',
            'bss220':'Phải thu cổ tức, tiền lãi đến ngày nhận',
            'bss221':'Trong đó : phải thu khó đòi về cổ tức , tiền lãi đến ngày nhận nhưng chưa nhận được',
            'bss222':'Dự thu cổ tức , tiền lãi chưa đến ngày nhận',
            'bss223':'Thuế giá trị gia tăng được khấu trừ (Trước năm 2016)',
            'bss224':'Phải thu các dịch vụ CTCK cung cấp',
            'bss225':'Phải thu về lỗi giao dịch CK',
            'bss226':'Dự phòng suy giảm giá trị các khoản phải thu',
            'bss227':'Tạm ứng',
            'bss228':'Vật tư văn phòng, công cụ, dụng cụ',
            'bss229':'Cầm cố, thế chấp, ký quỹ , ký cược ngắn hạn',
            'bss230':'Dự phòng suy giảm giá trị TSNH khác',
            'bss231':'Tài sản tài chính dài hạn',
            'bss232':'Đánh giá TSCĐHH theo giá trị hợp lý',
            'bss233':'Đánh giá TSCĐTTC theo giá trị hợp lý',
            'bss234':'Đánh giá TSCĐVH theo giá trị hợp lý',
            'bss235':'Đánh giá BĐSĐT theo giá trị hợp lý',
            'bss236':'Cầm cố, thế chấp, kỹ quỹ, Ký cược dài hạn',
            'bss237':'Dự phòng suy giảm giá trị tài sản dài hạn',
            'bss239':'Nợ thuê tài sản tài chính ngắn hạn',
            'bss240':'Vay tài sản tài chính ngắn hạn',
            'bss241':'Trái phiếu chuyển đổi ngắn hạn - Cấu phần nợ',
            'bss242':'Trái phiếu phát hành ngắn hạn',
            'bss243':'Vay Quỹ Hỗ trợ thanh toán',
            'bss244':'Phải trả về lỗi giao dịch các tài sản tài chính',
            'bss245':'Các khoản trích nộp phúc lợi nhân viên',
            'bss246':'Nhận ký quỹ, ký cược ngắn hạn',

            'bss248':'Nợ thuê tài chính dài hạn',
            'bss249':'Vay tài sản tài chính dài hạn',
            'bss250':'Trái phiếu phát hành dài hạn',
            'bss251':'Nhận ký quỹ, ký cược dài hạn',
            'bss252':'Vốn đầu tư của chủ sở hữu',
            'bss253':'Quỹ dự trữ bổ sung vốn điều lệ',
            'bss254':'Lợi nhuận đã thực hiện',
            'bss255':'Lợi nhuận chưa thực hiện',
            'nos355':'Tài sản cố định thuê ngoài',
            'nos356':'Chứng chỉ có giá nhận giữ hộ',
            'nos357':'Tài sản nhận thế chấp',
            'nos358':'Nợ khó đòi đã xử lý',
            'nos359':'Ngoại tệ các loại',
            'nos360':'Cổ phiếu đang lưu hành (Số lượng)',
            'nos361':'Cổ phiếu quỹ (Số lượng)',
            'nos362':'Tài sản tài chính niêm yết/đăng ký giao dịch tại VSD của CTCK',
            'nos370':'Tài sản tài chính đã lưu ký tại VSD và chưa giao dịch của CTCK',
            'nos375':'Tài sản tài chính chờ về của CTCK',
            'nos376':'Tài sản tài chính sửa lỗi giao dịch của CTCK',
            'nos377':'Tài sản tài chính chưa lưu ký tại VSD của CTCK',
            'nos378':'Tài sản tài chính được hưởng quyền của CTCK',
            'nos379':'Tài sản tài chính niêm yết/đăng ký giao dịch tại VSD của NĐT',
            'nos380':'Tài sản tài chính giao dịch tự do chuyển nhượng',
            'nos381':'Tài sản tài chính hạn chế chuyển nhượng',
            'nos382':'Tài sản tài chính giao dịch cầm cố',
            'nos383':'Tài sản tài chính phong tỏa, tạm giữ',
            'nos384':'Tài sản tài chính chờ thanh toán',
            'nos385':'Tài sản tài chính chờ cho vay',
            'nos386':'Tài sản tài chính đã lưu ký tại VSD và chưa giao dịch của NĐT',
            'nos387':'Tài sản tài chính đã lưu ký tại VSD và chưa giao dịch, tự do chuyển nhượng',
            'nos388':'Tài sản tài chính đã lưu ký tại VSD và chưa giao dịch, hạn chế chuyển nhượng',
            'nos389':'Tài sản tài chính đã lưu ký tại VSD và chưa giao dịch, cầm cố',
            'nos390':'Tài sản tài chính đã lưu ký tại VSD và chưa giao dịch, phong tỏa, tạm giữ',
            'nos391':'Tài sản tài chính chờ về của NĐT',
            'nos392':'Tài sản tài chính sửa lỗi giao dịch của NĐT',
            'nos393':'Tài sản tài chính chưa lưu ký tại VSD của NĐT',
            'nos394':'Tài sản tài chính được hưởng quyền của Nhà đầu tư',
            'nos395':'Tiền gửi của khách hàng',
            'nos396':'Tiền gửi của Nhà đầu tư về giao dịch chứng khoán',
            'nos399':'Tiền gửi tổng hợp giao dịch chứng khoán cho khách hàng',
            'nos410':'Phải trả Tổ chức phát hành chứng khoán',
            'nos411':'Phải thu/phải trả của khách hàng về lỗi giao dịch các tài sản tài chính',
            'nos412':'Phải trả vay CTCK',
            'nos413':'Phải trả cổ tức, gốc và lãi trái phiếu',
            'nos607':'Tiền gửi bù trừ và thanh toán giao dịch chứng khoán',
            'nos608':'Tiền gửi bù trừ và thanh toán giao dịch chứng khoán Nhà đầu tư trong nước',
            'nos609':'Tiền gửi bù trừ và thanh toán giao dịch chứng khoán Nhà đầu tư nước ngoài',
            'nos610':'Tiền gửi của Tổ chức phát hành chứng khoán',
            'nos614':'Phải trả Nhà đầu tư về tiền gửi giao dịch chứng khoán theo phương thức CTCK quản lý',
            'nos615':'Phải trả Nhà đầu tư trong nước về tiền gửi giao dịch chứng khoán theo phương thức CTCK quản lý',
            'nos616':'Phải trả Nhà đầu tư nước ngoài về tiền gửi giao dịch chứng khoán theo phương thức CTCK quản lý'
            }

        stock=["AGR", "APS", "ART", "BSI", "BVS", "CTS", "FSC", "HCM", "IVS",
            "MBS", "ORS", "PSI", "SHS", "SSI", "TVB", "TVS", "VDS", "VND",
            "VPS", "VIX", "WSS", "DNSE", "YSVN", "TCSC", "APG", "EVS", "VCI","TCI"]
        bank=["ACB", "BAB", "BID", "BVB", "CTG", "EIB", "HDB", "KLB", "LPB", "MBB",
            "MSB", "NAB", "NVB", "OCB", "PGB", "SGB", "SHB", "STB", "TPB", "VCB",
            "VAB", "VBB", "VIB", "VietA", "VPB", "SEAB", "SCB", "ABB"]
        
        rename_stock = {
                    'bsa12':'Phải thu về XDCB (Trước năm 2016)',
                    'bsa14':'Dự phòng nợ khó đòi (Trước năm 2016)',
                    'bsa15':'Hàng tồn kho, ròng (Trước năm 2016)',
                    'bsa159':'Phải thu về cho vay ngắn hạn (Trước năm 2016)',
                    'bsa16':'Hàng tồn kho (Trước năm 2016)',
                    'bsa161':'Trả trước người bán dài hạn (Trước năm 2016)',
                    'bsa162':'Phải thu về cho vay dài hạn (Trước năm 2016)',
                    'bsa168':'Quỹ bình ổn giá (Trước năm 2016)',
                    'bsa17':'Dự phòng giảm giá HTK (Trước năm 2016)',
                    'bsa172':'Phải trả nội bộ về vốn kinh doanh (Trước năm 2016)',
                    'bsa173':'Trái phiếu chuyển đổi dài hạn - Cấu phần nợ',
                    'bsa174':'Cổ phiếu ưu đãi (Trước năm 2016)',
                    'bsa175':'Cổ phiếu phổ thông có quyền biểu quyết',
                    'bsa176':'Quyền chọn chuyển đổi trái phiếu - Cấu phần vốn',
                    'bsa22':'Tài sản ngắn hạn khác',
                    'bsa26':'Phải thu nội bộ dài hạn (Trước năm 2016)',
                    'bsa27':'Phải thu dài hạn khác (Trước năm 2016)',
                    'bsa28':'Dự phòng phải thu dài hạn (Trước năm 2016)',
                    'bsa40':'Bất động sản đầu tư',
                    'bsa6':'Các tài sản tài chính ghi nhận thông qua lãi lỗ (FVTPL)',
                    'bsa63':'Phải trả về xây dựng cơ bản (Trước năm 2016)',
                    'bsa73':'Dự phòng trợ cấp thôi việc (Trước năm 2016)',
                    'bsa80':'Vốn góp của chủ sở hữu',
                    'bsa86':'Quỹ đầu tư và phát triển (Trước năm 2016)',
                    'bsa9':'Phải thu khách hàng (Trước năm 2016)',
                    'bsa92':'Nguồn kinh phí và quỹ khác',
                    'bsa95':'LỢI ÍCH CỦA CỔ ĐÔNG KHÔNG KIỂM SOÁT (trước 2015)',
                    'bsi141':'Tài sản thiếu chờ xử lý (Trước năm 2016)',
                    'bss134':'Vốn kinh doanh ở các đơn vị trực thuộc (Trước năm 2016)',
                    'bss238':'Vay ngắn hạn',
                    'bsa56':'Vay và nợ thuê tài sản tài chính ngắn hạn',
                    'bss247':'Vay dài hạn',
                    'bsa71':'Vay và nợ thuê tài sản tài chính dài hạn',     
                }
        
        rename_bank = {
                    'bsa210':'Lợi ích của cổ đông thiểu số',
                        'bsa30':'Tài sản cố định hữu hình',
                        'bsa40':'Bất động sản đầu tư',
                        'bsa41':'Nguyên giá bất động sản đầu tư',
                        'bsa42':'Hao mòn bất động sản đầu tư',
                        'bsa80':'Vốn điều lệ',
                        'bsa95':'Lợi ích của cổ đông thiểu số (trước 2015)'
                }
    
        rename_other = {
                        'bsa12':'Phải thu hợp đồng xây dựng đang thực hiện',
                        'bsa14':'Dự phòng nợ khó đòi',
                        'bsa15':'Hàng tồn kho, ròng',
                        'bsa159':'Phải thu cho vay ngắn hạn',
                        'bsa16':'Hàng tồn kho',
                        'bsa161':'Trả trước người bán dài hạn',
                        'bsa162':'Phải thu cho vay dài hạn',
                        'bsa168':'Quỹ bình ổn giá',
                        'bsa17':'Dự phòng giảm giá hàng tồn kho',
                        'bsa172':'Phải trả nội bộ về vốn kinh doanh',
                        'bsa173':'Trái phiếu chuyển đổi',
                        'bsa174':'Cổ phiếu ưu đãi',
                        'bsa175':'Cổ phiếu phổ thông',
                        'bsa176':'Quyền chọn chuyển đổi trái phiếu',
                        'bsa210':'Lợi ích cổ đông không kiểm soát',
                        'bsa22':'Tài sản lưu động khác',
                        'bsa26':'Phải thu nội bộ dài hạn',
                        'bsa27':'Phải thu dài hạn khác',
                        'bsa28':'Dự phòng phải thu dài hạn',
                        'bsa30':'GTCL TSCĐ hữu hình',
                        'bsa40':'Giá trị ròng tài sản đầu tư',
                        'bsa41':'Nguyên giá tài sản đầu tư',
                        'bsa42':'Khấu hao lũy kế tài sản đầu tư',
                        'bsa6':'Đầu tư ngắn hạn',
                        'bsa63':'Phải trả về xây dựng cơ bản',
                        'bsa73':'Dự phòng trợ cấp thôi việc',
                        'bsa80':'Vốn góp',
                        'bsa86':'Quỹ đầu tư và phát triển',
                        'bsa9':'Phải thu khách hàng',
                        'bsa92':'Vốn Ngân sách nhà nước và quỹ khác',
                        'bsa95':'Lợi ích của cổ đông thiểu số',
                        'bsi141':'Tài sản thiếu cần xử lý',
                        'bss134':'Vốn kinh doanh ở các đơn vị trực thuộc',
                        'bsa56':'Vay ngắn hạn',
                        'bsa71':'Vay dài hạn',

                    }

        if self.symbol in stock:
            rename_dict = {**rename_common, **rename_stock}
        elif self.symbol in bank:
            rename_dict = {**rename_common, **rename_bank}
        else:
            rename_dict = {**rename_common, **rename_other}

        # ==== Đổi tên và chỉ giữ các cột có trong rename_dict ====
        data = data.rename(columns=rename_dict)
        data = data[[col for col in data.columns if col in rename_dict.values()]]

        if time == "quarters":
            datat = data.set_index("Quý").T
            datat.index.name = "Chỉ tiêu"
            datat = datat.reset_index()
            datat.columns.name = None

            quarter_cols = [c for c in datat.columns if c != "Chỉ tiêu"]
            quarter_sorted = sorted(
                quarter_cols,
                key=lambda x: (
                    int(str(x).split()[-1]),
                    int(str(x).replace("Q", "").split()[0])
                )
            )
            datat = datat[["Chỉ tiêu"] + quarter_sorted]

        else:
            datat = data.set_index("Năm").T
            datat.index.name = "Chỉ tiêu"
            datat = datat.reset_index()
            datat.columns.name = None

            year_cols = [c for c in datat.columns if c != "Chỉ tiêu"]
            year_cols = sorted(year_cols)
            datat = datat[["Chỉ tiêu"] + year_cols]

        for col in datat.columns[1:]:
            datat[col] = pd.to_numeric(datat[col], errors="coerce").astype("Int64")

        return datat
      except Exception as e:
        print(f"❌ Không có dữ liệu '{self.symbol}': {e}")
        return pd.DataFrame()
      
    def income_statement(self,time):
      try:
        headers = {
        'content-type': 'application/json',
        'referer': 'https://trading.vietcap.com.vn/',
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36'
        }

        url = f"https://iq.vietcap.com.vn/api/iq-insight-service/v1/company/{self.symbol}/financial-statement?section=INCOME_STATEMENT"
        response = requests.get(url, headers=headers)
        data=response.json()['data'][time]
        data=pd.DataFrame(data)
        data=data.loc[:,data.sum()!=0]
        if time == "quarters":
          data['Quý']='Q'+ data['lengthReport'].astype(str) +" "+ data['yearReport'].astype(str)
          quater=data.pop('Quý')
          data.insert(1,'Quý',quater)
          data.drop(["organCode","ticker","createDate","updateDate","publicDate",'lengthReport','yearReport'],axis=1,inplace=True)
        else:
          data.drop(["organCode","ticker","createDate","updateDate","lengthReport","publicDate"],axis=1,inplace=True)

        rename_dict = {
          'yearReport' : 'Năm',
          'isa1' : 'Doanh thu bán hàng và cung cấp dịch vụ',	
          'isa2' : 'Các khoản giảm trừ doanh thu',	
          'isa3' : 'Doanh thu thuần',	
          'isa4' : 'Giá vốn hàng bán',	
          'isa5' : 'Lợi nhuận gộp',	
          'isa6' : 'Doanh thu hoạt động tài chính',	
          'isa7' : 'Chi phí tài chính',	
          'isa8' : 'Chi phí lãi vay',	
          'isa9' : 'Chi phí bán hàng',	
          'isa10' : 'Chi phí quản lý doanh nghiệp',	
          'isa11' : 'Lãi/(lỗ) từ hoạt động kinh doanh',	
          'isa12' : 'Thu nhập khác',	
          'isa13' : 'Chi phí khác',	
          'isa14' : 'Thu nhập khác, ròng',	
          'isa15' : 'Lãi/(lỗ) từ công ty liên doanh',	
          'isa16' : 'Lãi/(lỗ) trước thuế',	
          'isa17' : 'Thuế thu nhập doanh nghiệp - hiện thời',	
          'isa18' : 'Thuế thu nhập doanh nghiệp - hoãn lại',	
          'isa19' : 'Chi phí thuế thu nhập doanh nghiệp',	
          'isa20' : 'Lãi/(lỗ) thuần sau thuế',	
          'isa21' : 'Lợi ích của cổ đông thiểu số',	
          'isa22' : 'Lợi nhuận của Cổ đông của Công ty mẹ',	
          'isa23' : 'Lãi cơ bản trên cổ phiếu (VND)',	
          'isa24' : 'Lãi trên cổ phiếu pha loãng (VND)',	
          'isb25' : 'Thu nhập lãi và các khoản thu nhập tương tự',	
          'isb26' : 'Chi phí lãi và các chi phí tương tự',	
          'isb27' : 'Thu nhập lãi thuần',	
          'isb28' : 'Thu nhập từ dịch vụ',	
          'isb29' : 'Chi phí dịch vụ',	
          'isb30' : 'Lãi/Lỗ thuần từ hoạt động dịch vụ',	
          'isb31' : 'Lãi/(lỗ) thuần từ hoạt động kinh doanh ngoại hối và vàng',	
          'isb32' : 'Lãi/(lỗ) thuần từ mua bán chứng khoán kinh doanh',	
          'isb33' : 'Lãi/(lỗ) thuần từ mua bán chứng khoán đầu tư',	
          'isb34' : 'Thu nhập khác',	
          'isb35' : 'Chi phí khác',	
          'isb36' : 'Lãi/(lỗ) thuần từ hoạt động khác',	
          'isb37' : 'Thu nhập từ cổ tức',	
          'isb38' : 'Tổng thu nhập hoạt động',	
          'isb39' : 'Chi phí quản lý doanh nghiệp',	
          'isb40' : 'Lợi nhuận thuần hoạt động trước khi trích lập dự phòng tổn thất tín dụng',	
          'isb41' : 'Trích lập dự phòng tổn thất tín dụng',	
          'iss42' : 'Doanh thu nghiệp vụ môi giới chứng khoán',	
          'iss43' : 'Doanh thu hoạt động đầu tư chứng khoán, góp vốn (Trước năm 2016)',	
          'iss44' : 'Doanh thu nghiệp vụ bảo lãnh phát hành chứng khoán',	
          'iss46' : 'Doanh thu nghiệp vụ tư vấn đầu tư chứng khoán',	
          'iss47' : 'Doanh thu lưu ký chứng khoán',	
          'iss48' : 'Doanh thu hoạt động ủy thác, đấu giá (Trước năm 2016)',	
          'iss49' : 'Thu cho thuê sử dụng tài sản (Trước năm 2016)',	
          'iss50' : 'Doanh thu khác',	
          'isa102' : 'Lãi/(lỗ) từ công ty liên doanh (từ năm 2015)',	
          'iss115' : 'Lãi từ các tài sản tài chính ghi nhận thông qua lãi/lỗ ( FVTPL)',	
          'iss116' : 'Lãi bán các tài sản tài chính FVTPL',	
          'iss117' : 'Chênh lệch tăng đánh giá lại các TSTC thông qua lãi/lỗ',	
          'iss118' : 'Cổ tức, tiền lãi phát sinh từ tài sản tài chính FVTPL',	
          'iss119' : 'Lãi từ các khoản đầu tư nắm giữ đến ngày đáo hạn',	
          'iss120' : 'Lãi từ các khoản cho vay và phải thu',	
          'iss121' : 'Lãi từ các tài sản tài chính sẵn sàng để bán',	
          'iss122' : 'Lãi từ các công cụ phát sinh phòng ngừa rủi ro',	
          'iss123' : 'Doanh thu hoạt động tư vấn tài chính',	
          'iss124' : 'Lỗ các tài sản tài chính ghi nhận thông qua lãi lỗ (FVTPL)',	
          'iss125' : 'Lỗ bán các tài sản tài chính',	
          'iss126' : 'Chênh lệch giảm đánh giá lại các TSTC thông qua lãi/lỗ',	
          'iss127' : 'Chi phí giao dịch mua các tài sản tài chính FVTPL',	
          'iss128' : 'Lỗ các khoản đầu tư nắm giữ đến ngày đáo hạn (HTM)',	
          'iss129' : 'Chi Phí Lãi Vay, Lỗ Từ Các Khoản Cho Vay Và Phải Thu (Trước Năm 2016)',	
          'iss130' : 'Lỗ Và Ghi Nhận Chênh Lệch Đánh Giá Theo Giá Trị Hợp Lý Tài Sản Tài Chính Sẵn Sàng Để Bán (Afs) Khi Phân Loại Lại',	
          'iss168' : 'Cp Dự Phòng Tstc, Xử Lý Tổn Thất Các Khoản Phải Thu Khó Đòi Là Lỗ Suy Giảm Tstc Và Cp Đi Vay',	
          'iss131' : 'Lỗ Từ Các Tài Sản Tài Chính Phái Sinh Phòng Ngừa Rủi Ro',	
          'iss132' : 'Chi phí hoạt động tự doanh',	
          'iss133' : 'Chi phí nghiệp vụ môi giới chứng khoán',	
          'iss134' : 'chi phí nghiệp vụ bảo lãnh, đại lý phát hành chứng khoán',	
          'iss135' : 'Chi phí nghiệp vụ tư vấn đầu tư chứng khoán',	
          'iss136' : 'Chí phí hoạt động đấu giá, ủy thác',	
          'iss137' : 'Chi phí nghiệp vụ lưu ký chứng khoán',	
          'iss138' : 'Chi phí hoạt động tư vấn tài chính',	
          'iss139' : 'Chi phí các dịch vụ khác',	
          'iss140' : 'Chi phí sửa lỗi giao dịch chứng khoán, lỗi khác',	
          'iss141' : 'Doanh thu từ hoạt động tài chính',	
          'iss142' : 'Chênh Lệch Lãi Tỷ Giá Hối Đoái Đã Và Chưa Thực Hiện',	
          'iss143' : 'Doanh Thu, Dự Thu Cổ Tức, Lãi Tiền Gửi Không Cố Định Phát Sinh Trong Kỳ',	
          'iss144' : 'Lãi Bán, Thanh Lý Các Khoản Đầu Tư Vào Công Ty Con, Liên Kết, Liên Doanh',	
          'iss145' : 'Doanh thu khác về đầu tư',	
          'iss146' : 'Chi phí tài chính',	
          'iss147' : 'Chênh Lệch Lỗ Tỷ Giá Hối Đoái Đã Và Chưa Thực Hiện',	
          'iss148' : 'Chi phí lãi vay',	
          'iss149' : 'Lỗ Bán, Thanh Lý Các Khoản Đầu Tư Vào Công Ty Con, Liên Kết, Liên Doanh',	
          'iss150' : 'Chi Phí Dự Phòng Suy Giảm Giá Trị Các Khoản Đầu Tư Tài Chính Dài Hạn',	
          'iss151' : 'Chi phí đầu tư khác',	
          'iss152' : 'Chi phí bán hàng',	
          'iss153' : 'Lợi nhuận đã thực hiện',	
          'iss154' : 'Lợi nhuận chưa thực hiện',	
          'iss155' : 'Lnst Trích Các Quỹ Dự Trữ Điều Lệ, Quỹ Dự Phòng Tài Chính Và Rủi Ro Nghề Nghiệp',	
          'iss156' : 'Lãi/(Lỗ) Từ Đánh Giá Lại Các Các Khoản Đầu Tư Giữ Đến Ngày Đáo Hạn',	
          'iss157' : 'Lãi/(Lỗ) Từ Đánh Giá Lại Các Tài Sản Tài Chính Sẵn Sàng Để Bán',	
          'iss158' : 'Lãi/(Lỗ) Toàn Diện Khác Được Chia Từ Hoạt Động Đầu Tư Vào Công Ty Con, Đầu Tư Liên Kết, Liên Doanh',	
          'iss159' : 'Lãi/(Lỗ) Từ Đánh Giá Lại Các Công Cụ Tài Chính Phái Sinh',	
          'iss160' : 'Lãi/(Lỗ) Chênh Lệch Tỷ Giá Của Hoạt Động Tại Nước Ngoài',	
          'iss161' : 'Lãi/(Lỗ) Từ Các Khoản Đầu Tư Vào Công Ty Con. Công Ty Liên Kết, Liên Doanh Chưa Chia',	
          'iss162' : 'Lãi/(lỗ) đánh giá công cụ phái sinh',	
          'iss163' : 'Lãi/(Lỗ) Đánh Giá Lại Tài Sản Cố Định Theo Mô Hình Giá Trị Hợp Lý',	
          'iss164' : 'Tổng thu nhập toàn diện',	
          'iss165' : 'Thu Nhập Toàn Diện Phân Bổ Cho Chủ Sở Hữu',	
          'iss166' : 'Thu Nhập Toàn Diện Phân Bổ Cho Cổ Đông Không Nắm Quyền Kiểm Soát',	
          'iss167' : 'Thu Nhập Thuần Trên Cổ Phiếu Phổ Thông',	
          'iss174' : 'Thu nhập (lỗ) toàn diện khác sau thuế'	

        }

        data=data.rename(columns=rename_dict)
        data = data[[col for col in data.columns if col in rename_dict.values() or col == 'Quý']]

        if time == "quarters":
            num_cols = [c for c in data.columns if c != "Quý"]
            data[num_cols] = data[num_cols].apply(pd.to_numeric, errors="coerce").astype("Int64")

            datat = data.set_index("Quý").T
            datat.index.name = "Chỉ tiêu"
            datat = datat.reset_index()
            datat.columns.name = None

            quarter_cols = [c for c in datat.columns if c != "Chỉ tiêu"]
            quarter_sorted = sorted(
                quarter_cols,
                key=lambda x: (
                    int(str(x).split()[-1]),
                    int(str(x).replace("Q", "").split()[0])
                )
            )
            datat = datat[["Chỉ tiêu"] + quarter_sorted]

        else:
            num_cols = [c for c in data.columns if c != "Năm"]
            data[num_cols] = data[num_cols].apply(pd.to_numeric, errors="coerce").astype("Int64")

            datat = data.set_index("Năm").T
            datat.index.name = "Chỉ tiêu"
            datat = datat.reset_index()
            datat.columns.name = None

            year_cols = [c for c in datat.columns if c != "Chỉ tiêu"]
            year_cols = sorted(year_cols)
            datat = datat[["Chỉ tiêu"] + year_cols]

        return datat
      except Exception as e:
        print(f"❌ Không có dữ liệu '{self.symbol}': {e}")
        return pd.DataFrame()

    def cash_flow(self,time):
      try:  
        headers={
            'content-type': 'application/json',
            'referer': 'https://trading.vietcap.com.vn/',
            'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36'
        }

        url=f'https://iq.vietcap.com.vn/api/iq-insight-service/v1/company/{self.symbol.upper()}/financial-statement?section=CASH_FLOW'
        response=requests.get(url,headers=headers)

        if time=='years':
            data=response.json()['data']['years']
            data=pd.json_normalize(data)
            data=data.loc[:,data.sum()!=0]
            cols=['organCode','ticker','createDate','updateDate','lengthReport','publicDate','cfs222','cfa44','cfa45','cfs107','cfs108','cfs109','cfs110','cfs111','cfs112']
            col_drop=[col for col in cols if col in data.columns]
            data=data.drop(columns=col_drop)
            data['yearReport']=data['yearReport'].astype(str)

        else:
            data=response.json()['data']['quarters']
            data=pd.json_normalize(data)
            data['Quý']='Q'+ data['lengthReport'].astype(str) +" "+ data['yearReport'].astype(str)
            quater=data.pop('Quý')
            data.insert(1,'Quý',quater)
            data=data.loc[:,data.sum()!=0]
            cols=['organCode','ticker','createDate','updateDate','publicDate','yearReport','lengthReport','cfs222','cfa44','cfa45','cfs107','cfs108','cfs109','cfs110','cfs111','cfs112']
            col_drop=[col for col in cols if col in data.columns]
            data=data.drop(columns=col_drop)


        #data=data.rename(columns={
        rename_common={
            'yearReport':'Năm',
            'cfa1':'Lợi nhuận/(lỗ) trước thuế',
            'cfa103':'Phân bổ lợi thế thương mại',
            'cfa104':'Các khoản điều chỉnh khác',
            'cfa105':'(Tăng)/giảm chi phí trả trước',
            'cfa19':'Tiền chi để mua sắm, xây dựng TSCĐ, BĐSĐT và các tài sản dài hạn khác',
            'cfa2':'Khấu hao TSCĐ và BĐSĐT',
            'cfa20':'Tiền thu từ thanh lý, nhượng bán TSCĐ, BĐSĐT và các tài sản dài hạn khác',
            'cfa21':'Tiền chi cho vay, mua các công cụ nợ của đơn vị khác',
            'cfa22':'Tiền thu hồi cho vay, bán lại các công cụ nợ của đơn vị khác',
            'cfa23':'Tiền chi đầu tư góp vốn vào công ty con, công ty liên doanh, liên kết và đầu tư khác',
            'cfa24':'Tiền thu hồi các khoản đầu tư góp vốn vào công ty con, công ty liên doanh, liên kết và đầu tư khác',
            'cfa25':'Tiền thu lãi cho vay, cổ tức và lợi nhuận được chia',
            'cfa26':'Lưu chuyển tiền thuần từ hoạt động đầu tư',
            'cfa27':'Tiền thu từ phát hành cổ phiếu, nhận vốn góp của chủ sở hữu',
            'cfa28':'Tiền chi trả vốn góp cho các chủ sở hữu, mua lại cổ phiếu của doanh nghiệp đã phát hành',
            'cfa29':'Tiền thu được các khoản đi vay',
            'cfa3':'Chi phí dự phòng',
            'cfa30':'Tiền trả nợ gốc vay',
            'cfa31':'Tiền trả nợ gốc thuê tài chính',
            'cfa32':'Cổ tức, lợi nhuận đã trả cho chủ sở hữu',
            'cfa33':'Tiền lãi đã nhận',
            'cfa34':'Lưu chuyển tiền thuần từ hoạt động tài chính',
            'cfa35':'Lưu chuyển tiền thuần trong kỳ',
            'cfa36':'Tiền và tương đương tiền đầu kỳ',
            'cfa37':'Ảnh hưởng của thay đổi tỷ giá hối đoái quy đổi ngoại tệ',
            'cfa38':'Tiền và tương đương tiền cuối kỳ',
            'cfa4':'Lãi/lỗ chênh lệch tỷ giá hối đoái do đánh giá lại các khoản mục tiền tệ có gốc ngoại tệ',
            'cfa43':'Tiền thuế thu nhập thực nộp trong kỳ',
            'cfa5':'Lãi/(lỗ) từ thanh lý tài sản cố định',
            'cfa6':'(Lãi)/lỗ từ hoạt động đầu tư',
            'cfa7':'Chi phí lãi vay',
            'cfa8':'Thu lãi và cổ tức',
            'cfa9':'Lưu chuyển tiền thuần từ hoạt động kinh doanh trước những thay đổi về tài sản và vốn lưu động',
            'cfb106':'Tiền thu các khoản nợ đã được xử lý, xóa, bù đắp bằng nguồn rủi ro',
            'cfb221':'Chênh lệch số tiền thực thu/thực chi từ hoạt động kinh doanh',
            'cfb48':'Tiền gửi tại NHNN',
            'cfb49':'Tăng/giảm các khoản tiền gửi và cho vay các tổ chức tín dụng khác',
            'cfb50':'Tăng/giảm các khoản về kinh doanh chứng khoán',
            'cfb51':'Tăng/giảm các công cụ tài chính phái sinh và các tài sản tài chính khác',
            'cfb52':'Tăng/giảm các khoản cho vay khách hàng',
            'cfb53':'(Tăng)/Giảm lãi, phí phải thu',
            'cfb54':'Tăng/giảm nguồn dự phòng để bù đắp tổn thất các khoản',
            'cfb55':'Tăng/giảm khác về tài sản hoạt động',
            'cfb56':'Tăng/(Giảm) các khoản nợ chính phủ và NHNN',
            'cfb57':'Tăng/(Giảm) các khoản tiền gửi và vay các TCTD khác',
            'cfb58':'Tăng/(Giảm) tiền gửi của khách hàng',
            'cfb59':'Tăng/(Giảm) các công cụ tài chính phái sinh và các khoản nợ tài chính khác',
            'cfb60':'Tăng/(Giảm) vốn tài trợ, uỷ thác đầu tư của chính phủ và các TCTD khác',
            'cfb61':'Tăng/(Giảm) phát hành giấy tờ có giá',
            'cfb62':'Tăng/(Giảm) lãi, phí phải trả',
            'cfb63':'Tăng/(Giảm) khác về công nợ hoạt động',
            'cfb64':'Lưu chuyển tiền thuần từ hoạt động kinh doanh trước thuế thu nhập DN',
            'cfb65':'Chi từ các quỹ của TCTD',
            'cfb66':'Thu được từ nợ khó đòi',
            'cfb67':'Tiền chi từ thanh lý, nhượng bán TSCĐ',
            'cfb68':'Mua sắm Bất động sản đầu tư',
            'cfb69':'Tiền thu từ bán, thanh lý bất động sản đầu tư',
            'cfb70':'Tiền chi ra do bán, thanh lý bất động sản đầu tư',
            'cfb71':'Tiền thu từ phát hành giấy tờ có giá dài hạn đủ điều kiện tính vào vốn tự có và các khoản vốn vay dài hạn khác',
            'cfb72':'Tiền chi thanh toán giấy tờ có giá dài hạn đủ điều kiện tính vào vốn tự có và các khoản vốn vay dài hạn khác',
            'cfb73':'Tiền chi ra mua cổ phiếu quỹ',
            'cfb74':'Tiền thu được do bán cổ phiếu quỹ',
            'cfb75':'Thu nhập lãi và các khoản thu nhập tương tự nhận được',
            'cfb76':'Chi phí lãi và các chi phí tương tự đã trả',
            'cfb77':'Thu nhập từ hoạt động dịch vụ nhận được',
            'cfb78':'Thu nhập thuần từ hoạt động kinh doanh ngoại hối và vàng',
            'cfb79':'Thu nhập từ hoạt động kinh doanh chứng khoán',
            'cfb80':'Thu nhập khác',
            'cfb81':'Tiền chi trả cho nhân viên và hoạt động quản lý, cộng cụ',
            'cfs113':'Tiền vay Quỹ Hỗ trợ thanh toán',
            'cfs114':'Tiền vay khác',
            'cfs115':'Tiền chi trả gốc vay Quỹ Hỗ trợ thanh toán',
            'cfs116':'Tiền chi trả nợ gốc vay tài sản tài chính',
            'cfs117':'Tiền chi trả gốc nợ vay khác',
            'cfs118':'Tiền mặt, tiền gửi ngân hàng đầu kỳ',
            'cfs119':'Tiền gửi ngân hàng cho hoạt động CTCK (đầu kỳ)',
            'cfs120':'Các khoản tương đương tiền (Lưu chuyển thuần trong kỳ) (Đầu kỳ)',
            'cfs121':'Tiền mặt, tiền gửi ngân hàng cuối kỳ',
            'cfs122':'Tiền gửi ngân hàng cho hoạt động CTCK (Cuối kỳ)',
            'cfs123':'Các khoản tương đương tiền (Lưu chuyển thuần trong kỳ) (Cuối kỳ)',
            'cfs124':'Ảnh hưởng của thay đổi tỷ giá hối đoái quy đổi ngoại tệ (Lưu chuyển thuần trong kỳ) (Cuối kỳ)',
            'cfs125':'Tiền thu bán chứng khoán môi giới cho khách hàng',
            'cfs126':'Tiền chi mua chứng khoán môi giới cho khách hàng',
            'cfs127':'Tiền thu bán chứng khoán ủy thác của khách hàng',
            'cfs128':'Tiền chi bán chứng khoán ủy thác của khách hàng',
            'cfs129':'Thu tiền từ tài khoản vãng lai của khách hàng (Trước năm 2016)',
            'cfs130':'Chi tiền từ tài khoản vãng lai của khách hàng (Trước năm 2016)',
            'cfs131':'Thu vay Quỹ Hỗ trợ thanh toán',
            'cfs132':'Chi trả vay Quỹ Hỗ trợ thanh toán',
            'cfs133':'Nhận tiền gửi để thanh toán giao dịch chứng khoán của khách hàng',
            'cfs134':'Nhận tiền gửi của Nhà đầu tư cho hoạt động ủy thác đầu tư của khách hàng',
            'cfs135':'Chi trả phí lưu ký chứng khoán của khách hàng',
            'cfs136':'Thu lỗi giao dịch chứng khoán',
            'cfs137':'Chi lỗi giao dịch chứng khoán',
            'cfs138':'Tiền thu của Tổ chức phát hành chứng khoán',
            'cfs139':'Tiền chi trả Tổ chức phát hành chứng khoán',
            'cfs140':'Lưu chuyển tiền hoạt động môi giới, ủy thác của khách hàng',
            'cfs142':'Tiền gửi ngân hàng đầu kỳ',
            'cfs143':'Tiền gửi của NĐT về GDCK theo phương thức CTCK quản lý (Đầu kỳ)',
            'cfs144':'Tiền gửi của NĐT về GDCK theo phương thức CTCK quản lý (Đầu kỳ): có kỳ hạn',
            'cfs145':'Tiền gửi tổng hợp GDCK cho khách hàng (Đầu kỳ)',
            'cfs146':'Tiền gửi bù trừ và thanh toán GDCK (đầu kỳ)',
            'cfs147':'Tiền gửi của tổ chức phát hành (đầu kỳ)',
            'cfs148':'Tiền gửi của tổ chức phát hành (Đầu kỳ): có kỳ hạn',
            'cfs149':'Tiền gửi của NĐT về GDCK theo phương thức NHTM quản lý (Đầu kỳ) (Trước năm 2016)',
            'cfs150':'Tiền gửi của NĐT về GDCK theo phương thức NHTM quản lý (Đầu kỳ): có kỳ hạn (Trước năm 2016)',
            'cfs151':'Các khoản tương đương tiền ( hoạt động môi giới, ủy thác của khách hàng) (Đầu kỳ)',
            'cfs152':'Ảnh hưởng của thay đổi tỷ giá hối đoái quy đổi ngoại tệ (Đầu kỳ)',
            'cfs154':'Tiền gửi ngân hàng cuối kỳ',
            'cfs155':'Tiền gửi của NĐT về GDCK theo phương thức CTCK quản lý (Cuối kỳ)',
            'cfs156':'Tiền gửi của NĐT về GDCK theo phương thức CTCK quản lý (Cuối kỳ): có kỳ hạn',
            'cfs157':'Tiền gửi của NĐT về GDCK theo phương thức NHTM quản lý (Cuối kỳ) (Trước năm 2016)',
            'cfs158':'Tiền gửi của NĐT về GDCK theo phương thức NHTM quản lý (Cuối kỳ): có kỳ hạn (Trước năm 2016)',
            'cfs159':'Tiền gửi tổng hợp GDCK cho khách hàng (Cuối kỳ)',
            'cfs160':'Tiền gửi bù trừ và thanh toán GDCK (Cuối kỳ)',
            'cfs161':'Tiền gửi của tổ chức phát hành (Cuối kỳ)',
            'cfs162':'Tiền gửi của tổ chức phát hành (Cuối kỳ): có kỳ hạn',
            'cfs163':'Các khoản tương đương tiền ( hoạt động môi giới, ủy thác của khách hàng) (Cuối kỳ)',
            'cfs164':'Ảnh hưởng của thay đổi tỷ giá hối đoái quy đổi ngoại tệ (hoạt động môi giới, ủy thác của khách hàng) (Cuối kỳ)',
            'cfs165':'Điều chỉnh cho các khoản',
            'cfs166':'Chi phí phải trả, chi phí trả trước',
            'cfs167':'Tăng các chi phí phi tiền tệ',
            'cfs168':'Lỗ đánh giá giá trị các tài sản tài chính ghi nhận thông qua lãi/lỗ FVTPL',
            'cfs169':'Lỗ đánh giá giá trị các công nợ tài chính ghi nhận thông qua KQKD (Trước năm 2016)',
            'cfs170':'Lỗ đánh giá giá trị các công cụ tài chính phái sinh (Trước năm 2016)',
            'cfs171':'Lỗ từ thanh lý các tài sản tài chính sẵn sàng để bán (Trước năm 2016)',
            'cfs172':'Suy giảm giá trị của các tài sản tài chính sẵn sàng để bán (Trước năm 2016)',
            'cfs173':'Lỗ suy giảm giá trị các khoản đầu tư nắm giữ đến ngày đáo hạn (HTM)',
            'cfs174':'Lỗ suy giảm giá trị các khoản cho vay',
            'cfs175':'Lỗ về ghi nhận chênh lệch đánh giá theo giá trị hợp lý tài sản tài chính sẵn sàng để bán AFS khi phân loại lại',
            'cfs176':'Lỗ đánh giá giá các công cụ tài chính phát sinh cho mục đích phòng ngừa rủi ro (Trước năm 2016)',
            'cfs177':'Lỗ từ thanh lý TSCĐ (Trước năm 2016)',
            'cfs178':'Suy giảm giá trị của các tài sản cố định, BĐSĐT',
            'cfs179':'Chi phí dự phòng suy giảm giá trị các khoản đầu tư tài chính dài hạn',
            'cfs180':'Lỗ từ thanh lý các khoản đầu tư vào công ty con và công ty liên doanh, liên kết (Trước năm 2016)',
            'cfs181':'Lỗ khác',
            'cfs182':'Giảm các doanh thu phi tiền tệ',
            'cfs183':'Lãi đánh giá giá trị các tài sản chính ghi nhận thông qua lãi/lỗ FVTPL',
            'cfs184':'Lãi đánh giá giá trị các công nợ tài chính thông qua kết quả kinh doanh (Trước năm 2016)',
            'cfs185':'Lãi từ thanh lý các tài sản tài chính sẵn sàng để bán (Trước năm 2016)',
            'cfs186':'Hoàn nhập suy giảm giá trị của các tài sản tài chính sẵn sàng để bán (Trước năm 2016)',
            'cfs187':'Lãi về ghi nhận chệnh lệch đánh giá theo giá trị hợp lý tài sản tài chính sẵn sàng để bán AFS khi phân loại lại',
            'cfs188':'Lãi đánh giá giá trị các công cụ tài chính phái sinh cho mục đích phòng ngừa',
            'cfs189':'Lãi từ thanh lý các khoản cho vay và phải thu',
            'cfs190':'Hoàn nhập chi phí dự phòng',
            'cfs191':'Lãi từ thanh lý tài sản cố định, BĐSĐT',
            'cfs192':'Lãi từ thanh lý các khoản đầu tư vào công ty con và công ty liên doanh, liên kết',
            'cfs193':'Lãi khác',
            'cfs194':'Thay đổi tài sản và nợ phải trả hoạt động (Trước năm 2016)',
            'cfs195':'Tăng (giảm) tài sản tài chính ghi nhận thông qua lãi/ lỗ (FVTPL)',
            'cfs196':'Tăng (giảm) các khoản đầu tư giữ đến ngày đáo hạn (HTM)',
            'cfs197':'Tăng(giảm) các khoản cho vay',
            'cfs198':'Tăng (giảm) tài sản tài chính sẵn sàng để bán AFS',
            'cfs199':'Tăng/giảm các tài sản khác',
            'cfs200':'Tăng/giảm các khoản phải thu (Trước năm 2016)',
            'cfs201':'Tăng/giảm vay và nợ thuê tài sản tài chính (Trước năm 2016)',
            'cfs202':'Tăng/giảm vay tài sản tài chính (Trước năm 2016)',
            'cfs203':'Tăng/giảm Trái phiếu chuyển đổi-Cấu phần nợ (Trước năm 2016)',
            'cfs204':'Tăng/giảm Trái phiếu phát hành (Trước năm 2016)',
            'cfs205':'Tăng/giảm vay Quỹ Hỗ trợ thanh toán (Trước năm 2016)',
            'cfs206':'(-) Tăng, (+) giảm phải thu bán các tài sản tài chính',
            'cfs207':'(-) Tăng, (+) giảm phải thu và dự thu cổ tức, tiền lãi các tài sản tài chính',
            'cfs208':'(-) Tăng, (+) giảm các khoản phải thu các dịch vụ CTCK cung cấp',
            'cfs209':'(-) Tăng, (+) giảm các khoản phải thu về lỗi giao dịch các TSTC',
            'cfs210':'(+) Tăng, (-) giảm phải trả cho người bán',
            'cfs211':'(+) Tăng, (-) giảm phải trả Tổ chức phát hành chứng khoán (Trước năm 2016)',
            'cfs212':'(+) Tăng, (-) giảm các khoản trích nộp phúc lợi nhân viên',
            'cfs213':'(+) Tăng, (-) giảm thuế và các khoản phải nộp Nhà nước',
            'cfs214':'(+) Tăng, (-) giảm phải trả người lao động',
            'cfs215':'(+) Tăng, (-) giảm phải trả về lỗi giao dịch các tài sản tài chính',
            'cfs216':'Tiền lãi đã thu',
            'cfs217':'Tiền thu khác',
            'cfs220':'Các khoản chi khác',
            'cfs223':'(-) Tăng, (+) giảm chi phí phải trả (không bao gồm chi phí lãi vay)',
            'cfs224':'Chi trả thanh toán giao dịch chứng khoán của khách hàng',
            'cfs225':'Chi trả cho hoạt động ủy thác đầu tư của khách hàng',
            'cfs141':'Tiền và các khoản tương đương tiền đầu kỳ của khách hàng',
            'cfs153':'Tiền và các khoản tương đương tiền cuối kỳ của khách hàng'
          }

        stock=["AGR", "APS", "ART", "BSI", "BVS", "CTS", "FSC", "HCM", "IVS",
        "MBS", "ORS", "PSI", "SHS", "SSI", "TVB", "TVS", "VDS", "VND",
        "VPS", "VIX", "WSS", "DNSE", "YSVN", "TCSC", "APG", "EVS", "VCI"]
        bank=["ACB", "BAB", "BID", "BVB", "CTG", "EIB", "HDB", "KLB", "LPB", "MBB",
        "MSB", "NAB", "NVB", "OCB", "PGB", "SGB", "SHB", "STB", "TPB", "VCB",
        "VAB", "VBB", "VIB", "VietA", "VPB", "SEAB", "SCB", "ABB"]
        
        rename_stock={
          'cfa10':'(-) Tăng, (+) giảm các khoản phải thu khác',
          'cfa11':'Tăng/giảm hàng tồn kho (Trước năm 2016)',
          'cfa12':'(+) Tăng, (-) giảm các khoản phải trả, phải nộp khác',
          'cfa13':'Tăng/giảm chi phí trả trước',
          'cfa14':'Tiền lãi vay đã trả',
          'cfa15':'Thuế TNDN CTCK đã nộp',
          'cfa16':'Tiền thu khác từ hoạt động kinh doanh',
          'cfa17':'Tiền chi khác cho hoạt động kinh doanh',
          'cfa18':'Lưu chuyển thuần từ hoạt động kinh doanh'
        }
        
        rename_elsestock={
          'cfa10':'Lợi nhuận/(lỗ) từ hoạt động kinh doanh trước những thay đổi vốn lưu động',
          'cfa11':'(Tăng)/giảm các khoản phải thu',
          'cfa12':'(Tăng)/giảm hàng tồn kho',
          'cfa13':'Tăng/(giảm) các khoản phải trả',
          'cfa14':'(Tăng)/giảm chứng khoán kinh doanh',
          'cfa16':'Thuế thu nhập doanh nghiệp đã nộp',
          'cfa17':'Tiền thu khác từ hoạt động kinh doanh',
          'cfa18':'Lưu chuyển tiền tệ ròng từ các hoạt động sản xuất kinh doanh'
        }

        rename_bank={
          'cfa15':'Thuế thu nhập doanh nghiệp đã trả'
        }

        rename_elsebank={
          'cfa15':'Tiền lãi vay đã trả'
        } 
        
        rename_dict = rename_common.copy()
        if self.symbol in stock:
          rename_dict.update(rename_stock)
        else:
          rename_dict.update(rename_elsestock)
          if self.symbol in bank:
              rename_dict.update(rename_bank)
          else:
              rename_dict.update(rename_elsebank)
        
        data = data.rename(columns=rename_dict)
        data = data[[col for col in data.columns if col in rename_dict.values() or col in ["Quý", "Năm"]]]

        if time == "quarters":
            num_cols = [c for c in data.columns if c != "Quý"]
            data[num_cols] = data[num_cols].apply(pd.to_numeric, errors="coerce").astype("Int64")

            df = data.set_index("Quý").T
            df.index.name = "Quý"
            df = df.reset_index()
            df.columns.name = None

            quarter_cols = [c for c in df.columns if c != "Quý"]
            quarter_sorted = sorted(
                quarter_cols,
                key=lambda x: (
                    int(str(x).split()[-1]),
                    int(str(x).replace("Q", "").split()[0])
                )
            )
            df = df[["Quý"] + quarter_sorted]

        else:
            num_cols = [c for c in data.columns if c != "Năm"]
            data[num_cols] = data[num_cols].apply(pd.to_numeric, errors="coerce").astype("Int64")

            df = data.set_index("Năm").T
            df.index.name = "Năm"
            df = df.reset_index()
            df.columns.name = None

            year_cols = [c for c in df.columns if c != "Năm"]
            year_cols = sorted(year_cols)
            df = df[["Năm"] + year_cols]

        df = df.fillna(0)
        return df
      except Exception as e:
        print(f"❌ Không có dữ liệu '{self.symbol}': {e}")
        return pd.DataFrame()

class StockShareHolder:
    def __init__(self, symbol):
        self.symbol = symbol

    # Thông tin cổ đông
    def shareholders_info(self):
      try:
        headers = {
          'content-type': 'application/json',
          'referer': 'https://trading.vietcap.com.vn/',
          'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36'
          }

        url1=f'https://iq.vietcap.com.vn/api/iq-insight-service/v1/company/{self.symbol.upper()}/shareholder'
        response=requests.get(url1,headers=headers)
        data1=response.json()['data']
        data1=pd.json_normalize(data1)
        data1=data1.drop(columns=['ownerNameEn','ownerCode','positionNameEn'])
        data1['percentage']=round(data1['percentage']*100,4)
        data1['updateDate']=pd.to_datetime(data1['updateDate'],format='mixed').dt.strftime('%Y-%m-%d')
        data1['ownerType']=data1['ownerType'].replace({'INDIVIDUAL':'Cá nhân','CORPORATE':'Doanh nghiệp'})
        data1['Mã CK']=self.symbol.upper()
        col = data1.pop('Mã CK')
        data1.insert(0, 'Mã CK', col)
        data1['positionName'] = data1['positionName'].fillna('-')
        data1=data1.rename(columns={
            'ownerName': 'Tên chủ sở hữu',
            'positionName' : 'Chức vụ',
            'quantity': 'Số lượng sở hữu',
            'percentage':'Phần trăm sở hữu (%)',
            'ownerType':'Loại sở hữu',
            'updateDate': 'Ngày cập nhật',
            'publicDate': 'Ngày công bố'
        })
        data1 = data1.sort_values("Ngày cập nhật", ascending=True).reset_index(drop=True)
        return data1
      except Exception as e:
        print(f"❌ Không có dữ liệu '{self.symbol}': {e}")
        return pd.DataFrame()

    #Cấu trúc cổ đông
    def shareholders_structure(self):
      try:
        headers = {
          'content-type': 'application/json',
          'referer': 'https://trading.vietcap.com.vn/',
          'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36'
          }

        url2=f'https://iq.vietcap.com.vn/api/iq-insight-service/v1/company/{self.symbol.upper()}/shareholder-structure'
        response=requests.get(url2,headers=headers)
        data2=response.json()['data']
        data2=pd.json_normalize(data2)
        percent_cols=['statePercentage','foreignPercentage','otherPercentage','bodPercentage','institutionPercentage']
        data2[percent_cols]=round(data2[percent_cols]*100,4)
        data2['totalShares']=data2['totalShares'].astype(int)
        data2['Mã CK']=self.symbol.upper()
        col = data2.pop('Mã CK')
        data2.insert(0, 'Mã CK', col)
        data2=data2[['Mã CK','totalShares',
                    'stateVolume', 'statePercentage',
                    'foreignerVolume', 'foreignPercentage',      
                    'otherVolume', 'otherPercentage',            
                    'bodPercentage',                             
                    'institutionPercentage'                     
                    ]]  
        data2.rename(columns={
            'totalShares': 'Số cổ phiếu đang lưu hành',
            'statePercentage': 'Tỷ lệ Nhà nước sở hữu (%)',
            'foreignPercentage': 'Tỷ lệ nước ngoài sở hữu (%)',
            'otherPercentage': 'Tỷ lệ nhóm cổ đông khác (%)',
            'foreignerVolume': 'Số lượng cổ phiếu nước ngoài nắm giữ',
            'otherVolume': 'Số lượng cổ phiếu nhóm cổ đông khác nắm giữ',
            'stateVolume': 'Số lượng cổ phiếu Nhà nước nắm giữ',
            'bodPercentage': 'Tỷ lệ Hội đồng Quản trị nắm giữ (%)',
            'institutionPercentage': 'Tỷ lệ các tổ chức đầu tư nắm giữ (%)'
        },inplace=True)
        pd.set_option('display.max_rows', None)
        return data2
      except Exception as e:
        print(f"❌ Không có dữ liệu '{self.symbol}': {e}")
        return pd.DataFrame()

    #Công ty liên quan
    def shareholders_relationship(self):
      try:
        headers = {
          'content-type': 'application/json',
          'referer': 'https://trading.vietcap.com.vn/',
          'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36'
          }

        url3=f'https://iq.vietcap.com.vn/api/iq-insight-service/v1/company/{self.symbol.upper()}/relationship'
        response=requests.get(url3,headers=headers)
        data3_1=response.json()['data']['affiliates']
        data3_1=pd.json_normalize(data3_1)
        data3_1['Loại cty']='Cty liên kết'
        data3_2=response.json()['data']['subsidiaries']
        data3_2=pd.json_normalize(data3_2)
        data3_2['Loại cty']='Cty con'
        data3=pd.concat([data3_1,data3_2],ignore_index=True)
        data3=data3.drop(columns=['rightOrganCode','rightTicker','rightOrganNameEn'])
        data3['ownedPercentage']=round(data3['ownedPercentage']*100,4)
        data3['ownedQuantity']=data3['ownedQuantity'].astype(int)
        data3['Mã CK']=self.symbol.upper()
        col = data3.pop('Mã CK')
        data3.insert(0, 'Mã CK', col)
        data3.rename(columns={
            'rightOrganNameVi': 'Tên Cty',
            'ownedQuantity': 'Số lượng cổ phiếu nắm giữ',
            'ownedPercentage': 'Tỷ lệ nắm giữ (%)'
        },inplace=True)
        pd.set_option('display.max_rows', None)  
        return data3[['Mã CK','Tên Cty','Loại cty', 'Số lượng cổ phiếu nắm giữ', 'Tỷ lệ nắm giữ (%)']]
      except Exception as e:
        print(f"❌ Không có dữ liệu '{self.symbol}': {e}")
        return pd.DataFrame()

    # Giao dịch nội bộ
    def insider_trans(self):
      try:
        headers={
          'content-type': 'application/json',
          'referer': 'https://trading.vietcap.com.vn/',
          'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36'
        }
        url=f'https://iq.vietcap.com.vn/api/iq-insight-service/v1/company/{self.symbol.upper()}/insider-transaction?page=0&size=1000'
        response=requests.get(url,headers=headers)
        data=pd.json_normalize(response.json()['data']['content'])
        data['Mã CK']=self.symbol.upper()
        col = data.pop('Mã CK')
        data.insert(0, 'Mã CK', col)
        data['traderNameVi']=data['traderNameVi'].fillna(data['traderOrganNameVi'])
        nacol=['traderPositionVi','relativeNameVi',	'roleNameVi']
        data[nacol]=data[nacol].fillna('-')
        for col in ['shareRegister', 'shareBeforeTrade', 'shareAcquire', 'shareAfterTrade']:
              data[col] = pd.to_numeric(data[col], errors='coerce').astype('Int64')

        data=data.drop(columns=[
          'id', 
          'organCode', 
          'eventNameEn', 
          'ticker', 
          'eventCode',
          'sourceUrlVi',
          'sourceUrlEn',
          'tradeStatusEn',
          'traderPersonId',
          'traderNameEn',
          'traderPositionEn',
          'actionTypeCode',
          'actionTypeEn',
          'relativeNameEn',
          'icbCodeLv1',
          'traderOrganNameEn',
          'displayDate1',
          'displayDate2',
          'roleNameEn',
          'traderOrganNameVi'
          ])
        data['eventNameVi']=data['eventNameVi'].replace(r'^Giao dịch nội bộ: ','',regex=True)
        ngay=['startDate','endDate','publicDate']
        for col in ngay:
            data[col]=pd.to_datetime(data[col],format='mixed').dt.strftime('%Y-%m-%d')
        data['ownershipAfterTrade']=data['ownershipAfterTrade']*100
        chucvu=self.shareholders_info()[['Tên chủ sở hữu','Chức vụ']]
        data=pd.merge(data,chucvu,left_on='relativeNameVi',right_on='Tên chủ sở hữu',how='left')
        data=data.drop(columns=['Tên chủ sở hữu'])
        mask = data['eventNameVi'] != 'Giao dịch người liên quan'
        data.loc[mask, ['relativeNameVi', 'Chức vụ', 'roleNameVi']] = '-'
        filted_cols=[
          'Mã CK',
          'eventNameVi',
          'traderNameVi',
          'traderPositionVi',
          'actionTypeVi',
          'tradeStatusVi',
          'shareRegister',
          'shareBeforeTrade',
          'shareAcquire',
          'shareAfterTrade',
          'ownershipAfterTrade',
          'startDate',
          'endDate',
          'publicDate',
          'relativeNameVi',
          'Chức vụ',
          'roleNameVi'
          ]
        df=data[filted_cols]
        df=df.rename(columns={ 
          'eventNameVi': 'Loại giao dịch',
          'traderNameVi': 'Người/Tổ chức giao dịch',
          'traderPositionVi': 'Chức vụ',
          'actionTypeVi': 'Phân loại mua/bán',
          'tradeStatusVi': 'Trạng thái',
          'shareRegister': 'Số lượng cp đăng ký',
          'shareBeforeTrade': 'Số lượng cp trước GD',
          'shareAcquire': 'Số lượng mua',
          'shareAfterTrade': 'Số lượng cp sau GD',
          'ownershipAfterTrade': 'Tỷ lệ sở hữu sau GD (%)',
          'startDate': 'Ngày bắt đầu',
          'endDate': 'Ngày kết thúc',
          'publicDate': 'Ngày công bố',
          'relativeNameVi': 'Người liên quan',
          'roleNameVi': 'Quan hệ',
          'Chức vụ': 'Chức vụ người liên quan'
        })

        df = df.sort_values(
            ["Ngày công bố", "Ngày bắt đầu", "Ngày kết thúc"],
            ascending=[True, True, True]
        ).reset_index(drop=True)
        return df
      except Exception as e:
        print(f"❌ Không có dữ liệu '{self.symbol}': {e}")
        return pd.DataFrame()

class StockEvent:
    def __init__(self, symbol):
        self.symbol = symbol

    def news(self):
        try:
            headers = {
                'content-type': 'application/json',
                'referer': 'https://trading.vietcap.com.vn/',
                'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36'
            }
            
            now=datetime.today().strftime('%Y%m%d')
            params = {
                'ticker': self.symbol.upper(),
                "fromDate": '19000101',
                "toDate": now,
                "size": 50000
            }
        
            # Lấy danh sách tin tức
            url = 'https://iq.vietcap.com.vn/api/iq-insight-service/v1/news'
            response = requests.get(url, headers=headers, params=params)
            data = json_normalize(response.json()['data']['content'])
            datax = data[['id', 'publicDate', 'newsTitle']]
        
        
            # Hàm lấy chi tiết tin
            def fetch_news_detail(news_id):
                try:
                    url = f'https://iq.vietcap.com.vn/api/iq-insight-service/v1/news/{news_id}'
                    response = requests.get(url, headers=headers)
                    detail = json_normalize(response.json()['data'])

                    html = detail.loc[0, 'newsFullContent']
                    source_link = detail.loc[0, 'newsSourceLink'] if 'newsSourceLink' in detail.columns else '-'

                    # Trích link file PDF từ HTML (nếu có)
                    if pd.notna(html):
                        soup = BeautifulSoup(html, 'html.parser')
                        link = soup.find('a', href=True)
                        file_url = link.get('href') if link else '-'
                    else:
                        file_url = '-'

                    return {
                        'id': news_id,
                        'newsFullContent': file_url,
                        'newsSourceLink': source_link
                    }

                except Exception as e:
                    return {'id': news_id, 'newsFullContent': '-', 'newsSourceLink': '-'}

            # Chạy đa luồng lấy chi tiết tin
            results = []
            with ThreadPoolExecutor(max_workers=100) as executor:
                futures = [executor.submit(fetch_news_detail, _id) for _id in data['id']]
                for future in as_completed(futures):
                    results.append(future.result())

            # Gộp kết quả
            tong = pd.DataFrame(results)
            datax = pd.merge(datax, tong, on='id', how='left')
            datax[['newsSourceLink', 'newsFullContent']] = datax[['newsSourceLink', 'newsFullContent']].fillna('-')
            cols=['publicDate','newsTitle','newsSourceLink','newsFullContent']
            datax=datax[cols]
            datax.insert(0, 'Mã CP', self.symbol.upper())
            datax['publicDate'] = pd.to_datetime(datax['publicDate'], format='mixed', errors='coerce')
            datax['publicDate'] = datax['publicDate'].dt.floor('s')
            datax = datax[~((datax['newsSourceLink'] == '-') & (datax['newsFullContent'] == '-'))]
            datax['newsTitle']=datax['newsTitle'].replace(r'^.*?:\s*','',regex=True)
            rename_dict = {
                'publicDate': 'Ngày công bố',
                'newsTitle': 'Tiêu đề tin',
                'newsSourceLink': 'Link nguồn',
                'newsFullContent': 'Tệp đính kèm'
            }
            datax=datax.rename(columns=rename_dict)
            datax = datax.sort_values("Ngày công bố", ascending=True).reset_index(drop=True)
            return datax
        
        except Exception as e :
                print(f"Lỗi: {e}")
                return pd.DataFrame()

    def dividend(self):
        try:
            headers = {
                'content-type': 'application/json',
                'referer': 'https://trading.vietcap.com.vn/',
                'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36'
            }

            now=datetime.today().strftime('%Y%m%d')
            params = {
                'ticker': self.symbol.upper(),
                "fromDate": '19000101',
                "toDate": now,
                "eventCode":["DIV","ISS"],
                "size": 50000
            }
            url = 'https://iq.vietcap.com.vn/api/iq-insight-service/v1/events'
            response = requests.get(url, headers=headers, params=params)
            data = json_normalize(response.json()['data']['content'])
            cols=['ticker','eventNameVi', 'eventTitleVi' ,'publicDate', 'exrightDate']
            date_cols=['publicDate', 'exrightDate']
            data=data[cols]
            for col in date_cols:
                data[col] = pd.to_datetime(data[col], errors='coerce').dt.floor('d')
            data['eventTitleVi']=data['eventTitleVi'].replace(r'^.*?-\s*','',regex=True)
            rename_dict = {
                'ticker': 'Mã CP',
                'eventNameVi': 'Sự kiện',
                'eventTitleVi': 'Chi tiết sự kiện',
                'publicDate': 'Ngày thông báo',
                'exrightDate': 'Ngày GD không hưởng quyền'
            }
            data=data.rename(columns=rename_dict)
            data = data.sort_values(
                ["Ngày thông báo", "Ngày GD không hưởng quyền"],
                ascending=[True, True]
            ).reset_index(drop=True)
            return data
        except Exception as e :
                print(f"Lỗi: {e}")
                return pd.DataFrame()

    def general_meeting(self):
        try:
            headers = {
                'content-type': 'application/json',
                'referer': 'https://trading.vietcap.com.vn/',
                'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36'
            }

            now=datetime.today().strftime('%Y%m%d')
            params = {
                'ticker': self.symbol.upper(),
                "fromDate": '19000101',
                "toDate": now,
                "eventCode":['AGME','AGMR','EGME'],
                "size": 50000
            }
            url = 'https://iq.vietcap.com.vn/api/iq-insight-service/v1/events'
            response = requests.get(url, headers=headers, params=params)
            data = json_normalize(response.json()['data']['content'])
            cols=['ticker','eventNameVi', 'eventTitleVi' ,'publicDate', 'exrightDate','issueDate']
            date_cols=['publicDate', 'exrightDate','issueDate']
            data=data[cols]
            for col in date_cols:
            # Loại phần sau 'T' (nếu có), sau đó ép kiểu datetime, rồi lấy .date
                data[col] = data[col].astype(str).str.split('T').str[0]          # chỉ lấy phần ngày
                data[col] = pd.to_datetime(data[col], errors='coerce')

            data['eventTitleVi']=data['eventTitleVi'].replace(r'^.*?-\s*','',regex=True)
            rename_dict = {
                'ticker': 'Mã CP',
                'eventNameVi': 'Sự kiện',
                'eventTitleVi': 'Chi tiết sự kiện',
                'publicDate': 'Ngày thông báo',
                'exrightDate': 'Ngày GD không hiệu quả',
                'issueDate' : 'Ngày thực hiện'
            }
            data=data.rename(columns=rename_dict)
            data = data.sort_values(
                ["Ngày thông báo", "Ngày thực hiện", "Ngày GD không hiệu quả"],
                ascending=[True, True, True]
            ).reset_index(drop=True)    
            return data
        except Exception as e :
                print(f"Lỗi: {e}")
                return pd.DataFrame()

    def other_event(self):
        try:
            headers = {
                'content-type': 'application/json',
                'referer': 'https://trading.vietcap.com.vn/',
                'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36'
            }

            now=datetime.today().strftime('%Y%m%d')
            params = {
                'ticker': self.symbol.upper(),
                "fromDate": '19000101',
                "toDate": now,
                "eventCode":['AIS','MA','MOVE','NLIS','OTHE','RETU','SUSPME'],
                "size": 50000
            }
            url = 'https://iq.vietcap.com.vn/api/iq-insight-service/v1/events'
            response = requests.get(url, headers=headers, params=params)
            data = json_normalize(response.json()['data']['content'])
            cols=['ticker','eventNameVi', 'eventTitleVi' ,'publicDate','issueDate']
            date_cols=['publicDate','issueDate']
            data=data[cols]
            for col in date_cols:
            # Loại phần sau 'T' (nếu có), sau đó ép kiểu datetime, rồi lấy .date
                data[col] = data[col].astype(str).str.split('T').str[0]          # chỉ lấy phần ngày
                data[col] = pd.to_datetime(data[col], errors='coerce')

            data['eventTitleVi']=data['eventTitleVi'].replace(r'^.*?-\s*','',regex=True)
            rename_dict = {
                'ticker': 'Mã CP',
                'eventNameVi': 'Sự kiện',
                'eventTitleVi': 'Chi tiết sự kiện',
                'publicDate': 'Ngày thông báo',
                'issueDate' : 'Ngày thực hiện'
            }
            data=data.rename(columns=rename_dict)
            data = data.sort_values(
                ["Ngày thông báo", "Ngày thực hiện"],
                ascending=[True, True]
            ).reset_index(drop=True)
            return data
        except Exception as e :
                print(f"Lỗi: {e}")
                return pd.DataFrame()    
 
class stock:
    def __init__(self,symbol):
        self.symbol=symbol.upper()
        self.market=StockMarket(self.symbol)
        self.financial=StockFinancial(self.symbol)
        self.shareholder=StockShareHolder(self.symbol)
        self.event=StockEvent(self.symbol)

    # ===== MARKET =====
    @classmethod
    def get_stock_info(cls, symbol, *args, **kwargs):
        return StockMarket(symbol).stock_info(*args, **kwargs)
    
    @classmethod
    def get_history(cls, symbol, *args, **kwargs):
        return StockMarket(symbol).history(*args, **kwargs)

    @classmethod
    def get_intraday(cls, symbol):
        return StockMarket(symbol).intraday()

    @classmethod
    def get_intraday_order(cls, symbol):
        return StockMarket(symbol).intraday_order()

    @classmethod
    def get_price_history(cls, symbol, *args, **kwargs):
        return StockMarket(symbol).price_history(*args, **kwargs)

    @classmethod
    def get_price_history_summary(cls, symbol, *args, **kwargs):
        return StockMarket(symbol).price_history_summary(*args, **kwargs)

    @classmethod
    def get_foreign_history(cls, symbol, *args, **kwargs):
        return StockMarket(symbol).foreign_history(*args, **kwargs)

    @classmethod
    def get_foreign_history_summary(cls, symbol, *args, **kwargs):
        return StockMarket(symbol).foreign_history_summary(*args, **kwargs)

    @classmethod
    def get_proprietary_history(cls, symbol, *args, **kwargs):
        return StockMarket(symbol).proprietary_history(*args, **kwargs)

    @classmethod
    def get_proprietary_history_summary(cls, symbol, *args, **kwargs):
        return StockMarket(symbol).proprietary_history_summary(*args, **kwargs)

    @classmethod
    def get_demand_history(cls, symbol, *args, **kwargs):
        return StockMarket(symbol).demand_history(*args, **kwargs)

    # ===== FINANCIAL =====
    @classmethod
    def get_finance_ratio(cls, symbol, *args, **kwargs):
        return StockFinancial(symbol).finance_ratio(*args, **kwargs)

    @classmethod
    def get_balance_sheet(cls, symbol, *args, **kwargs):
        return StockFinancial(symbol).balance_sheet(*args, **kwargs)

    @classmethod
    def get_income_statement(cls, symbol, *args, **kwargs):
        return StockFinancial(symbol).income_statement(*args, **kwargs)

    @classmethod
    def get_cash_flow(cls, symbol, *args, **kwargs):
        return StockFinancial(symbol).cash_flow(*args, **kwargs)

    # ===== SHAREHOLDER =====
    @classmethod
    def get_shareholders_info(cls, symbol):
        return StockShareHolder(symbol).shareholders_info()

    @classmethod
    def get_shareholders_structure(cls, symbol):
        return StockShareHolder(symbol).shareholders_structure()

    @classmethod
    def get_shareholders_relationship(cls, symbol):
        return StockShareHolder(symbol).shareholders_relationship()

    @classmethod
    def get_insider_trans(cls, symbol):
        return StockShareHolder(symbol).insider_trans()

    # ===== EVENT =====
    @classmethod
    def get_news(cls, symbol):
        return StockEvent(symbol).news()

    @classmethod
    def get_dividend(cls, symbol):
        return StockEvent(symbol).dividend()

    @classmethod
    def get_general_meeting(cls, symbol):
        return StockEvent(symbol).general_meeting()

    @classmethod
    def get_other_event(cls, symbol):
        return StockEvent(symbol).other_event()
   
class exchange:
    def __init__(self, exchange):
        self.exchange = exchange

    
    def top_stock(self, up_down):
        try:
            headers = {
                'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36'
            }

            payload = {
                "columns": [
                    "name",  # cổ phiếu
                    "sector", # ngành
                    "exchange", # sàn
                    "close",  #giá
                    "change", # thay đổi giá
                    "volume", # KLGD
                    "volume_change", #Thay đổi KLGD #ở đâu ra
                    "market_cap_basic", #vốn hóa
                    "price_earnings_ttm", #P/E raito
                    "earnings_per_share_diluted_ttm", #EPS 
                    "relative_volume_10d_calc", #KLTB 10 ngày
                    "dividends_yield_current", #Tỷ suất cổ tức
                    "total_revenue_ttm", #tổng doanh thu
                    "earnings_per_share_diluted_yoy_growth_ttm", # doanh thu tăng trưởng
                    "oper_income_ttm", # Lợi nhuận hoạt động(năm)
                    "net_income_ttm" #LNST
                    ],
                "ignore_unknown_fields": False,
                "markets": ["vietnam"],
                "options": {"lang": "en"},
                "range": [0, 1600],
                "sort": {"sortBy": "market_cap_basic","sortOrder": "desc"}

            }

            url = "https://scanner.tradingview.com/vietnam/scan"
            response = requests.post(url, headers=headers, data=json.dumps(payload))

            data = response.json()
            datax=pd.json_normalize(data['data'])
            datay=datax.drop(columns='s')
            df_data=pd.DataFrame(datay['d'].to_list())
            df_data.columns = ["Cổ phiếu", "Ngành", "Sàn", "Giá", "Thay đổi giá(%)", "Khối lượng", "Thay đổi Khối lượng(%)", "Vốn hóa", "PE Ratio", "EPS", "KLTB 10 ngày", "Tỷ suất cổ tức(%)",
            "Tổng doanh thu", "Tăng trưởng doanh thu(%)", "Lợi nhuận hoạt động (năm)", "LNST"]
            df_data=df_data.fillna(0)
            df_data['Giá'] = df_data['Giá'].apply(lambda x:x / 1000)
            cols_round=['Thay đổi giá(%)',"Thay đổi Khối lượng(%)","PE Ratio", "EPS","KLTB 10 ngày","Tỷ suất cổ tức(%)","Tăng trưởng doanh thu(%)"]
            df_data[cols_round] = df_data[cols_round].apply(lambda x:round(x,2))
            cols=['Khối lượng','Vốn hóa','Tổng doanh thu','Lợi nhuận hoạt động (năm)','LNST']
            df_data[cols]=df_data[cols].astype(int)
            industry_map = {"Finance": "Tài chính",
                            "Transportation": "Vận tải",
                            "Consumer Non-Durables": "Hàng tiêu dùng không bền",
                            "Non-Energy Minerals": "Khoáng sản phi năng lượng",
                            "Technology Services": "Công nghệ",
                            "Utilities": "Tiện ích công cộng",
                            "Process Industries": "Chế biến",
                            "Retail Trade": "Bán lẻ",
                            "Consumer Durables": "Hàng tiêu dùng bền",
                            "Energy Minerals": "Khoáng sản năng lượng",
                            "Producer Manufacturing": "Sản xuất công nghiệp",
                            "Distribution Services": "Phân phối",
                            "Electronic Technology": "Điện tử",
                            "Industrial Services": "Công nghiệp",
                            "Health Technology": "Công nghệ y tế",
                            "Commercial Services": "Thương mại",
                            "Health Services": "Y tế",
                            "Consumer Services": "Tiêu dùng",
                            "Communications": "Viễn thông",
                            "0": "Không xác định",
                            "Miscellaneous": "Khác"
                        }

            df_data["Ngành"] = df_data["Ngành"].replace(industry_map)
            ascending= up_down != 'up'
            return df_data[df_data['Sàn']==self.exchange].sort_values("Thay đổi giá(%)",ascending=ascending).iloc[:10]
        except Exception as e :
                print(f"Lỗi: {e}")
                return pd.DataFrame()

    @classmethod
    def get_top_stock(cls, exchange, up_down):
        return cls(exchange).top_stock(up_down)

class indice:
    def __init__(self, indice):
        self.indice = indice
    
    def overview_market(self, start, end):
        try:
            headers = {
                'authorization': 'Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6IkdYdExONzViZlZQakdvNERWdjV4QkRITHpnSSIsImtpZCI6IkdYdExONzViZlZQakdvNERWdjV4QkRITHpnSSJ9.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmZpcmVhbnQudm4iLCJhdWQiOiJodHRwczovL2FjY291bnRzLmZpcmVhbnQudm4vcmVzb3VyY2VzIiwiZXhwIjoyMDQyMTgwMDgzLCJuYmYiOjE3NDIxODAwODMsImNsaWVudF9pZCI6ImZpcmVhbnQudHJhZGVzdGF0aW9uIiwic2NvcGUiOlsib3BlbmlkIiwicHJvZmlsZSIsInJvbGVzIiwiZW1haWwiLCJhY2NvdW50cy1yZWFkIiwiYWNjb3VudHMtd3JpdGUiLCJvcmRlcnMtcmVhZCIsIm9yZGVycy13cml0ZSIsImNvbXBhbmllcy1yZWFkIiwiaW5kaXZpZHVhbHMtcmVhZCIsImZpbmFuY2UtcmVhZCIsInBvc3RzLXdyaXRlIiwicG9zdHMtcmVhZCIsInN5bWJvbHMtcmVhZCIsInVzZXItZGF0YS1yZWFkIiwidXNlci1kYXRhLXdyaXRlIiwidXNlcnMtcmVhZCIsInNlYXJjaCIsImFjYWRlbXktcmVhZCIsImFjYWRlbXktd3JpdGUiLCJibG9nLXJlYWQiLCJpbnZlc3RvcGVkaWEtcmVhZCJdLCJzdWIiOiI1YWMwOWFmZS00OWQ1LTRlZGQtYTkxOS1mMTc3ZmQ5MmJmZjkiLCJhdXRoX3RpbWUiOjE3NDIxODAwODMsImlkcCI6Ikdvb2dsZSIsIm5hbWUiOiJsdW9uZ2Jhb3F1YW4yNUBnbWFpbC5jb20iLCJzZWN1cml0eV9zdGFtcCI6IjFhNWVkNmRiLTgzNWQtNDcxMC05MzBjLWQ2MWRkMjU2YjgwZCIsImp0aSI6Ijc5ZTE3OTFiYWQ0OWM5YWRlMmUwYWRkMjlmOGVmZDViIiwiYW1yIjpbImV4dGVybmFsIl19.KqciuLmnUfgXD9hb1u3UA31n9imDpENW2ny3XBMF7IUOAoqpEWOVVOHbmdgX8anAS2mLPMP1opJeb66GlCfjWgElTcXXNB8L35TrvA_NnkrqC4xjV4KtJacRY9Y5R0q_Fq58tN0d-lKKgg8A9QZ7TyHkBlzQoHZePsVwlnQEe54hSfIeJeZazvEfJH1GKzcIEbCPOPbUTpJ7iauprgr5WnKQkRV3MseQW5O-KTI0s0BvRNofgNOXZo_j3k96agBgFhKD3YDXCokYTtpTGwQexQuwEogIaDFGIMqZ6zkkdPGYgDrTag9kJBuLInkHiV-siXVHQd_ZHlyaWsE72sV_gQ',
            }
            url = f"https://restv2.fireant.vn/symbols/{self.indice}/historical-quotes"
            params = {
                    "startDate": start,
                    "endDate": end,
                    "offset": 0,
                    "limit": 100
                }

            request = requests.get(url, headers=headers, params=params)
            data = request.json()
            data = pd.json_normalize(data)
            data = data[['date','symbol','priceClose','totalVolume','totalValue','buyForeignQuantity','sellForeignQuantity','buyForeignValue','sellForeignValue']]
            cols_ty=['buyForeignValue','sellForeignValue']
            data[cols_ty] = data[cols_ty].round(0) # làm tròn sô thập phân
            cols=[ 'totalVolume', 'totalValue', 'buyForeignQuantity','sellForeignQuantity','buyForeignValue','sellForeignValue']
            data[cols] = data[cols].apply(pd.to_numeric, errors='coerce').astype("Int64")
            data['date'] = pd.to_datetime(data['date']).dt.strftime('%Y-%m-%d')
            data.rename(columns={
                'date':'Ngày',
                'symbol':'Sàn',
                'priceClose':'Điểm',
                'totalVolume':'KL khớp',
                'dealVolume':'Deal Volume',
                'totalValue':'Tổng giá trị',
                'buyForeignQuantity':'KL Mua NN',
                'sellForeignQuantity':'KL Bán NN',
                'buyForeignValue':'GT Mua NN',
                'sellForeignValue':'GT Bán NN',
            }, inplace=True)
            data["GT Ròng NN"] = data["GT Mua NN"] - data["GT Bán NN"]
            data = data.sort_values("Ngày", ascending=True).reset_index(drop=True)
            return  data
        except Exception as e :
                print(f"Lỗi: {e}")
                return pd.DataFrame()
            
    @classmethod
    def get_overview_market(cls, indice, start, end):
        return cls(indice).overview_market(start, end)
    
class other:
    # def __init__(self,other):
    #      self.other=other

    @staticmethod
    def exchange_other():
        headers = {
            'content-type': 'application/json',
            'referer': 'https://trading.vietcap.com.vn/?filter-group=HOSE&filter-value=HOSE&view-type=FLAT&type=stock',
            'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36'
        }   

        US = ["^DJI", "^GSPC", "^IXIC", "^RUT", "^GDOW"]
        EU = ["^FTSE", "^STOXX", "^GDAXI", "^FCHI", "FTSEMIB.MI"]
        ASIA = ["^ADOW", "^N225", "^HSI", "000001.SS", "^STI"]
        goods = ["CL=F", "GC=F","SI=F", "HG=F", "ZR=F"]
        other = ["VND=X", "^TNX", "BTC-USD", "ETH-USD"]

        cols = US + EU + ASIA + goods + other

        payload = {
            "symbols": cols
        }

        url = "https://trading.vietcap.com.vn/api/price/globalPrice/getList"
        try: 
            session = requests.Session()
            response = session.post(url, headers=headers, data=json.dumps(payload))
            data = response.json()
            data = json_normalize(data)
            data = data[["id", "price", "change", "changePercent"]]
            data = data.rename(columns={
                "id": "Sàn",
                "price": "Điểm",
                "change": "Thay đổi",
                "changePercent": "Thay đổi (%)",
            })

            data["Sàn"] = data["Sàn"].replace({
                "^DJI": "DOWjones", "^GSPC": "S&P500", "^IXIC": "NASDAQ", "^RUT": "Russell", "^GDOW": "Dow Jones Global", 
                "^FTSE": "FTSE 100", "^STOXX": "STOXX 600", "^GDAXI": "DAX", "^FCHI": "CAC 40", "FTSEMIB.MI": "FTSE MIB",
                "^ADOW": "Asia ASX", "^N225": "NIKKEI 225", "^HSI": "Hang Seng", "000001.SS": "Shanghai", "^STI": "Singapore",
                'CL=F': "Dầu thô", "GC=F": "Vàng", "SI=F": "Bạc", "HG=F": "Đồng", "ZR=F": "Gạo",
                'VND=X': "VND/USD", "^TNX": "TP Mỹ 10 năm(%)", "BTC-USD": "Bitcoin", "ETH-USD": "Ethereum"})
            return data.sort_values("Thay đổi (%)",ascending=False).reset_index(drop=True)
        except Exception as e :
                print(f"Lỗi: {e}")
                return pd.DataFrame()

class fund:
    category={  
        '88':'MBAM','87':'BMFF','86':'KDEF','83':'RVPF24','82':'VCBFAIF','81':'ENF','80':'VDEF','79':'TCGF','78':'UVDIF','77':'MDI',
        '76':'LHCDF','75':'VCAMDF','72':'MAFEQI','71':'MAFBAL','70':'VCAMBF','69':'GFMVIF','40':'VNDCF','68':'VMPF','67':'VFMVFC','66':'PHVSF',
        '65':'ABBF','64':'LHBF','63':'VCAMFI','62':'HDBOND','61':'PBIF','58':'UVEEF','53':'VLBF','52':'TVPF','51':'ASBF','50':'MAFF',
        '49':'VLGF','47':'MBVF','48':'MBBOND','46':'VCBFMGF','45':'PVBF','41':'TBLF','37':'VNDBF','38':'VNDAF','35':'MAGEF','32':'VCBFBCF',
        '33':'VCBFFIF','31':'VCBFTBF','20':'VEOF','21':'VFF','22':'VIBF','23':'VESAF','27':'VFMVFB','25':'VFMVF4','28':'VFMVF1','12':'BVFED',
        '13':'BVBF','14':'BVPF','29':'DCAF','30':'DFIX','8':'SSIBF','11':'SSISCA'
        }
    
    headers={
        'content-type': 'application/json',
        'referer': 'https://fmarket.vn/',
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36'
        }
    
    def __init__(self,fund):
        self.fund=fund

    def _get_fund_id(self):
        if isinstance(self.fund, (int, float)):
            return int(self.fund)

        if isinstance(self.fund, str):
            fund_str = self.fund.strip()

            if fund_str.isdigit():
                return int(fund_str)

            fund_upper = fund_str.upper()
            matched = [k for k, v in self.category.items() if v == fund_upper]
            if matched:
                return int(matched[0])

        raise ValueError(f"Không tìm thấy quỹ: {self.fund}")

    def _get_fund_code(self):
        fund_id = str(self._get_fund_id())
        return self.category.get(fund_id, "")
    
    @staticmethod
    # Tổng quan danh sách các quỹ
    def fund_listing():
        try:
            payload={
                "types": [
                        "TRADING_FUND",
                        "NEW_FUND"
                    ],
            }
            url='https://api.fmarket.vn/res/products/filter'
            response=requests.post(url,headers=fund.headers,data=json.dumps(payload))
            data=pd.json_normalize(response.json()['data']['rows'])
            #data[['id','code']].to_csv(r'D:\DE\API\Fmarrket\category.csv',encoding='utf-8-sig')
            lower_col=['name','type','owner.name']
            for col in lower_col:
                data[col] = data[col].astype(str).str.title()
            data[['productNavChange.navTo12Months','productNavChange.annualizedReturn36Months']]=data[['productNavChange.navTo12Months','productNavChange.annualizedReturn36Months']].fillna(0)
            col_collect=['id','shortName','dataFundAssetType.name','name','type','nav','lastYearNav','productNavChange.navTo12Months','productNavChange.annualizedReturn36Months','owner.name','owner.shortName']
            data=data[col_collect]
            data=data.rename(columns={
                'id':'ID Quỹ',
                'shortName':'Chứng chỉ Quỹ',
                'name':'Tên Chứng chỉ Quỹ',
                'type':'Phân loại',
                'dataFundAssetType.name':'Loại quỹ',
                'nav':'Giá gần nhất',
                'lastYearNav':'Giá năm trước',
                'productNavChange.navTo12Months':'Lợi nhuận 1 năm gần nhất',
                'productNavChange.annualizedReturn36Months':'LN bình quân hàng năm',
                'owner.name':'Tổ chức phát hành',
                'owner.shortName':'Tên tổ chức'
            })
            data=data.sort_values('Lợi nhuận 1 năm gần nhất',ascending=False)
            return data
        except Exception as e:
            print(f"❌ Không có dữ liệu {e}")
            return pd.DataFrame()

    # Tăng trưởng tài sản ròng (NAV) của quỹ
    def nav_history(self,start=None,end=None):
        try:
            if start is not None:
                start_day = datetime.strptime(start, '%Y-%m-%d').strftime('%Y%m%d')
            else:
                start_day = '19700101'

            if end is not None:
                end_day = datetime.strptime(end, '%Y-%m-%d').strftime('%Y%m%d')
            else:
                end_day = datetime.today().strftime('%Y%m%d')

            payload={
                "fromDate":start_day,#"20240620",
                "productId": self._get_fund_id(),
                "toDate": end_day #"20250621"
            }

            url='https://api.fmarket.vn/res/product/get-nav-history'
            response=requests.post(url,headers=self.headers,data=json.dumps(payload))
            data=pd.json_normalize(response.json()['data'])

            if data.empty:
                print(f"❌ Không có dữ liệu '{self.fund}'. Vui lòng kiểm tra lại tên quỹ hoặc khoảng thời gian.")
                return pd.DataFrame()
            else:
                data = data[['productId','nav','navDate']].sort_values('navDate', ascending=True).reset_index(drop=True)

            data['productId']=data['productId'].astype(str).map(self.category)
            data=data.rename(columns={
                'productId':'Chứng chi Quỹ',
                'nav':'Giá trị tài sản ròng',
                'navDate':'Ngày'    
            })
            return data
        except Exception as e:
            print(f"❌ Không có dữ liệu '{self.fund}': {e}")
            return pd.DataFrame()

    # Phân bổ theo tài sản
    def asset_holding(self):
        try:
            url=f'https://api.fmarket.vn/res/products/{self._get_fund_id()}'
            response=requests.get(url,headers=self.headers)
            data=pd.json_normalize(response.json()['data']['productAssetHoldingList'])
            data['Chứng chỉ Quỹ']=self._get_fund_code()
            data=data.drop(columns=['id','updateAt','assetType.id','assetType.code','assetType.colorCode','createAt'])
            data=data[['Chứng chỉ Quỹ','assetType.name','assetPercent']]
            data=data.rename(columns={
                'assetType.name':'Loại tài sản nắm giữ',
                'assetPercent':'Tỉ trọng (%)'
            }).sort_values('Tỉ trọng (%)',ascending=False).reset_index(drop=True)
            return data
        except Exception as e:
            print(f"❌ Không có dữ liệu '{self.fund}': {e}")
            return pd.DataFrame()

    # Phân bổ theo ngành
    def industries_holding(self):
        try:
            url=f'https://api.fmarket.vn/res/products/{self._get_fund_id()}'
            response=requests.get(url,headers=self.headers)
            data=pd.json_normalize(response.json()['data']['productIndustriesHoldingList'])
            data['Chứng chỉ Quỹ']=self._get_fund_code()
            data=data.drop(columns=['id'])[['Chứng chỉ Quỹ','industry','assetPercent']]
            data=data.rename(columns={
                            'industry':'Ngành',
                            'assetPercent':'Tỉ trọng(%)'}).sort_values('Tỉ trọng(%)',ascending=False).reset_index(drop=True)
            return data
        except Exception as e:
            print(f"❌ Không có dữ liệu '{self.fund}': {e}")
            return pd.DataFrame()

    # Danh mục đầu tư lớn
    def top_holding(self):
        try:
            url=f'https://api.fmarket.vn/res/products/{self._get_fund_id()}'
            response=requests.get(url,headers=self.headers)
            data1=pd.json_normalize(response.json()['data']['productTopHoldingList'])
            data2=pd.json_normalize(response.json()['data']['productTopHoldingBondList'])
            dfs = []
            for df in [data1, data2]:
                if df is not None and not df.empty:
                    df = df.dropna(axis=1, how="all").dropna(axis=0, how="all")
                    if not df.empty:
                        dfs.append(df)

            data = pd.concat(dfs, ignore_index=True) if dfs else pd.DataFrame()
            data['Chứng chỉ Quỹ']=self._get_fund_code()
            data=data.drop(columns=['id','updateAt'])
            data=data[['Chứng chỉ Quỹ','type','stockCode','industry','netAssetPercent','price','changeFromPrevious','changeFromPreviousPercent']]
            data['type']=data['type'].replace({'STOCK':'Cổ phiếu'})
            data.loc[data['type'].str.contains('BOND', case=False, na=False), 'type'] = 'Trái phiếu'
            data=data.rename(columns={
                'stockCode':'Mã',
                'industry':'Ngành',
                'netAssetPercent':'Tỷ trọng trên tổng giá trị tài sản gộp (%)',
                'price':'Giá',
                'changeFromPrevious':'Thay đổi giá',
                'changeFromPreviousPercent':'% thay đổi giá',
                'type':'Loại đầu tư'
            })
            data=data.fillna(0).sort_values('Tỷ trọng trên tổng giá trị tài sản gộp (%)', ascending=False).reset_index(drop=True)
            has_stock = data['Loại đầu tư'].str.contains('Cổ phiếu', case=False, na=False).any()
            has_bond = data['Loại đầu tư'].str.contains('Trái phiếu', case=False, na=False).any()

            if has_stock:
                return data
            elif has_bond:
                data=data.drop(columns=['Giá','Thay đổi giá','% thay đổi giá'])
                return data
        except Exception as e:
            print(f"❌ Không có dữ liệu '{self.fund}': {e}")
            return pd.DataFrame()

    @classmethod
    def get_nav_history(cls, fund, start=None, end=None):
        return cls(fund).nav_history(start, end)

    @classmethod
    def get_asset_holding(cls, fund):
        return cls(fund).asset_holding()

    @classmethod
    def get_industries_holding(cls, fund):
        return cls(fund).industries_holding()

    @classmethod
    def get_top_holding(cls, fund):
        return cls(fund).top_holding()

class macro_economic:
    def __init__(self,indicator):
        self.indicator=indicator

    def general(self,time,start,end):
        try:  
            headers={
                'content-type': 'application/json',
                'referer': 'https://data.maybanktrade.com.vn/du-lieu-vi-mo',
                'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36'
            }

            indicator_list = {
                43: {"name": "GDP", "symbol": "GDP"},
                52: {"name": "CPI", "symbol": "CPI"},
                46: {"name": "Sản xuất công nghiệp", "symbol": "IIP"},
                47: {"name": "Bán lẻ", "symbol": "RET"},
                48: {"name": "Xuất nhập khẩu", "symbol": "TRADE"},
                50: {"name": "FDI", "symbol": "FDI"},
                51: {"name": "Tín dụng", "symbol": "CREDIT"},
                53: {"name": "Tỷ giá", "symbol": "FX"},
                55: {"name": "Dân số và lao động", "symbol": "LABOR"}
            }
            # Alias map (cho phép gõ thường, viết tắt hoặc tiếng Việt)
            alias_map = {}

            for k, v in indicator_list.items():
                # tên đầy đủ
                alias_map[v["name"].lower()] = k
                
                # symbol
                alias_map[v["symbol"].lower()] = k
                
                # uppercase
                alias_map[v["symbol"].upper()] = k

            def inputindicator():
                if isinstance(self.indicator, (int, float)):
                    return int(self.indicator)
                name = str(self.indicator).strip().lower()
                if name.isdigit():
                    return int(name)
                if name in alias_map:
                    return alias_map[name]
                raise ValueError(f"Không nhận diện được chỉ số: {self.indicator}")

            period={
                1:'days', #(type=1)
                2:'months', #(type=2)
                3:'quarters', #(tpye=3)
                4:'years'#(type=4)
            }

            def inputtime():
                if isinstance(time,(int,float)):
                    return time
                elif isinstance(time,str) and time.isdigit():
                    return int(time)
                elif isinstance(time,str) and time.isalpha():
                    id_time=[k for k,v in period.items() if v==time]
                    return int(id_time[0])


            if inputtime()==1:
                batdau=start
                ketthuc=end
                start='2025'
                end='2025'

            elif inputtime()==2:
                batdau=start.split('-')[1]
                ketthuc=end.split('-')[1]
                start=start.split('-')[0]
                end=end.split('-')[0]

            elif inputtime()==3:
                batdau=1
                ketthuc=4

            else:
                start=start.split('-')[0]
                end=end.split('-')[0]
                batdau=0
                ketthuc=0

            payload={
                "type": inputtime(),
                "fromYear": start,
                "toYear": end,
                "from": batdau, #(tháng hoặc quý) (ngày thì nhập đầy đủ)
                "to": ketthuc,   #(tháng hoặc quý) (ngày thì nhập đầy đủ)
                "normTypeID": inputindicator()
            }

            url='https://data.maybanktrade.com.vn/data/reportdatatopbynormtype'
            response=requests.post(url,headers=headers,data=json.dumps(payload))
            data=pd.json_normalize(response.json())

            #GDP #Sản xuất công nghiệp #bán lẻ năm #tín dụng năm #dân số lao động
            if (inputindicator() in [43,46,48,55]) or (inputindicator()in[47,51,53] and inputtime()==4):

                if inputindicator()==43:
                    data=data[~data['ReportTime'].str.contains('tháng',na=False)]

                if inputindicator()==48:
                    xuatkhaum=[358,359,360,361,362,364,365,366,367,462]
                    nhapkhaum=[368,369,370,371,372,373,374,375,376,463]
                    xuatkhauy=[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,414]
                    nhapkhauy=[113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,415]
                    data['GroupName']=data['NormID'].apply(lambda x:'Xuất khẩu' if x in (xuatkhauy+xuatkhaum) else 'Nhập khẩu')

                if inputindicator()==51:
                    data=data.loc[data['GroupName']!='So với GDP']
                    data['GroupName']=data['GroupName'].apply(lambda x:'Giá trị' if x=="" else x)
                    data=data.loc[(data['NormName']=='Cung tiền M2')|(data['NormName']=='Tín dụng')]


                if inputindicator()==55:
                    danso=[248,247,246,245]
                    laodong=[256,260,259,258,257,254,495,494,493,249] 
                    data['GroupName']=data['NormID'].apply(lambda x:'Lao động' if x in laodong else 'Dân số')

                data=data.drop(columns=['ReportDataID','TermID','TermYear','TernDay','NormID','CssStyle','NormTypeID','FromSource','NormGroupID'])
                data=data.rename(columns={'GroupName':'Nhóm chỉ tiêu',
                                        'NormName':'Chỉ tiêu',
                                        'UnitCode':'Đơn vị tính',
                                        'NormValue':'Giá trị',
                                        'ReportTime':'Thời gian báo cáo'}).fillna(0)
                data

            #CPI #FDI # bán lẻ tháng #Tín dụng tháng #tỉ giá lãi suất ngày
            if (inputindicator() in [52,50]) or (inputindicator() in [47,51] and inputtime()==2) or (inputindicator() in [53] and inputtime()==1) :
                if inputindicator()==50:
                    data=data.loc[(data['NormName']=='Giải ngân') | (data['NormName']=='Đăng ký')]

                if inputindicator()==53:
                    data=data.loc[data['NormValue'].notna()]

                data=data.drop(columns=['ReportDataID','TermID','TermYear','TernDay','NormID','CssStyle','NormTypeID','FromSource','NormGroupID','GroupName'])
                data=data.rename(columns={'NormName':'Chỉ tiêu',
                                          'UnitCode':'Đơn vị tính',
                                          'NormValue':'Giá trị',
                                          'ReportTime':'Thời gian báo cáo'}).fillna(0)

            if 'Nhóm chỉ tiêu' in data.columns:
                pivot_data=data.pivot(
                    index=['Nhóm chỉ tiêu','Chỉ tiêu','Đơn vị tính'],
                    columns='Thời gian báo cáo',
                    values='Giá trị'
                ).reset_index()
            else:
                pivot_data=data.pivot(
                index=['Chỉ tiêu','Đơn vị tính'],
                columns='Thời gian báo cáo',
                values='Giá trị'
                ).reset_index()
            pivot_data.columns.name = None
            return pivot_data
        except Exception as e:
            print(f"[{self.indicator}] ⚠️ Lỗi: {str(e)}")
            return pd.DataFrame()
        
    @classmethod
    def get_general(cls, indicator, time, start, end):
        return cls(indicator).general(time, start, end)
    
