Files
ProStock/docs/db_sync_guide.md
liaozhaorun e58b39970c feat: HDF5迁移至DuckDB存储
- 新增DuckDB Storage与ThreadSafeStorage实现
- 新增db_manager模块支持增量同步策略
- DataLoader与Sync模块适配DuckDB
- 补充迁移相关文档与测试
- 修复README文档链接
2026-02-23 00:07:21 +08:00

6.1 KiB
Raw Blame History

DuckDB 数据同步指南

ProStock 现已从 HDF5 迁移至 DuckDB 存储。本文档介绍新的同步机制。

新功能概览

  • 自动表创建: 根据 DataFrame 自动推断表结构
  • 复合索引: 自动为 (trade_date, ts_code) 创建复合索引
  • 增量同步: 智能判断同步策略(按日期或按股票)
  • 类型映射: 预定义常见字段的数据类型

核心模块

1. TableManager - 表管理

from src.data.db_manager import TableManager

# 创建表管理器
manager = TableManager()

# 从 DataFrame 创建表(自动创建复合索引)
import pandas as pd
data = pd.DataFrame({
    "ts_code": ["000001.SZ"],
    "trade_date": ["20240101"],
    "close": [10.5],
})

manager.create_table_from_dataframe("daily", data)

# 确保表存在(不存在则自动创建)
manager.ensure_table_exists("daily", sample_data=data)

2. IncrementalSync - 增量同步

from src.data.db_manager import IncrementalSync

sync = IncrementalSync()

# 获取同步策略
strategy, start, end, stocks = sync.get_sync_strategy(
    table_name="daily",
    start_date="20240101",
    end_date="20240131",
    stock_codes=None  # None = 所有股票
)

# 返回值:
# - strategy: "by_date" | "by_stock" | "none"
# - start: 同步开始日期
# - end: 同步结束日期  
# - stocks: 需要同步的股票列表None = 全部)

# 执行数据同步
result = sync.sync_data("daily", data, strategy="by_date")

3. SyncManager - 高级同步

from src.data.db_manager import SyncManager
from src.data.api_wrappers import get_daily

# 创建同步管理器
manager = SyncManager()

# 一键同步(自动处理表创建、策略选择、数据获取)
result = manager.sync(
    table_name="daily",
    fetch_func=get_daily,      # 数据获取函数
    start_date="20240101",
    end_date="20240131",
    stock_codes=["000001.SZ", "600000.SH"]  # 可选:指定股票
)

print(result)
# {
#     "status": "success",
#     "table": "daily",
#     "strategy": "by_date",
#     "rows": 1000,
#     "date_range": "20240101 to 20240131"
# }

便捷函数

快速同步数据

from src.data.db_manager import sync_table
from src.data.api_wrappers import get_daily

# 同步日线数据
result = sync_table(
    table_name="daily",
    fetch_func=get_daily,
    start_date="20240101",
    end_date="20240131"
)

获取表信息

from src.data.db_manager import get_table_info

# 查看表统计信息
info = get_table_info("daily")
print(info)
# {
#     "exists": True,
#     "row_count": 100000,
#     "min_date": "20240101",
#     "max_date": "20240131",
#     "unique_stocks": 5000
# }

确保表存在

from src.data.db_manager import ensure_table

# 如果表不存在,使用 sample_data 创建
ensure_table("daily", sample_data=df)

同步策略详解

1. 按日期同步 (by_date)

适用场景: 全市场数据同步、每日增量更新

逻辑:

  • 表不存在 → 全量同步
  • 表存在但空 → 全量同步
  • 表存在且有数据 → 从 last_date + 1 开始增量同步
# 示例: 表已有数据到 20240115
strategy, start, end, stocks = sync.get_sync_strategy(
    "daily", "20240101", "20240131"
)
# 返回: ("by_date", "20240116", "20240131", None)
# 只需同步 16-31 号的新数据

2. 按股票同步 (by_stock)

适用场景: 补充特定股票的历史数据

逻辑:

  • 检查哪些请求的股票不存在于表中
  • 仅同步缺失的股票
# 示例: 表中已有 000001.SZ请求两只股票
strategy, start, end, stocks = sync.get_sync_strategy(
    "daily", "20240101", "20240131",
    stock_codes=["000001.SZ", "600000.SH"]
)
# 返回: ("by_stock", "20240101", "20240131", ["600000.SH"])
# 只同步缺失的 600000.SH

3. 无需同步 (none)

适用场景: 数据已是最新

触发条件:

  • 表存在且日期已覆盖请求范围
  • 所有请求的股票都已存在

完整示例

from src.data.db_manager import SyncManager, get_table_info
from src.data.api_wrappers import get_daily

# 1. 查看当前表状态
info = get_table_info("daily")
print(f"当前数据: {info['row_count']} 行, 最新日期: {info['max_date']}")

# 2. 创建同步管理器
manager = SyncManager()

# 3. 执行同步
result = manager.sync(
    table_name="daily",
    fetch_func=get_daily,
    start_date="20240101",
    end_date="20240222"
)

# 4. 检查结果
if result["status"] == "success":
    print(f"成功同步 {result['rows']} 行数据")
    print(f"使用策略: {result['strategy']}")
elif result["status"] == "skipped":
    print("数据已是最新,无需同步")
else:
    print(f"同步失败: {result.get('error')}")

类型映射

默认字段类型映射:

DEFAULT_TYPE_MAPPING = {
    "ts_code": "VARCHAR(16)",
    "trade_date": "DATE",
    "open": "DOUBLE",
    "high": "DOUBLE",
    "low": "DOUBLE",
    "close": "DOUBLE",
    "pre_close": "DOUBLE",
    "change": "DOUBLE",
    "pct_chg": "DOUBLE",
    "vol": "DOUBLE",
    "amount": "DOUBLE",
    "turnover_rate": "DOUBLE",
    "volume_ratio": "DOUBLE",
    "adj_factor": "DOUBLE",
    "suspend_flag": "INTEGER",
}

未定义字段会根据 pandas dtype 自动推断:

  • intINTEGER
  • floatDOUBLE
  • boolBOOLEAN
  • datetimeTIMESTAMP
  • 其他 → VARCHAR

索引策略

自动创建的索引:

  1. 主键: (ts_code, trade_date) - 确保数据唯一性
  2. 复合索引: (trade_date, ts_code) - 优化按日期查询性能

与旧代码的兼容性

原有 StorageThreadSafeStorage API 保持不变:

from src.data.storage import Storage, ThreadSafeStorage

# 旧代码继续可用
storage = Storage()
storage.save("daily", data)
df = storage.load("daily", start_date="20240101")

新增的功能通过 db_manager 模块提供。

性能建议

  1. 批量写入: 使用 SyncManager 自动处理批量写入
  2. 避免重复查询: 使用 get_table_info() 检查现有数据
  3. 合理选择策略: 全市场更新用 by_date,补充数据用 by_stock
  4. 利用索引: 查询时优先使用 trade_datets_code 过滤