# DataProvider 接口规范

本文档定义了 `BaseDataProvider` 抽象基类的接口规范。所有用于获取金融数据的数据提供商都必须继承此类并实现其定义的所有抽象方法。

## 设计哲学

`BaseDataProvider` 的设计旨在创建一个统一、标准化的接口，用于从各种不同的外部数据源（如 Tushare, iFind, yfinance, Finnhub 等）获取金融数据。通过这种方式，上层服务（如 `DataManager`）可以以一种与具体数据源无关的方式来请求数据，从而实现了系统核心逻辑与数据源的解耦。

这种设计带来了以下好处：
- **可扩展性**: 添加新的数据源变得简单，只需创建一个新的类继承 `BaseDataProvider` 并实现其接口即可，无需改动现有核心逻辑。
- **健壮性**: `DataManager` 可以根据配置实现数据源的优先级和故障转移（Fallback），当一个数据源不可用时，可以无缝切换到备用数据源。
- **一致性**: 所有数据提供商返回的数据格式都是标准化的，简化了上层服务的数据处理逻辑。

## 接口定义 (`BaseDataProvider`)

### 1. `get_stock_basic`

- **目的**: 获取单只股票的基本信息。
- **方法签名**: `async def get_stock_basic(self, stock_code: str) -> Optional[Dict[str, Any]]`
- **参数**:
    - `stock_code` (str): 股票的唯一代码。代码应尽量使用数据源通用的格式（例如 A 股的 `000001.SZ`）。
- **返回值**:
    - 一个包含股票基本信息的字典 (`Dict`)，例如公司名称、上市日期、行业等。
    - 如果未找到该股票，则返回 `None`。
- **示例**:
  ```json
  {
    "ts_code": "000001.SZ",
    "name": "平安银行",
    "area": "深圳",
    "industry": "银行",
    "list_date": "19910403"
  }
  ```

### 2. `get_daily_price`

- **目的**: 获取指定时间范围内的每日股价行情数据。
- **方法签名**: `async def get_daily_price(self, stock_code: str, start_date: str, end_date: str) -> List[Dict[str, Any]]`
- **参数**:
    - `stock_code` (str): 股票代码。
    - `start_date` (str): 开始日期，格式为 'YYYYMMDD'。
    - `end_date` (str): 结束日期，格式为 'YYYYMMDD'。
- **返回值**:
    - 一个列表 (`List`)，其中每个元素是一个字典，代表一天的行情数据。
    - 如果没有数据，则返回一个空列表 `[]`。
- **示例**:
  ```json
  [
    {
      "trade_date": "20231229",
      "open": 10.5,
      "high": 10.6,
      "low": 10.4,
      "close": 10.55,
      "vol": 1234567.0
    },
    ...
  ]
  ```

### 3. `get_financial_statements`

- **目的**: 获取多年的财务报表数据，并将其处理成标准化的 **时间序列 (Series)** 格式。这是最核心也是最复杂的方法。
- **方法签名**: `async def get_financial_statements(self, stock_code: str, report_dates: List[str]) -> Dict[str, List[Dict[str, Any]]]`
- **参数**:
    - `stock_code` (str): 股票代码。
    - `report_dates` (List[str]): 财报报告期列表，格式为 `['YYYYMMDD', ...]`。通常使用年末的日期，如 `['20221231', '20211231']`。
- **返回值**:
    - 一个时间序列格式的字典。该字典的键 (key) 是财务指标的名称（如 `revenue`, `n_income`），值 (value) 是一个列表，列表中的每个元素代表该指标在一个年份的数据点。
    - 如果无法获取任何数据，应返回一个空字典 `{}`。
- **关键要求**:
    1.  **数据合并**: 数据提供商内部需要调用多个API（如利润表、资产负债表、现金流量表、财务指标等）来获取所有需要的原始指标，并将它们合并。
    2.  **格式转换**: 必须将合并后的年度报表数据转换为标准的时间序列格式。
    3.  **衍生指标计算**: **数据提供商必须负责计算所有派生的财务指标**。如果某些指标（如自由现金流、各种费用率、资产占比等）无法从API直接获取，提供商需要在内部完成计算，并将计算结果一同放入返回的时间序列对象中。这确保了无论数据源如何，返回给上层服务的数据都是完整且可以直接使用的。
- **示例**:
  ```json
  {
    "revenue": [
      { "year": "2021", "value": 100000000 },
      { "year": "2022", "value": 120000000 }
    ],
    "n_income": [
      { "year": "2021", "value": 10000000 },
      { "year": "2022", "value": 12000000 }
    ],
    "__free_cash_flow": [
      { "year": "2021", "value": 8000000 },
      { "year": "2022", "value": 9500000 }
    ],
    "__sell_rate": [
      { "year": "2021", "value": 15.5 },
      { "year": "2222", "value": 16.2 }
    ]
  }
  ```

### 4. `get_financial_statement` (辅助方法)

- **目的**: 这是一个便利的辅助方法，用于获取单份、扁平化的财务报告。它主要用于需要单点数据的场景，以保持向后兼容性。
- **方法签名**: `async def get_financial_statement(self, stock_code: str, report_date: str) -> Optional[Dict[str, Any]]`
- **实现**: 此方法通常通过调用 `get_financial_statements` 并从返回的时间序列数据中重构出单份报告来实现。基类中已提供了默认实现，通常无需重写。
- **返回值**:
    - 一个扁平化的字典，包含了指定报告期的所有财务指标。
    - 如果没有数据，则返回 `None`。
- **示例**:
  ```json
  {
    "ts_code": "000001.SZ",
    "end_date": "20221231",
    "revenue": 120000000,
    "n_income": 12000000,
    "__free_cash_flow": 9500000,
    ...
  }
  ```
