You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

34 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

AmazingData 数据源适配器 - 完整文档

目录

  1. 适配器代码
  2. 接口详细说明
  3. 使用示例
  4. 数据结构说明

一、适配器代码

1. 主适配器代码 (amazing_data_adapter.py)

"""
AmazingData 数据源适配器
基于银河证券星耀数智量化平台 SDK 的封装
提供统一、简洁的金融数据获取接口
"""

import pandas as pd
from typing import List, Dict, Optional, Union, Tuple
from datetime import datetime, date
from dataclasses import dataclass
from enum import Enum
import logging

# 配置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)


class SecurityType(Enum):
    """证券类型枚举"""
    STOCK_A = "EXTRA_STOCK_A"  # 沪深A股
    STOCK_A_SH_SZ = "EXTRA_STOCK_A_SH_SZ"  # 沪深A股沪深
    INDEX_A = "EXTRA_INDEX_A"  # 沪深指数
    ETF = "EXTRA_ETF"  # ETF
    FUTURE = "EXTRA_FUTURE"  # 期货
    KZZ = "EXTRA_KZZ"  # 可转债
    GLRA = "EXTRA_GLRA"  # 逆回购
    HKT = "EXTRA_HKT"  # 港股通
    ETF_OP = "EXTRA_ETF_OP"  # ETF期权


class Market(Enum):
    """市场枚举"""
    SH = "SH"  # 上海
    SZ = "SZ"  # 深圳
    BJ = "BJ"  # 北京


class Period(Enum):
    """周期枚举"""
    MIN1 = "min1"
    MIN5 = "min5"
    MIN15 = "min15"
    MIN30 = "min30"
    MIN60 = "min60"
    DAILY = "daily"
    WEEKLY = "weekly"
    MONTHLY = "monthly"


@dataclass
class DataSourceConfig:
    """数据源配置"""
    username: str
    password: str
    host: str
    port: int
    local_path: str = "./amazing_data_cache/"
    use_local_cache: bool = True


