# 市场数据服务接口文档 ## 架构概览 ``` ┌─────────────────────────────────────────────────────────────────────────────┐ │ HTTP 客户端 │ │ (浏览器/Postman/其他服务) │ └─────────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────────────┐ │ API 路由层 (HTTP) │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────────┐ │ │ │ /stock/* │ │ /futures/* │ │ /admin/* │ │ /stream (WS) │ │ │ └──────────────┘ └──────────────┘ └──────────────┘ └──────────────────┘ │ └─────────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────────────┐ │ 服务层 (Service) │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────────┐ │ │ │ StockService │ │FuturesService│ │ AdminService │ │ TestService │ │ │ └──────────────┘ └──────────────┘ └──────────────┘ └──────────────────┘ │ └─────────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────────────┐ │ 适配器服务层 (Adapter) │ │ ┌──────────────────────────────────┐ │ │ │ AdapterService (单例) │ │ │ │ ┌────────────────────────────┐ │ │ │ │ │ AmazingDataAdapter │ │ │ │ │ │ ┌──────────────────────┐ │ │ │ │ │ │ │ _internal: │ │ │ │ │ │ │ │ InternalDataService │ │ │ │ │ │ │ └──────────────────────┘ │ │ │ │ │ └────────────────────────────┘ │ │ │ └──────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────────────┐ │ 内部数据服务层 (Internal) │ │ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────────────┐ │ │ │ _MarketDataInternal│ │ _BaseDataInternal │ │ _InfoDataInternal │ │ │ │ ┌──────────────┐ │ │ ┌──────────────┐ │ │ ┌──────────────────────┐ │ │ │ │ │ query_kline │ │ │ │get_code_list │ │ │ │ get_equity_structure │ │ │ │ │ │query_snapshot│ │ │ │ get_calendar │ │ │ │ get_share_holder │ │ │ │ │ └──────────────┘ │ │ │get_adj_factor│ │ │ │ get_income │ │ │ │ │ │ │ │ get_etf_pcf │ │ │ │ get_balance_sheet │ │ │ │ │ │ │ └──────────────┘ │ │ │ get_cash_flow │ │ │ │ │ │ │ │ │ │ get_margin_* │ │ │ │ │ │ │ │ │ │ get_index_* │ │ │ │ │ │ │ │ │ │ get_fund_share │ │ │ │ └──────────────────┘ └──────────────────┘ │ └──────────────────────┘ │ │ │ └──────────────────────────┘ │ └─────────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────────────┐ │ SDK 层 (AmazingData) │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │ login │ │BaseData │ │MarketData│ │ InfoData │ │ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ │ (银河证券星耀数智) │ └─────────────────────────────────────────────────────────────────────────────┘ ``` --- ## 一、对外接口 (HTTP API) 对外接口是提供给外部系统调用的 RESTful API,路径以 `/v1` 为前缀。 ### 1.1 股票接口 | 接口 | 方法 | 路径 | 说明 | |------|------|------|------| | 查询股票K线 | GET | `/v1/stock/klines/{symbol}` | 获取指定股票的历史K线数据 | | 查询股票列表 | GET | `/v1/stock/symbols` | 获取所有股票代码列表 | | 查询股票基本信息 | GET | `/v1/stock/basic/{symbol}` | 获取股票的基本信息 | | 批量查询K线 | POST | `/v1/stock/klines/batch` | 批量获取多只股票的K线 | **调用链示例:** ``` GET /v1/stock/klines/000001.SZ │ ▼ routes.py:query_stock_klines() │ ▼ StockService.query_klines() │ ├── 1. 先查数据库 (StockRepository) │ └── 有数据 → 直接返回 │ └── 2. 无数据 → 从适配器获取 │ ▼ AdapterService.get_active_adapter("stock") │ ▼ AmazingDataAdapter.fetch_klines() │ ▼ InternalDataService.market.query_kline() │ ▼ AmazingData.MarketData.query_kline() ``` ### 1.2 期货接口 | 接口 | 方法 | 路径 | 说明 | |------|------|------|------| | 查询期货K线 | GET | `/v1/futures/klines/{symbol}` | 获取期货合约K线数据 | | 查询期货列表 | GET | `/v1/futures/symbols` | 获取所有期货合约列表 | ### 1.3 管理接口 | 接口 | 方法 | 路径 | 说明 | |------|------|------|------| | 健康检查 | GET | `/v1/admin/health` | 检查服务健康状态 | | 数据源状态 | GET | `/v1/admin/source/status` | 查看数据源连接状态 | | 适配器列表 | GET | `/v1/admin/adapters` | 查看所有适配器配置 | ### 1.4 测试接口 (Admin) | 接口 | 方法 | 路径 | 说明 | |------|------|------|------| | 获取API测试列表 | GET | `/v1/admin/tests/api` | 获取对外接口测试列表 | | 执行API测试 | POST | `/v1/admin/tests/api/run` | 执行指定的API测试 | | **获取内部接口测试列表** | **GET** | **`/v1/admin/tests/internal`** | **获取对内SDK接口测试列表** | | **执行内部接口测试** | **POST** | **`/v1/admin/tests/internal/run`** | **执行指定的对内接口测试** | --- ## 二、对内接口 (Internal SDK 封装层) 对内接口是直接封装 AmazingData SDK 的内部方法,通过 `InternalDataService` 统一暴露。 ### 2.1 访问路径 ```python # 获取 adapter adapter = AdapterService.get_active_adapter("stock") # 访问内部接口 adapter._internal.market.query_kline(...) adapter._internal.base.get_code_list(...) adapter._internal.info.get_equity_structure(...) ``` ### 2.2 接口清单 (23个) #### 2.2.1 市场数据接口 (_MarketDataInternal) | 序号 | 方法名 | 说明 | 对应 SDK | |------|--------|------|----------| | 1 | `query_kline()` | 查询K线数据 | `MarketData.query_kline()` | | 2 | `query_snapshot()` | 查询快照数据 | `MarketData.query_snapshot()` | #### 2.2.2 基础数据接口 (_BaseDataInternal) | 序号 | 方法名 | 说明 | 对应 SDK | |------|--------|------|----------| | 3 | `get_code_list()` | 获取股票代码列表 | `BaseData.get_code_list()` | | 4 | `get_future_code_list()` | 获取期货代码列表 | `BaseData.get_future_code_list()` | | 5 | `get_code_info()` | 获取代码详细信息 | `BaseData.get_code_info()` | | 6 | `get_calendar()` | 获取交易日历 | `BaseData.get_calendar()` | | 7 | `get_adj_factor()` | 获取复权因子 | `BaseData.get_adj_factor()` | | 8 | `get_etf_pcf()` | 获取ETF申赎数据 | `BaseData.get_etf_pcf()` | #### 2.2.3 股本股东接口 (_InfoDataInternal) | 序号 | 方法名 | 说明 | 对应 SDK | 特殊处理 | |------|--------|------|----------|----------| | 9 | `get_equity_structure()` | 获取股本结构 | `InfoData.get_equity_structure()` | - | | 10 | `get_share_holder()` | 获取股东数据 | `InfoData.get_share_holder()` | **每次创建新实例** | | 11 | `get_holder_num()` | 获取股东户数 | `InfoData.get_holder_num()` | - | #### 2.2.4 财务报表接口 (_InfoDataInternal) | 序号 | 方法名 | 说明 | 对应 SDK | |------|--------|------|----------| | 12 | `get_income()` | 获取利润表 | `InfoData.get_income()` | | 13 | `get_balance_sheet()` | 获取资产负债表 | `InfoData.get_balance_sheet()` | | 14 | `get_cash_flow()` | 获取现金流量表 | `InfoData.get_cash_flow()` | #### 2.2.5 市场状态接口 (_InfoDataInternal) | 序号 | 方法名 | 说明 | 对应 SDK | |------|--------|------|----------| | 15 | `get_history_stock_status()` | 获取历史股票状态 | `InfoData.get_history_stock_status()` | | 16 | `get_margin_summary()` | 获取融资融券汇总 | `InfoData.get_margin_summary()` | | 17 | `get_margin_detail()` | 获取融资融券明细 | `InfoData.get_margin_detail()` | #### 2.2.6 特色数据接口 (_InfoDataInternal) | 序号 | 方法名 | 说明 | 对应 SDK | |------|--------|------|----------| | 18 | `get_long_hu_bang()` | 获取龙虎榜数据 | `InfoData.get_long_hu_bang()` | | 19 | `get_block_trading()` | 获取大宗交易数据 | `InfoData.get_block_trading()` | | 20 | `get_index_constituent()` | 获取指数成分股 | `InfoData.get_index_constituent()` | | 21 | `get_index_weight()` | 获取指数权重 | `InfoData.get_index_weight()` | #### 2.2.7 基金可转债接口 (_InfoDataInternal) | 序号 | 方法名 | 说明 | 对应 SDK | |------|--------|------|----------| | 22 | `get_fund_share()` | 获取基金份额 | `InfoData.get_fund_share()` | | 23 | `get_kzz_issuance()` | 获取可转债发行 | `InfoData.get_kzz_issuance()` | --- ## 三、调用链详解 ### 3.1 完整调用链示例:查询股票K线 ``` ┌─────────────────────────────────────────────────────────────────────────────┐ │ 第1层:HTTP 客户端请求 │ │ GET http://localhost:8080/v1/stock/klines/000001.SZ?start=20240101&... │ └─────────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────────────┐ │ 第2层:API 路由层 (app/api/routes.py) │ │ @router.get("/stock/klines/{symbol}") │ │ def query_stock_klines(symbol, start, end, freq, adjust, db, api_key) │ │ │ │ 职责:参数校验、认证、调用服务层 │ └─────────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────────────┐ │ 第3层:服务层 (app/services/stock_service.py) │ │ class StockService: │ │ def query_klines(self, req: KLineQueryRequest) -> KLineData: │ │ │ │ 职责:业务逻辑、数据聚合、缓存策略 │ │ 步骤: │ │ 1. 先查询数据库 (StockRepository) │ │ 2. 如无数据,调用适配器获取 │ │ 3. 保存到数据库 │ │ 4. 返回格式化数据 │ └─────────────────────────────────────────────────────────────────────────────┘ │ (如无缓存) ▼ ┌─────────────────────────────────────────────────────────────────────────────┐ │ 第4层:适配器服务层 (app/services/adapter_service.py) │ │ class AdapterService: # 单例模式 │ │ def get_active_adapter(self, asset_class: str) -> DataSourceAdapter: │ │ │ │ 职责:管理适配器生命周期、连接管理、配置管理 │ └─────────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────────────┐ │ 第5层:适配器实现 (app/adapters/amazingdata_adapter.py) │ │ class AmazingDataAdapter(DataSourceAdapter): │ │ async def fetch_klines(self, symbol, start, end, freq) -> List[KLine] │ │ │ │ 职责:适配器具体实现、数据格式转换、调用内部接口 │ │ │ │ 内部调用: │ │ self._internal.market.query_kline( │ │ code_list=[symbol], │ │ begin_date=int(start), │ │ end_date=int(end), │ │ period=10000 # SDK只支持日线 │ │ ) │ └─────────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────────────┐ │ 第6层:内部数据服务层 (app/adapters/internal_data_service.py) │ │ class _MarketDataInternal: │ │ def query_kline(self, code_list, begin_date, end_date, period): │ │ return self._market_data.query_kline(...) │ │ │ │ 职责:SDK 封装、异常处理、日志记录 │ └─────────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────────────┐ │ 第7层:SDK 层 (AmazingData) │ │ from AmazingData import MarketData │ │ market_data = MarketData(calendar) │ │ market_data.query_kline(code_list, begin_date, end_date, period) │ │ │ │ 职责:与银河证券星耀数智服务器通信 │ └─────────────────────────────────────────────────────────────────────────────┘ ``` ### 3.2 内部接口测试调用链 ``` ┌─────────────────────────────────────────────────────────────────────────────┐ │ 第1层:管理后台点击"测试"按钮 │ │ POST /v1/admin/tests/internal/run │ │ Body: { "id": "internal_market_query_kline", "params": {...} } │ └─────────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────────────┐ │ 第2层:Admin 路由 (app/api/admin_routes.py) │ │ @admin_router.post("/admin/tests/internal/run") │ │ async def run_internal_test(req: APITestRequest, token): │ │ │ │ 职责:获取 adapter、确保连接、调用测试服务 │ └─────────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────────────┐ │ 第3层:测试服务 (app/services/test_service.py) │ │ class TestService: │ │ async def run_internal_test(self, adapter, req: APITestRequest): │ │ │ │ 职责:根据 test_id 分发到对应的内部接口调用 │ │ │ │ 例如 req.id == "internal_market_query_kline": │ │ adapter._internal.market.query_kline(...) │ │ │ │ 例如 req.id == "internal_info_get_share_holder": │ │ adapter._internal.info.get_share_holder(...) # 创建新 InfoData 实例 │ └─────────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────────────┐ │ 第4层:内部数据服务层 (app/adapters/internal_data_service.py) │ │ │ │ 标准调用流程: │ │ def query_kline(self, ...): │ │ return self._market_data.query_kline(...) │ │ │ │ 特殊处理(get_share_holder): │ │ def get_share_holder(self, ...): │ │ # 创建新的 InfoData 实例以避免 SDK 内部状态问题 │ │ import AmazingData as ad │ │ info_data = ad.InfoData() # <-- 新实例 │ │ return info_data.get_share_holder(...) │ └─────────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────────────┐ │ 第5层:SDK 层 (AmazingData) │ │ 与银河证券星耀数智服务器通信 │ └─────────────────────────────────────────────────────────────────────────────┘ ``` --- ## 四、关键代码片段 ### 4.1 内部数据服务初始化 ```python # app/adapters/amazingdata_adapter.py class AmazingDataAdapter(DataSourceAdapter): def __init__(self): self._internal: Optional[InternalDataService] = None def _do_login(self): # 初始化 SDK 数据类 self._base_data = self._ad.BaseData() self._info_data = self._ad.InfoData() self._calendar = self._base_data.get_calendar() self._market_data = self._ad.MarketData(self._calendar) # 初始化内部数据服务层(关键!) self._internal = InternalDataService(self) ``` ### 4.2 内部数据服务封装 ```python # app/adapters/internal_data_service.py class InternalDataService: """内部数据服务统一入口""" def __init__(self, ad): """ Args: ad: AmazingDataAdapter instance with _market_data, _base_data, _info_data """ self.market = _MarketDataInternal(ad._market_data) self.base = _BaseDataInternal(ad._base_data) self.info = _InfoDataInternal(ad._info_data) ``` ### 4.3 特殊处理:get_share_holder ```python # app/adapters/internal_data_service.py class _InfoDataInternal: def get_share_holder(self, code_list, local_path, is_local, begin_date=None, end_date=None): """获取股东数据""" try: # 创建新的 InfoData 实例以避免 SDK 内部状态问题 import AmazingData as ad info_data = ad.InfoData() return info_data.get_share_holder( code_list=code_list, local_path=local_path, is_local=is_local, begin_date=begin_date, end_date=end_date ) except Exception as e: error(f"[_InfoDataInternal] Get share holder failed: {e}") return {} ``` --- ## 五、接口测试清单 ### 5.1 对外接口测试 (18个) | 分类 | 测试项 | 路径 | |------|--------|------| | 股票接口 | 查询股票K线 | GET /v1/stock/klines/{symbol} | | 股票接口 | 查询股票列表 | GET /v1/stock/symbols | | 期货接口 | 查询期货K线 | GET /v1/futures/klines/{symbol} | | 期货接口 | 查询期货列表 | GET /v1/futures/symbols | | 管理接口 | 健康检查 | GET /v1/admin/health | | ... | ... | ... | ### 5.2 对内接口测试 (23个) 详见第二节接口清单,每个内部接口都有对应的测试用例。 --- ## 六、配置说明 ### 6.1 数据源配置 (config.json) ```json { "sources": { "stock": { "active": "amazingdata", "list": { "amazingdata": { "type": "sdk", "config": { "username": "your_username", "password": "your_password", "host": "140.206.44.234", "port": "8600", "local_path": "./amazing_data_cache/", "use_local_cache": "true" } } } } } } ``` --- ## 七、总结 1. **对外接口**:HTTP RESTful API,供外部系统调用 2. **对内接口**:SDK 封装层,通过 `adapter._internal` 访问 3. **调用链**:外部请求 → 路由 → 服务 → 适配器服务 → 适配器 → 内部接口 → SDK 4. **特殊处理**:`get_share_holder` 每次创建新的 `InfoData` 实例以避免 SDK 状态问题 --- ## 八、数据流向与缓存策略 ### 8.1 数据流向图 ``` ┌─────────────────────────────────────────────────────────────────────────────┐ │ 数据流向架构 │ └─────────────────────────────────────────────────────────────────────────────┘ 外部请求 │ ▼ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ API │────▶│ Service│────▶│Repository│ │ Layer │ │ Layer │ │ Layer │ └────┬────┘ └────┬────┘ └────┬────┘ │ │ │ │ │ ▼ │ │ ┌─────────┐ │ │ │ MySQL │ │ │ │ Database│ │ │ └────┬────┘ │ │ │ │ ▼ │ │ ┌─────────┐ │ │ │ Adapter │ │ │ │ Service │ │ │ └────┬────┘ │ │ │ │ ▼ ▼ ▼ ┌─────────────────────────────────────────┐ │ AmazingDataAdapter │ │ ┌─────────────────────────────────┐ │ │ │ InternalDataService │ │ │ │ ┌─────────┐ ┌─────────┐ │ │ │ │ │ _Market │ │ _Base │ ... │ │ │ │ │ _Data │ │ _Data │ │ │ │ │ └────┬────┘ └────┬────┘ │ │ │ └───────┼───────────┼────────────┘ │ └──────────┼───────────┼─────────────────┘ │ │ ▼ ▼ ┌─────────────────────────────────────────┐ │ AmazingData SDK │ │ MarketData BaseData InfoData │ └─────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────┐ │ 银河证券星耀数智服务器 │ └─────────────────────────────────────────┘ ``` ### 8.2 缓存策略 ```python # 数据获取优先级 1. 内存缓存 (Redis) - 最高优先级,实时数据 2. 数据库 (MySQL) - 持久化存储,历史数据 3. SDK 实时获取 - 兜底方案,网络请求 ``` **缓存规则:** | 数据类型 | 缓存位置 | 缓存时间 | 更新策略 | |---------|---------|---------|---------| | K线数据 | MySQL + Redis | 永久 + 5分钟 | 懒加载 | | 股票列表 | MySQL | 永久 | 每日同步 | | 实时行情 | Redis | 1分钟 | 实时推送 | | 财务数据 | MySQL | 永久 | 季度更新 | --- ## 九、错误处理机制 ### 9.1 错误处理层级 ``` ┌─────────────────────────────────────────────────────────────────────────────┐ │ 错误处理流程 │ └─────────────────────────────────────────────────────────────────────────────┘ SDK 错误 │ ▼ ┌─────────────────┐ │ Internal Layer │ 捕获异常,记录日志,返回默认值 │ try/except │ └────────┬────────┘ │ ▼ ┌─────────────────┐ │ Adapter Layer │ 转换数据格式,处理空值 │ │ └────────┬────────┘ │ ▼ ┌─────────────────┐ │ Service Layer │ 业务逻辑判断,降级策略 │ │ └────────┬────────┘ │ ▼ ┌─────────────────┐ │ API Layer │ 包装错误响应,HTTP 状态码 │ │ └────────┬────────┘ │ ▼ 客户端收到错误响应 ``` ### 9.2 错误码定义 | 错误码 | 说明 | 处理方式 | |-------|------|---------| | 0 | 成功 | - | | 400 | 请求参数错误 | 检查参数格式 | | 401 | 未授权 | 检查 API Key | | 404 | 数据不存在 | 尝试从 SDK 获取 | | 500 | 服务器内部错误 | 查看日志,联系管理员 | | 503 | 数据源不可用 | 检查适配器连接状态 | ### 9.3 内部接口错误处理示例 ```python # app/adapters/internal_data_service.py class _MarketDataInternal: def query_kline(self, code_list, begin_date, end_date, period): """查询K线数据 - 带错误处理""" try: return self._market_data.query_kline( code_list=code_list, begin_date=begin_date, end_date=end_date, period=period ) except Exception as e: # 记录详细错误日志 error(f"[_MarketDataInternal] Query kline failed: {e}") error(f" Params: code_list={code_list}, period={period}") # 返回空结果而非抛出异常,保证服务可用性 return {} ``` --- ## 十、WebSocket 实时数据接口 ### 10.1 WebSocket 连接 ``` ws://localhost:8080/v1/stream ``` ### 10.2 消息类型 | 消息类型 | 方向 | 说明 | |---------|------|------| | subscribe | C→S | 订阅标的 | | unsubscribe | C→S | 取消订阅 | | tick | S→C | 实时 tick 数据 | | kline | S→C | 实时 K线数据 | | error | S→C | 错误通知 | ### 10.3 订阅示例 ```javascript // 客户端订阅 const ws = new WebSocket('ws://localhost:8080/v1/stream'); ws.onopen = () => { // 订阅股票 ws.send(JSON.stringify({ action: 'subscribe', symbols: ['000001.SZ', '000002.SZ'] })); }; ws.onmessage = (event) => { const data = JSON.parse(event.data); console.log('收到数据:', data); }; ``` ### 10.4 WebSocket 调用链 ``` 客户端订阅 │ ▼ WebSocket Endpoint │ ▼ StreamService │ ▼ AdapterService.get_adapter("stock") │ ▼ AmazingDataAdapter.subscribe_tick(symbols, callback) │ ▼ AmazingData.MarketData.subscribe(...) # SDK 订阅 │ ▼ 数据推送回调 │ ▼ WebSocket 发送给客户端 ``` --- ## 十一、数据同步机制 ### 11.1 同步任务类型 ``` ┌─────────────────────────────────────────────────────────────────────────────┐ │ 数据同步架构 │ └─────────────────────────────────────────────────────────────────────────────┘ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ 股票K线同步 │ │ 期货K线同步 │ │ 股票列表同步│ │ 财务数据同步│ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │ │ │ │ └────────────────┴────────────────┴────────────────┘ │ ▼ ┌─────────────────┐ │ Sync Service │ └────────┬────────┘ │ ┌────────────┼────────────┐ ▼ ▼ ▼ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ Daily │ │ Weekly │ │ Manual │ │ Sync │ │ Sync │ │ Sync │ └─────────┘ └─────────┘ └─────────┘ ``` ### 11.2 同步接口 | 接口 | 方法 | 路径 | 说明 | |------|------|------|------| | 手动同步 | POST | `/v1/admin/data/sync` | 触发指定类型的数据同步 | ### 11.3 同步调用链 ``` POST /v1/admin/data/sync │ ▼ AdminService.sync_data(sync_type) │ ├── sync_type = "base" → 同步基础K线 ├── sync_type = "quote" → 同步行情指标 ├── sync_type = "finance" → 同步财务数据 └── sync_type = "full" → 全量同步 │ ▼ AmazingDataAdapter.fetch_stock_basic_info() │ ▼ InternalDataService.base.get_code_list() InternalDataService.base.get_code_info() InternalDataService.info.get_equity_structure() │ ▼ 保存到 MySQL ``` --- ## 十二、数据库表结构 ### 12.1 表清单 | 表名 | 说明 | 数据来源 | |------|------|---------| | `stock_symbols` | 股票基础信息 | SDK BaseData | | `stock_klines_1d_base` | 股票日线基础数据 | SDK MarketData | | `stock_klines_1d_quote` | 股票日线行情指标 | SDK MarketData | | `stock_klines_1d_finance` | 股票日线财务数据 | SDK InfoData | | `futures_klines_1d_base` | 期货日线基础数据 | SDK MarketData | | `futures_klines_1d_quote` | 期货日线行情指标 | SDK MarketData | | `realtime_quotes` | 实时行情数据 | SDK MarketData | | `sync_tasks` | 同步任务记录 | 系统生成 | ### 12.2 分表策略 ``` stock_klines_* ├── stock_klines_1d_base # 日线基础K线 (OHLCV) ├── stock_klines_1d_quote # 日线行情指标 (均线、MACD等) ├── stock_klines_1d_finance # 日线财务数据 (市值、PE等) ├── stock_klines_1m_base # 分钟线基础数据 └── stock_klines_5m_base # 5分钟线基础数据 ``` --- ## 十三、部署与运维 ### 13.1 启动流程 ```bash # 1. 启动服务 python -m uvicorn app.main:app --host 0.0.0.0 --port 8080 # 2. 服务初始化流程 main.py │ ├── 加载配置 (config.json) │ ├── 初始化数据库连接 │ ├── 初始化 Redis 连接 │ └── 启动 FastAPI 服务 │ └── 首次请求时懒加载适配器 ``` ### 13.2 适配器连接流程 ``` 首次请求 │ ▼ AdapterService.get_active_adapter("stock") │ ├── 检查 active_adapters 缓存 │ ├── 存在且已连接 → 直接返回 │ └── 不存在或断开 → 创建新连接 │ ▼ AmazingDataAdapter.connect(config) │ ├── 登录 SDK │ AmazingData.login(username, password, host, port) │ ├── 初始化数据类 │ BaseData(), InfoData(), MarketData() │ └── 初始化 InternalDataService │ self._internal = InternalDataService(self) │ ▼ 保存到 active_adapters 缓存 ``` ### 13.3 健康检查 ```bash # 健康检查接口 GET /v1/admin/health # 响应示例 { "code": 0, "message": "success", "data": { "status": "healthy", "database": "connected", "redis": "connected", "adapters": { "amazingdata": "connected" } } } ``` --- ## 十四、开发指南 ### 14.1 新增对外接口 ```python # 1. 在 routes.py 添加路由 @router.get("/stock/new_endpoint/{param}") def new_endpoint(param: str, db: Session = Depends(get_db)): service = StockService(db) return service.new_method(param) # 2. 在 service 实现业务逻辑 class StockService: def new_method(self, param): # 业务逻辑 return result # 3. 如需 SDK 数据,在 adapter 添加方法 class AmazingDataAdapter: async def fetch_new_data(self, param): return self._internal.xxx.method(param) ``` ### 14.2 新增对内接口 ```python # 1. 在 internal_data_service.py 添加方法 class _InfoDataInternal: def new_internal_method(self, param): try: return self._info_data.sdk_method(param) except Exception as e: error(f"[_InfoDataInternal] new method failed: {e}") return default_value # 2. 在 test_service.py 添加测试用例 APITestCase( id="internal_info_new_method", name="SDK: new_method", description="...", method="INTERNAL", path="AmazingDataAdapter._internal.info.new_internal_method" ) ``` ### 14.3 调用关系速查 ``` 需要调用 SDK 的接口: ↓ adapter._internal.{category}.{method} category 可选值: - market: 市场数据 (K线、快照) - base: 基础数据 (代码列表、日历、复权因子) - info: 信息数据 (财务、股本、融资融券等) ``` --- ## 十五、附录 ### 15.1 SDK Period 参数对照表 | 周期 | SDK 参数值 | 说明 | |------|-----------|------| | 日线 | 10000 | 仅支持此值 | | 1分钟 | - | SDK 不支持 | | 5分钟 | - | SDK 不支持 | > 注意:当前 SDK 版本 `query_kline` 仅支持 `period=10000`(日线),其他值会导致 `'NoneType' object cannot be interpreted as an integer` 错误。 ### 15.2 文件结构 ``` app/ ├── api/ │ ├── routes.py # 对外接口路由 │ └── admin_routes.py # 管理后台路由 ├── services/ │ ├── stock_service.py # 股票业务服务 │ ├── futures_service.py # 期货业务服务 │ ├── adapter_service.py # 适配器管理服务 │ └── test_service.py # 测试服务 ├── adapters/ │ ├── amazingdata_adapter.py # 星耀数智适配器 │ ├── internal_data_service.py # 内部数据服务层 │ └── base.py # 适配器基类 ├── models/ # 数据模型 ├── repositories/ # 数据访问层 └── core/ # 核心工具 ``` ### 15.3 关键配置项 | 配置项 | 说明 | 默认值 | |-------|------|--------| | `sources.stock.active` | 当前激活的股票数据源 | `amazingdata` | | `sources.stock.list.amazingdata.config.local_path` | 本地缓存路径 | `./amazing_data_cache/` | | `sources.stock.list.amazingdata.config.use_local_cache` | 是否使用本地缓存 | `true` | --- **文档版本**: 1.0 **最后更新**: 2026-03-15 **适用版本**: Python Market Data Service