Skip to content

Local 适配器架构说明

概述

Local 适配器是 FQData 框架中的本地文件数据访问组件,专门用于读取本地 CSV 文件数据。本文档详细说明其技术架构和设计决策。


整体架构

┌─────────────────────────────────────────────────────────────────────────┐
│                           应用层                                        │
│                    DataStore / DataStruct / API                         │
└─────────────────────────────────────────────────────────────────────────┘


┌─────────────────────────────────────────────────────────────────────────┐
│                         适配器层                                        │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐  ┌────────────┐ │
│  │LocalAdapter  │  │ TdxAdapter  │  │AkShareAdapter│  │EastMoney...│ │
│  └──────────────┘  └──────────────┘  └──────────────┘  └────────────┘ │
│         │                                                                   │
│         ▼                                                                   │
│  ┌──────────────┐                                                          │
│  │  CSVReader   │  (继承自 LocalAdapter)                                   │
│  └──────────────┘                                                          │
└─────────────────────────────────────────────────────────────────────────┘


┌─────────────────────────────────────────────────────────────────────────┐
│                          文件系统                                         │
│                    本地 CSV 文件 / 其他数据文件                            │
└─────────────────────────────────────────────────────────────────────────┘

核心组件

1. LocalAdapter - 本地文件适配器基类

位置: FQData/DataSource/adapters/local/base.py

职责:

职责说明
路径解析支持绝对路径和相对路径
文件操作CSV 文件的读写
连接状态管理适配器的连接状态

类图:

LocalAdapter
├── _name: str
├── _base_path: Path
├── _connected: bool
├── __init__(name, base_path)
├── _connect()
├── set_base_path(base_path)
├── get_base_path()
├── _resolve_path(file_path)
├── file_exists(file_path)
├── read_csv(file_path, encoding, **kwargs)
├── read_csv_with_date(file_path, date_column, encoding)
├── write_csv(df, file_path, encoding)
├── list_files(pattern)
└── health_check()

2. CSVReader - CSV 读取器

位置: FQData/DataSource/adapters/local/csv_reader.py

继承关系:

LocalAdapter

    └── CSVReader

职责:

职责说明
日期解析自动检测和解析日期列
数据过滤支持多种数据过滤方式
范围查询按日期范围读取数据

类图:

CSVReader
├── _default_encoding: str
├── _default_date_format: str
├── __init__(base_path, default_encoding, default_date_format)
├── read(file_path, encoding, **kwargs)
├── read_with_date_parse(file_path, date_columns, date_format, encoding)
├── read_date_range(file_path, start, end, date_column, encoding)
├── read_columns(file_path, columns, encoding)
├── read_with_filter(file_path, filters, encoding)
├── _detect_date_columns(df)
├── _parse_dates(df, date_columns, date_format)
└── get_info(file_path)

路径解析机制

路径解析流程

用户传入 file_path


┌─────────────────┐
│  类型转换        │ str → Path
└─────────────────┘


┌─────────────────┐
│  是否绝对路径?    │
└─────────────────┘

        ├── 是 → 直接返回

        └── 否


┌─────────────────┐
│  base_path 存在?  │
└─────────────────┘

        ├── 是 → base_path / file_path

        └── 否 → 返回 file_path(相对路径)

代码实现

python
def _resolve_path(self, file_path: Union[str, Path]) -> Path:
    if isinstance(file_path, str):
        file_path = Path(file_path)

    if file_path.is_absolute():
        return file_path

    if self._base_path is None:
        return file_path

    return self._base_path / file_path

数据读取流程

基础读取

read_csv(file_path, encoding)


resolve_path() → 获取完整路径


pd.read_csv(path, encoding) → DataFrame


返回 DataFrame 或 None

日期解析读取

read_csv_with_date(file_path, date_column)


read_csv() → DataFrame


检查 date_column 是否存在


pd.to_datetime(df[date_column]) → 转换日期


返回带日期类型的 DataFrame

范围读取

read_date_range(file_path, start, end, date_column)


read_with_date_parse() → 带日期的 DataFrame


排序 date_column


按 start 和 end 过滤


返回过滤后的 DataFrame

日期列自动检测

检测逻辑

python
def _detect_date_columns(self, df: pd.DataFrame) -> List[str]:
    common_date_names = [
        "date", "datetime", "时间", "日期",
        "tradedate", "trade_date"
    ]

    for col in df.columns:
        # 1. 检查列名是否匹配常见日期列名
        if col.lower() in common_date_names:
            detected.append(col)
            continue

        # 2. 尝试解析为日期
        try:
            pd.to_datetime(df[col].iloc[:10], errors='coerce')
            if df[col].iloc[:10].notna().sum() > 5:
                detected.append(col)
        except:
            pass

    return detected

数据过滤机制

过滤条件格式

python
filters = {
    "code": "600000",              # 精确匹配
    "volume": (1000, 10000),       # 范围匹配
    "name": ["平安", "银行"]        # 多值匹配(TODO
}

过滤实现

python
for col, value in filters.items():
    if isinstance(value, (list, tuple)) and len(value) == 2:
        df = df[(df[col] >= value[0]) & (df[col] <= value[1])]
    else:
        df = df[df[col] == value]

文件信息获取

get_info 返回结构

python
{
    "path": "/data/stock_600000.csv",     # 文件完整路径
    "size_bytes": 1024000,               # 文件大小(字节)
    "modified_time": datetime(2024,1,1),  # 修改时间
    "columns": ["date", "open", ...],    # 列名列表
    "row_count_estimate": 50000           # 行数估算
}

设计特点

1. 简单轻量

  • 无需网络连接
  • 无外部依赖(仅 pandas)
  • 快速响应

2. 路径灵活

  • 支持绝对路径
  • 支持相对路径
  • 支持配置基础路径

3. 错误容忍

  • 文件不存在返回 None
  • 读取失败返回 None
  • 不抛出异常,仅记录警告

4. 数据处理便捷

  • 自动日期解析
  • 支持多种过滤方式
  • 支持按范围读取

与其他适配器的比较

特性LocalAdapterTdxAdapterAkShareAdapter
数据来源本地文件通达信服务器AkShare API
网络依赖需要需要
响应速度极快较快较快
数据类型CSV股票/期货/期权多种
错误处理返回 None抛出异常抛出异常

扩展机制

扩展新的文件格式

python
class JSONReader(LocalAdapter):
    """JSON 文件读取器"""

    def read_json(self, file_path, **kwargs):
        import json
        resolved = self._resolve_path(file_path)
        with open(resolved) as f:
            return json.load(f)

扩展新的过滤类型

python
def read_with_advanced_filter(self, file_path, filters):
    df = self.read(file_path)

    for col, condition in filters.items():
        if condition.get("op") == "like":
            df = df[df[col].str.contains(condition["value"])]
        elif condition.get("op") == "in":
            df = df[df[col].isin(condition["value"])]

    return df

相关文档