class AmazingDataAdapter:
    """
    AmazingData 数据源适配器
    封装银河证券星耀数智 SDK提供统一的数据获取接口
    """
    
    def __init__(self, config: DataSourceConfig):
        self.config = config
        self._ad = None
        self._base_data = None
        self._market_data = None
        self._info_data = None
        self._calendar = None
        self._is_logged_in = False
        
    def connect(self) -> bool:
        """连接到数据源"""
        try:
            import AmazingData as ad
            self._ad = ad
            
            ad.login(
                username=self.config.username,
                password=self.config.password,
                host=self.config.host,
                port=self.config.port
            )
            
            self._base_data = ad.BaseData()
            self._info_data = ad.InfoData()
            self._calendar = self._base_data.get_calendar()
            self._market_data = ad.MarketData(self._calendar)
            
            self._is_logged_in = True
            logger.info("成功连接到 AmazingData 数据源")
            return True
            
        except Exception as e:
            logger.error(f"连接失败: {e}")
            return False
    
    def disconnect(self):
        """断开连接"""
        if self._is_logged_in and self._ad:
            try:
                self._ad.logout(self.config.username)
                logger.info("已断开与 AmazingData 的连接")
            except Exception as e:
                logger.warning(f"断开连接时出错: {e}")
        self._is_logged_in = False
    
    # ==================== 基础数据接口 ====================
    
    def get_code_list(self, security_type: SecurityType = SecurityType.STOCK_A) -> List[str]:
        """
        获取代码列表
        
        Args:
            security_type: 证券类型,可选 STOCK_A, ETF, FUTURE, KZZ, INDEX_A 等
            
        Returns:
            证券代码列表,如 ['000001.SZ', '600000.SH', ...]
        """
        self._check_login()
        
        if security_type == SecurityType.FUTURE:
            return self._base_data.get_future_code_list(security_type=security_type.value)
        elif security_type == SecurityType.ETF_OP:
            return self._base_data.get_option_code_list(security_type=security_type.value)
        else:
            return self._base_data.get_code_list(security_type=security_type.value)
    
    def get_code_info(self, security_type: SecurityType = SecurityType.STOCK_A) -> pd.DataFrame:
        """
        获取证券信息
        
        Returns:
            DataFrame 包含字段:
            - symbol: 证券简称
            - security_status: 产品状态标志
            - pre_close: 昨收价
            - high_limited: 涨停价
            - low_limited: 跌停价
            - price_tick: 最小价格变动单位
        """
        self._check_login()
        return self._base_data.get_code_info(security_type=security_type.value)
    
    def get_trading_calendar(self, market: Market = Market.SH) -> List[int]:
        """
        获取交易日历
        
        Returns:
            交易日列表,格式为 [20240102, 20240103, ...]
        """
        self._check_login()
        return self._base_data.get_calendar(market=market.value)
    
    def get_adj_factor(self, codes: List[str], is_local: Optional[bool] = None) -> pd.DataFrame:
        """
        获取单次复权因子
        
        Args:
            codes: 股票代码列表
            is_local: 是否使用本地缓存
            
        Returns:
            DataFrame (index: 日期, columns: 股票代码)
        """
        self._check_login()
        is_local = is_local if is_local is not None else self.config.use_local_cache
        return self._base_data.get_adj_factor(
            code_list=codes, local_path=self.config.local_path, is_local=is_local
        )
    
    def get_backward_factor(self, codes: List[str], is_local: Optional[bool] = None) -> pd.DataFrame:
        """
        获取后复权因子
        
        Returns:
            DataFrame (index: 日期, columns: 股票代码)
        """
        self._check_login()
        is_local = is_local if is_local is not None else self.config.use_local_cache
        return self._base_data.get_backward_factor(
            code_list=codes, local_path=self.config.local_path, is_local=is_local
        )
    
    # ==================== 历史行情数据接口 ====================
    
    def get_kline(self, codes: Union[str, List[str]],
                  start_date: Union[str, int, date],
                  end_date: Union[str, int, date],
                  period: Period = Period.DAILY) -> Dict[str, pd.DataFrame]:
        """
        获取历史K线数据
        
        Args:
            codes: 证券代码或列表,如 '000001.SZ' 或 ['000001.SZ', '600000.SH']
            start_date: 开始日期,支持 '20240101' 或 20240101 或 date对象
            end_date: 结束日期
            period: K线周期可选 MIN1/MIN5/MIN15/MIN30/MIN60/DAILY/WEEKLY/MONTHLY
            
        Returns:
            Dict[代码, DataFrame]DataFrame包含字段
            - open: 开盘价
            - high: 最高价
            - low: 最低价
            - close: 收盘价
            - volume: 成交量
            - amount: 成交金额
        """
        self._check_login()
        if isinstance(codes, str):
            codes = [codes]
        start_date = self._format_date(start_date)
        end_date = self._format_date(end_date)
        
        return self._market_data.query_kline(
            code_list=codes, begin_date=start_date, end_date=end_date,
            period=getattr(self._ad.constant.Period, period.value).value
        )
    
    def get_snapshot(self, codes: Union[str, List[str]],
                     start_date: Union[str, int, date],
                     end_date: Union[str, int, date]) -> Dict[str, pd.DataFrame]:
        """
        获取历史快照数据
        
        Returns:
            Dict[代码, DataFrame]包含Level-1行情快照
        """
        self._check_login()
        if isinstance(codes, str):
            codes = [codes]
        start_date = self._format_date(start_date)
        end_date = self._format_date(end_date)
        
        return self._market_data.query_snapshot(
            code_list=codes, begin_date=start_date, end_date=end_date
        )
    
    # ==================== 财务数据接口 ====================
    
    def get_balance_sheet(self, codes: List[str],
                         start_date: Optional[Union[str, int, date]] = None,
                         end_date: Optional[Union[str, int, date]] = None,
                         is_local: Optional[bool] = None) -> Dict[str, pd.DataFrame]:
        """
        获取资产负债表
        
        Args:
            codes: 股票代码列表
            start_date: 开始报告期 (如 20240930 表示2024年三季报)
            end_date: 结束报告期
            
        Returns:
            Dict[代码, DataFrame],主要字段包括:
            - TOTAL_ASSETS: 资产总计
            - TOTAL_CUR_ASSETS: 流动资产合计
            - TOTAL_NONCUR_ASSETS: 非流动资产合计
            - TOTAL_LIAB: 负债合计
            - TOTAL_CUR_LIAB: 流动负债合计
            - TOT_SHARE_EQUITY_INCL_MIN_INT: 股东权益合计
            - CURRENCY_CAP: 货币资金
            - NOTES_RECEIVABLE: 应收票据
            - ACCT_RECEIVABLE: 应收账款
            - INV: 存货
            - FIX_ASSETS: 固定资产
            - NOTES_PAYABLE: 应付票据
            - ACCT_PAYABLE: 应付账款
            - ST_BORROWING: 短期借款
            - LT_LOAN: 长期借款
        """
        return self._get_financial_data('get_balance_sheet', codes, start_date, end_date, is_local)
    
    def get_cash_flow(self, codes: List[str],
                     start_date: Optional[Union[str, int, date]] = None,
                     end_date: Optional[Union[str, int, date]] = None,
                     is_local: Optional[bool] = None) -> Dict[str, pd.DataFrame]:
        """
        获取现金流量表
        
        主要字段:
        - NET_CASH_FLOWS_OPERA_ACT: 经营活动现金流净额
        - NET_CASH_FLOWS_INV_ACT: 投资活动现金流净额
        - NET_CASH_FLOWS_FIN_ACT: 筹资活动现金流净额
        - NET_INCR_CASH_AND_CASH_EQU: 现金及现金等价物净增加额
        - CASH_RECP_SG_AND_RS: 销售商品提供劳务收到的现金
        - CASH_PAY_GOODS_SERVICES: 购买商品接受劳务支付的现金
        """
        return self._get_financial_data('get_cash_flow', codes, start_date, end_date, is_local)
    
    def get_income_statement(self, codes: List[str],
                            start_date: Optional[Union[str, int, date]] = None,
                            end_date: Optional[Union[str, int, date]] = None,
                            is_local: Optional[bool] = None) -> Dict[str, pd.DataFrame]:
        """
        获取利润表
        
        主要字段:
        - TOT_OPERA_REV: 营业总收入
        - OPERA_REV: 营业收入
        - TOT_OPERA_COST: 营业总成本
        - OPERA_PROFIT: 营业利润
        - TOTAL_PROFIT: 利润总额
        - NET_PRO_INCL_MIN_INT_INC: 净利润
        - BASIC_EPS: 基本每股收益
        - DILUTED_EPS: 稀释每股收益
        - RD_EXP: 研发费用
        - LESS_SELLING_EXP: 销售费用
        - LESS_ADMIN_EXP: 管理费用
        - LESS_FIN_EXP: 财务费用
        """
        return self._get_financial_data('get_income', codes, start_date, end_date, is_local)
    
    def get_profit_express(self, codes: List[str],
                          start_date: Optional[Union[str, int, date]] = None,
                          end_date: Optional[Union[str, int, date]] = None,
                          is_local: Optional[bool] = None) -> pd.DataFrame:
        """
        获取业绩快报
        
        主要字段:
        - TOTAL_ASSETS: 总资产
        - NET_PRO_EXCL_MIN_INT_INC: 净利润
        - TOT_OPERA_REV: 营业总收入
        - TOTAL_PROFIT: 利润总额
        - OPERA_PROFIT: 营业利润
        - EPS_BASIC: 基本每股收益
        - ROE_WEIGHTED: 净资产收益率-加权
        - YOY_GR_NET_PROFIT_PARENT: 同比增长率:归属母公司股东的净利润
        """
        self._check_login()
        is_local = is_local if is_local is not None else self.config.use_local_cache
        return self._info_data.get_profit_express(
            code_list=codes, local_path=self.config.local_path, is_local=is_local,
            begin_date=self._format_date(start_date) if start_date else None,
            end_date=self._format_date(end_date) if end_date else None
        )
    
    def get_profit_notice(self, codes: List[str],
                         start_date: Optional[Union[str, int, date]] = None,
                         end_date: Optional[Union[str, int, date]] = None,
                         is_local: Optional[bool] = None) -> pd.DataFrame:
        """
        获取业绩预告
        
        主要字段:
        - P_TYPECODE: 业绩预告类型代码
        - P_CHANGE_MAX: 预告净利润变动幅度上限
        - P_CHANGE_MIN: 预告净利润变动幅度下限
        - NET_PROFIT_MAX: 预告净利润上限(万元)
        - NET_PROFIT_MIN: 预告净利润下限(万元)
        - P_REASON: 业绩变动原因
        """
        self._check_login()
        is_local = is_local if is_local is not None else self.config.use_local_cache
        return self._info_data.get_profit_notice(
            code_list=codes, local_path=self.config.local_path, is_local=is_local,
            begin_date=self._format_date(start_date) if start_date else None,
            end_date=self._format_date(end_date) if end_date else None
        )
    
    # ==================== 股东股本数据接口 ====================
    
    def get_top10_shareholders(self, codes: List[str],
                              start_date: Optional[Union[str, int, date]] = None,
                              end_date: Optional[Union[str, int, date]] = None,
                              is_local: Optional[bool] = None) -> pd.DataFrame:
        """
        获取十大股东数据
        
        主要字段:
        - HOLDER_NAME: 股东名称
        - HOLDER_QUANTITY: 持股数
        - HOLDER_PCT: 持股比例(%)
        - HOLDER_HOLDER_CATEGORY: 股东性质(1:个人, 2:公司)
        - FLOAT_QTY: 流通股数量
        """
        self._check_login()
        is_local = is_local if is_local is not None else self.config.use_local_cache
        return self._info_data.get_share_holder(
            code_list=codes, local_path=self.config.local_path, is_local=is_local,
            begin_date=self._format_date(start_date) if start_date else None,
            end_date=self._format_date(end_date) if end_date else None
        )
    
    def get_shareholder_count(self, codes: List[str],
                             start_date: Optional[Union[str, int, date]] = None,
                             end_date: Optional[Union[str, int, date]] = None,
                             is_local: Optional[bool] = None) -> pd.DataFrame:
        """
        获取股东户数数据
        
        主要字段:
        - HOLDER_TOTAL_NUM: A股、B股、H股、境外股的总户数
        - HOLDER_NUM: A股股东户数
        """
        self._check_login()
        is_local = is_local if is_local is not None else self.config.use_local_cache
        return self._info_data.get_holder_num(
            code_list=codes, local_path=self.config.local_path, is_local=is_local,
            begin_date=self._format_date(start_date) if start_date else None,
            end_date=self._format_date(end_date) if end_date else None
        )
    
    def get_equity_structure(self, codes: List[str],
                            start_date: Optional[Union[str, int, date]] = None,
                            end_date: Optional[Union[str, int, date]] = None,
                            is_local: Optional[bool] = None) -> pd.DataFrame:
        """
        获取股本结构数据
        
        主要字段:
        - TOT_SHARE: 总股本(万股)
        - FLOAT_SHARE: 流通股(万股)
        - FLOAT_A_SHARE: 流通A股(万股)
        - RESTRICTED_A_SHARE: 限售A股(万股)
        - TOT_RESTRICTED_SHARE: 限售股合计
        """
        self._check_login()
        is_local = is_local if is_local is not None else self.config.use_local_cache
        return self._info_data.get_equity_structure(
            code_list=codes, local_path=self.config.local_path, is_local=is_local,
            begin_date=self._format_date(start_date) if start_date else None,
            end_date=self._format_date(end_date) if end_date else None
        )
    
    # ==================== 融资融券数据接口 ====================
    
    def get_margin_summary(self,
                          start_date: Optional[Union[str, int, date]] = None,
                          end_date: Optional[Union[str, int, date]] = None,
                          is_local: Optional[bool] = None) -> pd.DataFrame:
        """
        获取融资融券成交汇总
        
        主要字段:
        - TRADE_DATE: 交易日期
        - SUM_BORROW_MONEY_BALANCE: 融资余额(元)
        - SUM_PURCH_WITH_BORROW_MONEY: 融资买入额(元)
        - SUM_REPAYMENT_OF_BORROW_MONEY: 融资偿还额(元)
        - SUM_SEC_LENDING_BALANCE: 融券余额(元)
        - SUM_SALES_OF_BORROWED_SEC: 融券卖出量
        - SUM_MARGIN_TRADE_BALANCE: 融资融券余额(元)
        """
        self._check_login()
        is_local = is_local if is_local is not None else self.config.use_local_cache
        return self._info_data.get_margin_summary(
            local_path=self.config.local_path, is_local=is_local,
            begin_date=self._format_date(start_date) if start_date else None,
            end_date=self._format_date(end_date) if end_date else None
        )
    
    def get_margin_detail(self, codes: List[str],
                         start_date: Optional[Union[str, int, date]] = None,
                         end_date: Optional[Union[str, int, date]] = None,
                         is_local: Optional[bool] = None) -> Dict[str, pd.DataFrame]:
        """
        获取融资融券交易明细
        
        主要字段:
        - BORROW_MONEY_BALANCE: 融资余额
        - PURCH_WITH_BORROW_MONEY: 融资买入额
        - REPAYMENT_OF_BORROW_MONEY: 融资偿还额
        - SEC_LENDING_BALANCE: 融券余额
        - SALES_OF_BORROWED_SEC: 融券卖出量
        """
        self._check_login()
        is_local = is_local if is_local is not None else self.config.use_local_cache
        return self._info_data.get_margin_detail(
            code_list=codes, local_path=self.config.local_path, is_local=is_local,
            begin_date=self._format_date(start_date) if start_date else None,
            end_date=self._format_date(end_date) if end_date else None
        )
    
    # ==================== 交易异动数据接口 ====================
    
    def get_longhu_bang(self, codes: List[str],
                       start_date: Optional[Union[str, int, date]] = None,
                       end_date: Optional[Union[str, int, date]] = None,
                       is_local: Optional[bool] = None) -> pd.DataFrame:
        """
        获取龙虎榜数据
        
        主要字段:
        - TRADE_DATE: 交易日期
        - REASON_TYPE_NAME: 上榜原因
        - CHANGE_RANGE: 涨跌幅(%)
        - TRADER_NAME: 营业部名称
        - BUY_AMOUNT: 买入金额(元)
        - SELL_AMOUNT: 卖出金额(元)
        - FLOW_MARK: 买卖表示(1买入, 2卖出)
        """
        self._check_login()
        is_local = is_local if is_local is not None else self.config.use_local_cache
        return self._info_data.get_long_hu_bang(
            code_list=codes, local_path=self.config.local_path, is_local=is_local,
            begin_date=self._format_date(start_date) if start_date else None,
            end_date=self._format_date(end_date) if end_date else None
        )
    
    def get_block_trading(self, codes: List[str],
                         start_date: Optional[Union[str, int, date]] = None,
                         end_date: Optional[Union[str, int, date]] = None,
                         is_local: Optional[bool] = None) -> pd.DataFrame:
        """
        获取大宗交易数据
        
        主要字段:
        - TRADE_DATE: 交易日期
        - B_SHARE_PRICE: 成交价(元)
        - B_SHARE_VOLUME: 成交量(万股)
        - B_SHARE_AMOUNT: 成交金额(万元)
        - B_BUYER_NAME: 买方营业部名称
        - B_SELLER_NAME: 卖方营业部名称
        """
        self._check_login()
        is_local = is_local if is_local is not None else self.config.use_local_cache
        return self._info_data.get_block_trading(
            code_list=codes, local_path=self.config.local_path, is_local=is_local,
            begin_date=self._format_date(start_date) if start_date else None,
            end_date=self._format_date(end_date) if end_date else None
        )
    
    # ==================== 指数数据接口 ====================
    
    def get_index_constituents(self, codes: List[str],
                              is_local: Optional[bool] = None) -> Dict[str, pd.DataFrame]:
        """
        获取指数成分股
        
        Args:
            codes: 指数代码列表,如 ['000300.SH', '000905.SH']
            
        Returns:
            Dict[指数代码, DataFrame]
            
        DataFrame字段
        - INDEX_CODE: 指数代码
        - CON_CODE: 成分股代码
        - INDATE: 纳入日期
        - OUTDATE: 剔除日期
        - INDEX_NAME: 指数名称
        """
        self._check_login()
        is_local = is_local if is_local is not None else self.config.use_local_cache
        return self._info_data.get_index_constituent(
            code_list=codes, local_path=self.config.local_path, is_local=is_local
        )
    
    def get_index_weights(self, codes: List[str],
                         start_date: Optional[Union[str, int, date]] = None,
                         end_date: Optional[Union[str, int, date]] = None,
                         is_local: Optional[bool] = None) -> Dict[str, pd.DataFrame]:
        """
        获取指数成分股权重
        
        支持指数:
        - 000016.SH: 上证50
        - 000300.SH: 沪深300
        - 000905.SH: 中证500
        - 000906.SH: 中证800
        - 000852.SH: 中证1000
        
        DataFrame字段
        - INDEX_CODE: 指数代码
        - CON_CODE: 标的代码
        - TRADE_DATE: 生效日期
        - WEIGHT: 权重(%)
        - CLOSE: 收盘价
        """
        self._check_login()
        is_local = is_local if is_local is not None else self.config.use_local_cache
        return self._info_data.get_index_weight(
            code_list=codes, local_path=self.config.local_path, is_local=is_local,
            begin_date=self._format_date(start_date) if start_date else None,
            end_date=self._format_date(end_date) if end_date else None
        )
    
    # ==================== ETF数据接口 ====================
    
    def get_etf_pcf(self, codes: List[str]) -> Tuple[pd.DataFrame, Dict[str, pd.DataFrame]]:
        """
        获取ETF申赎数据
        
        Returns:
            (etf_info, etf_constituents)
            
        etf_info字段
        - creation_redemption_unit: 每个篮子对应的ETF份数
        - max_cash_ratio: 最大现金替代比例
        - creation: 是否允许申购
        - redemption: 是否允许赎回
        
        etf_constituents字段
        - underlying_symbol: 成份证券简称
        - component_share: 成份证券数量
        - substitute_flag: 现金替代标志
        """
        self._check_login()
        return self._base_data.get_etf_pcf(code_list=codes)
    
    def get_fund_share(self, codes: List[str],
                      start_date: Optional[Union[str, int, date]] = None,
                      end_date: Optional[Union[str, int, date]] = None,
                      is_local: Optional[bool] = None) -> Dict[str, pd.DataFrame]:
        """
        获取基金份额数据
        
        主要字段:
        - FUND_SHARE: 基金份额(万份)
        - TOTAL_SHARE: 基金总份额(万份)
        - FLOAT_SHARE: 流通份额(万份)
        - CHANGE_REASON: 份额变动原因
        """
        self._check_login()
        is_local = is_local if is_local is not None else self.config.use_local_cache
        return self._info_data.get_fund_share(
            code_list=codes, local_path=self.config.local_path, is_local=is_local,
            begin_date=self._format_date(start_date) if start_date else None,
            end_date=self._format_date(end_date) if end_date else None
        )
    
    # ==================== 可转债数据接口 ====================
    
    def get_kzz_issuance(self, codes: List[str],
                        is_local: Optional[bool] = None) -> Dict[str, pd.DataFrame]:
        """
        获取可转债发行数据
        
        主要字段:
        - STOCK_CODE: 正股代码
        - LISTED_DATE: 上市日期
        - PLAN_SCHEDULE: 方案进度
        - CLAUSE_INI_CONV_PRICE: 初始转换价格
        - LIST_ISSUE_SIZE: 发行规模(万元)
        - LIST_ISSUE_QUANTITY: 发行数量(万张)
        - TERM_YEAR: 借款期限(年)
        - COUPON_RATE: 利率(%)
        """
        self._check_login()
        is_local = is_local if is_local is not None else self.config.use_local_cache
        return self._info_data.get_kzz_issuance(
            code_list=codes, local_path=self.config.local_path, is_local=is_local
        )
    
    # ==================== 辅助方法 ====================
    
    def _check_login(self):
        if not self._is_logged_in:
            raise RuntimeError("未连接到数据源,请先调用 connect()")
    
    def _format_date(self, d: Union[str, int, date]) -> int:
        if isinstance(d, int):
            return d
        elif isinstance(d, str):
            return int(d.replace("-", "").replace("/", ""))
        elif isinstance(d, date):
            return int(d.strftime("%Y%m%d"))
        else:
            raise ValueError(f"不支持的日期格式: {d}")
    
    def _get_financial_data(self, method: str, codes: List[str],
                           start_date: Optional[Union[str, int, date]] = None,
                           end_date: Optional[Union[str, int, date]] = None,
                           is_local: Optional[bool] = None) -> Dict[str, pd.DataFrame]:
        self._check_login()
        is_local = is_local if is_local is not None else self.config.use_local_cache
        method = getattr(self._info_data, method)
        return method(
            code_list=codes, local_path=self.config.local_path, is_local=is_local,
            begin_date=self._format_date(start_date) if start_date else None,
            end_date=self._format_date(end_date) if end_date else None
        )


