|
|
|
@ -0,0 +1,922 @@
|
|
|
|
|
|
|
|
# AmazingData 数据源适配器 - 完整文档
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## 目录
|
|
|
|
|
|
|
|
1. [适配器代码](#一适配器代码)
|
|
|
|
|
|
|
|
2. [接口详细说明](#二接口详细说明)
|
|
|
|
|
|
|
|
3. [使用示例](#三使用示例)
|
|
|
|
|
|
|
|
4. [数据结构说明](#四数据结构说明)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## 一、适配器代码
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### 1. 主适配器代码 (amazing_data_adapter.py)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
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 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## 三、使用示例
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### 基础使用
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
|
|
|
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()
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### 获取财务数据
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
|
|
|
# 获取资产负债表
|
|
|
|
|
|
|
|
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]}")
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### 获取指数成分股
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
|
|
|
# 沪深300成分股
|
|
|
|
|
|
|
|
constituents = adapter.get_index_constituents(['000300.SH'])
|
|
|
|
|
|
|
|
df = constituents['000300.SH']
|
|
|
|
|
|
|
|
print(f"成分股数量: {len(df)}")
|
|
|
|
|
|
|
|
print(df[['CON_CODE', 'INDATE']].head())
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### 批量处理
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
|
|
|
# 分批获取数据避免超时
|
|
|
|
|
|
|
|
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`
|