a8ea13292452b6380eef317ff006719886a5bf1b
medium effort code-review 暴露 8 个 finding,按 P0/P1/P2 优先级修复: P0 (数据正确性 / 跑得起来): #1 replace_all_node_categories 改 scope-aware delete 之前无条件 delete(NodeCategory) + 插入 runtime filter 后的子集, 导致 --type2 0 跑把其它 6 个 category 误删。改为只 delete 本批 category_key 集合,其它 type2 不动。 #2 replace_all_stock_node_map 对称化 之前空 rows 时 early-return 留下 stale,导致「categories 新 但 mappings 旧」不一致。改为 scope-aware delete 同 #1。 #3 stock_node systemd --workers 20 → 8 20 workers × 默认 10 RPS = 200 RPS,撞穿 mairui 钻石档 100 RPS 上限,触发风控。改为 8 × 10 = 80 RPS,留 20% buffer。 P1 (静默错): #4 is_a_share_code 接 hermes 格式 之前硬性要求 len(c)==6,iter_stock_codes 改返 hermes 时 5 个 task (moneyflow/share_snapshot/kline_5min/tick_trade/kline_daily) 会静默过滤成空 list。剥前缀再判断,兼容 'SH600519'。 #5 mairui tz 契约钉在 source 层 tz_localize 改为「已带 tz 就保留,没有再标 Asia/Shanghai」, 避免 mairui 改格式时抛 TypeError。task_tick_trade 删掉 strftime fallback + 冗长注释(契约已在 source 层 docstring)。 #6 CLI inspect.signature 过滤 kwargs --type2 / --backfill 加在共享 p_sync parser 上,任何 task 通过 **kwargs 静默吞掉。改为 dispatcher 按 task._run 签名过滤, 不支持的参数打 warning。 P2 (维护): #7 task_stock_node --type2 输入校验 之前空字符串 / 「concept」 / 99 都 silently collapse 成空 set, 走「无匹配叶子节点」warning 分支(被 daily_check 当正常)。 CLI 不再 silent-drop,任务层加 strict 校验,typo 返 status=error。 #8 code6_to_exchange 删 3 个死分支 4 个 code6_to_* wrapper 都先 _strip_hermes,3 个 hermes if 分支 走不到。删除后 function 简化,所有 caller 行为不变。 附带: - tests/test_smoke.py: 11 → 13 (含 mairui_ma_daily + stock_node) - tests/test_schema_models.py: 21 → 22 (含 kline_stock_ma_daily + node_categories/nodes/stock_node_map) - bin/market_sync_stock_node_run.sh 注释补充 RPS 计算 验证: - pytest tests/ 11 passed - is_a_share_code 8 个 hermes 边界 case 全过 - cli sync kline_daily --type2 2,3 → warning 已打印 - cli sync stock_node --type2 concept → status=error - cli sync stock_node --type2 99 → status=error - cli sync stock_node --type2 0 → 仅 0:0 行被刷新,其它 6 类不动 - fetch_tick_trade('600519') 返回 tz=Asia/Shanghai +08:00
market_data_sync
A 股市场数据定时同步与管理框架。
把 akshare / baostock / 新浪 / 雪球 / 麦蕊智数 等多个数据源接入到 MySQL 库,提供:
- 后台线程调度器(time-based + interval-based,交易日感知)
- 多数据源 + 自动降级 + 健康度监控
dataset_registry同步状态机(运行中 / 成功 / 失败 / 中断恢复)- FastAPI 管理接口(手动触发、状态查询、失败重试)
- CLI 入口(手动跑任务、查看状态)
📖 详细架构说明见 docs/ARCHITECTURE.md
快速开始
# 1. 准备环境(首次)
cp .env.example .env # 编辑 .env 填写真实 MySQL 凭据 + XUEQIU_TOKEN
chmod +x start.sh
./start.sh # 自动创建 .venv + 装依赖 + 启动 API(http://localhost:8100)
# 2. 常用命令
./start.sh worker # 仅启动调度器(无 web)
./start.sh list # 列出所有同步任务
./start.sh sync kline_daily # 手动触发一次(dataset_id 即可)
./start.sh status # 查看调度器/数据源/同步任务状态
./start.sh datasources # 查看数据源健康度
./start.sh reseed # 重新 seed 默认配置到 config 表
# 3. 一键全量同步(首次接入)
python bin/runall_once.py
# 4. 跑测试
.venv/bin/pytest tests/ -v
项目结构
app/
├── core/ # 核心抽象(config / db / sync / scheduler / datasource base)
├── sources/ # 数据源实现(5 个)
├── tasks/ # 同步任务实现(8 个)
├── api/ # FastAPI 管理接口
└── entrypoints/ # 进程入口(cli + worker)
bin/ # 一次性脚本
docs/ # 架构文档
tests/ # 单元测试
内置同步任务
| dataset_id | 触发时间 | 说明 |
|---|---|---|
stock_basic |
交易日 09:00 | 全市场股票基础信息 + 股本 |
kline_daily |
交易日 15:40 | 增量日 K 线(OHLCV,多源交叉) |
kline_index |
交易日 15:50 | 六大指数日线 |
kline_5min |
交易日 16:00 | 增量 5 分钟 K 线 |
moneyflow |
交易日 16:30 | 资金流(主力/大/中/小单净额) |
industry_sector |
周一 09:30 | 股票-行业映射(Baostock) |
share_snapshot |
交易日 09:30 | 股本快照(雪球) |
market_regime |
交易日 16:00 | 市场情绪(衍生源) |
添加新数据源
- 在
app/sources/新建my_source.py,继承DataSource - 在
app/core/datasource/registry.py的build_default_registry()注册
添加新同步任务
- 在
app/tasks/新建task_xxx.py,继承SyncTask,设置dataset_id - 在
app/tasks/__init__.py的TASKS字典注册 - (可选)在
app/core/sync/registry.py的SYNC_DEFINITIONS加条目
License
私有
Description
Languages
Python
94.6%
Shell
5.4%