def create_adapter(username: str, password: str, host: str, port: int,
                   local_path: str = "./amazing_data_cache/",
                   use_local_cache: bool = True) -> AmazingDataAdapter:
    """快速创建适配器实例"""
    config = DataSourceConfig(
        username=username, password=password, host=host, port=port,
        local_path=local_path, use_local_cache=use_local_cache
    )
    return AmazingDataAdapter(config)

二、接口详细说明

1. 基础数据接口

接口名 功能 返回类型 主要字段
get_code_list 获取代码列表 List[str] 代码列表
get_code_info 获取证券信息 DataFrame symbol, pre_close, high_limited, low_limited
get_trading_calendar 获取交易日历 List[int] 交易日列表
get_adj_factor 单次复权因子 DataFrame index=日期, columns=代码
get_backward_factor 后复权因子 DataFrame index=日期, columns=代码

2. 历史行情接口

接口名 功能 返回类型 主要字段
get_kline K线数据 Dict[str, DataFrame] open, high, low, close, volume, amount
get_snapshot 历史快照 Dict[str, DataFrame] Level-1行情数据

Period 周期选项:

  • Period.MIN1 / Period.MIN5 / Period.MIN15 / Period.MIN30 / Period.MIN60
  • Period.DAILY / Period.WEEKLY / Period.MONTHLY

