"""CSI 300 (HS300) universe helpers.""" import logging import baostock as bs import pandas as pd logger = logging.getLogger(__name__) # First 30 HS300 constituents (large caps) in 'shXXXXXX' / 'szXXXXXX' format. # Hardcoded for fast, deterministic smoke tests. Use get_hs300_stocks() for the # live, full list — downloading daily bars for all ~300 takes roughly 10 minutes. SYMBOLS = [ "sh600000", "sh600009", "sh600010", "sh600028", "sh600030", "sh600036", "sh600048", "sh600050", "sh600104", "sh600276", "sh600309", "sh600519", "sh600585", "sh600887", "sh600900", "sh601012", "sh601166", "sh601288", "sh601318", "sh601398", "sh601628", "sh601668", "sh601857", "sh601888", "sh601988", "sz000001", "sz000002", "sz000333", "sz000651", "sz000858", ] def get_hs300_stocks() -> pd.DataFrame: """Fetch the current CSI 300 constituents from baostock. Returns: DataFrame with columns ``code`` (e.g. ``sh600000``), ``name``, ``date``. """ bs.login() try: rs = bs.query_hs300_stocks() stocks = [] while rs.next(): stocks.append(rs.get_row_data()) finally: bs.logout() df = pd.DataFrame(stocks, columns=["code", "name", "date"]) df["code"] = df["code"].str.replace(".", "", regex=False) return df