3. 财务数据接口

接口名 功能 返回类型 主要字段
get_balance_sheet 资产负债表 Dict[str, DataFrame] TOTAL_ASSETS, TOTAL_LIAB, TOT_SHARE_EQUITY
get_cash_flow 现金流量表 Dict[str, DataFrame] NET_CASH_FLOWS_OPERA_ACT, NET_CASH_FLOWS_INV_ACT
get_income_statement 利润表 Dict[str, DataFrame] TOT_OPERA_REV, NET_PRO_INCL_MIN_INT_INC, BASIC_EPS
get_profit_express 业绩快报 DataFrame ROE_WEIGHTED, YOY_GR_NET_PROFIT_PARENT
get_profit_notice 业绩预告 DataFrame P_CHANGE_MAX, P_CHANGE_MIN, NET_PROFIT_MAX

4. 股东股本接口

接口名 功能 返回类型 主要字段
get_top10_shareholders 十大股东 DataFrame HOLDER_NAME, HOLDER_QUANTITY, HOLDER_PCT
get_shareholder_count 股东户数 DataFrame HOLDER_TOTAL_NUM, HOLDER_NUM
get_equity_structure 股本结构 DataFrame TOT_SHARE, FLOAT_SHARE, RESTRICTED_A_SHARE

5. 融资融券接口

接口名 功能 返回类型 主要字段
get_margin_summary 融资融券汇总 DataFrame SUM_BORROW_MONEY_BALANCE, SUM_MARGIN_TRADE_BALANCE
get_margin_detail 个股融资融券 Dict[str, DataFrame] BORROW_MONEY_BALANCE, SEC_LENDING_BALANCE

6. 交易异动接口

接口名 功能 返回类型 主要字段
get_longhu_bang 龙虎榜 DataFrame TRADER_NAME, BUY_AMOUNT, SELL_AMOUNT, FLOW_MARK
get_block_trading 大宗交易 DataFrame B_SHARE_PRICE, B_SHARE_VOLUME, B_BUYER_NAME

7. 指数数据接口

接口名 功能 返回类型 主要字段
get_index_constituents 指数成分股 Dict[str, DataFrame] INDEX_CODE, CON_CODE, INDATE, OUTDATE
get_index_weights 成分股权重 Dict[str, DataFrame] INDEX_CODE, CON_CODE, WEIGHT

支持的指数代码:

  • 000016.SH - 上证50
  • 000300.SH - 沪深300
  • 000905.SH - 中证500
  • 000906.SH - 中证800
  • 000852.SH - 中证1000

8. ETF数据接口

接口名 功能 返回类型 主要字段
get_etf_pcf ETF申赎数据 Tuple[DataFrame, Dict] creation_redemption_unit, component_share
get_fund_share 基金份额 Dict[str, DataFrame] FUND_SHARE, TOTAL_SHARE

9. 可转债数据接口

接口名 功能 返回类型 主要字段
get_kzz_issuance 可转债发行 Dict[str, DataFrame] CLAUSE_INI_CONV_PRICE, LIST_ISSUE_SIZE, COUPON_RATE

三、使用示例

基础使用

from amazing_data_adapter import create_adapter, SecurityType, Period

# 创建并连接
adapter = create_adapter(
    username='your_username',
    password='your_password',
    host='your_host',
    port=8080
)

if adapter.connect():
    # 获取A股列表
    codes = adapter.get_code_list(SecurityType.STOCK_A)
    print(f"A股数量: {len(codes)}")
    
    # 获取平安银行K线
    kline = adapter.get_kline(
        codes=['000001.SZ'],
        start_date='20240101',
        end_date='20241231',
        period=Period.DAILY
    )
    print(kline['000001.SZ'].head())
    
    adapter.disconnect()

获取财务数据

# 获取资产负债表
balance = adapter.get_balance_sheet(
    codes=['000001.SZ', '600000.SH'],
    start_date=20240930,
    end_date=20240930
)

for code, df in balance.items():
    print(f"{code} 总资产: {df['TOTAL_ASSETS'].values[0]}")

获取指数成分股

# 沪深300成分股
constituents = adapter.get_index_constituents(['000300.SH'])
df = constituents['000300.SH']
print(f"成分股数量: {len(df)}")
print(df[['CON_CODE', 'INDATE']].head())

批量处理

# 分批获取数据避免超时
all_codes = adapter.get_code_list(SecurityType.STOCK_A)
batch_size = 50

for i in range(0, 100, batch_size):  # 只取前100只演示
    batch = all_codes[i:i+batch_size]
    data = adapter.get_balance_sheet(batch)
    print(f"已处理 {i+len(batch)} 只股票")

四、数据结构说明

K线数据字段

字段名 类型 说明
open float 开盘价
high float 最高价
low float 最低价
close float 收盘价
volume int 成交量(股)
amount float 成交金额(元)

资产负债表关键字段

字段名 说明
TOTAL_ASSETS 资产总计
TOTAL_CUR_ASSETS 流动资产合计
TOTAL_NONCUR_ASSETS 非流动资产合计
TOTAL_LIAB 负债合计
TOT_SHARE_EQUITY_INCL_MIN_INT 股东权益合计(含少数股东)
CURRENCY_CAP 货币资金
NOTES_RECEIVABLE 应收票据
ACCT_RECEIVABLE 应收账款
INV 存货

利润表关键字段

字段名 说明
TOT_OPERA_REV 营业总收入
OPERA_PROFIT 营业利润
TOTAL_PROFIT 利润总额
NET_PRO_INCL_MIN_INT_INC 净利润(含少数股东)
BASIC_EPS 基本每股收益
DILUTED_EPS 稀释每股收益

现金流量表关键字段

字段名 说明
NET_CASH_FLOWS_OPERA_ACT 经营活动现金流净额
NET_CASH_FLOWS_INV_ACT 投资活动现金流净额
NET_CASH_FLOWS_FIN_ACT 筹资活动现金流净额
NET_INCR_CASH_AND_CASH_EQU 现金及现金等价物净增加额

五、注意事项

  1. 连接管理: 使用前先调用 connect(),使用后调用 disconnect()
  2. 日期格式: 支持 20240101"2024-01-01"date 对象
  3. 本地缓存: 默认启用,可设置 is_local=False 强制从服务器获取
  4. 批量处理: 大量数据建议分批获取,每批 50-100 个代码
  5. 错误处理: 连接断开会抛出 RuntimeError,需做好异常处理

文件保存位置: /root/.openclaw/workspace/amazing_data_adapter.py