# market_data_sync A 股市场数据**定时同步与管理**框架。 把 `akshare` / `baostock` / 新浪 / 雪球 / 麦蕊智数 等多个数据源接入到 PostgreSQL 库,提供: - 后台线程调度器(time-based + interval-based,交易日感知) - 多数据源 + 自动降级 + 健康度监控 - `dataset_registry` 同步状态机(运行中 / 成功 / 失败 / 中断恢复) - FastAPI 管理接口(手动触发、状态查询、失败重试) - CLI 入口(手动跑任务、查看状态) > 📖 详细架构说明见 [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) ## 运行模式 项目支持两种互斥的运行模式,由环境变量 `RUNTIME_MODE` 控制: | 模式 | 值 | 适用场景 | 调度方式 | |---|---|---|---| | **Docker 模式** | `docker` | `docker compose up` 单容器部署 | 进程内 scheduler(uvicorn + daemon thread) | | **systemd 模式** | `systemd` | Linux 宿主机长期运行 | systemd timer/service | > ⚠️ 两种模式**不能同时启用**,否则同一个 task 会被两边各触发一次,造成状态机抖动和重复 IO。 ### Docker 模式 ```bash # 1. 准备环境(首次) cp .env.example .env # 编辑 .env 填写真实 PG 凭据 + XUEQIU_TOKEN + MAIRUI_LICENCE # 2. 启动(包含 postgres + market_sync 服务) docker compose up -d # 3. 查看日志 docker compose logs -f market_sync # 4. 手动触发一次任务 docker compose exec market_sync python -m app.entrypoints.cli sync kline_daily ``` Docker 模式下 `RUNTIME_MODE=docker` 已写在 `deploy/docker/docker-compose.yml` 中,容器内会启动进程内 scheduler 负责所有同步任务。 ### systemd 模式 ```bash # 1. 准备环境(首次) cp .env.example .env # 编辑 .env 填写真实 PG 凭据 # 并在 .env 中加上 RUNTIME_MODE=systemd # 2. 部署 systemd units sudo bash deploy/systemd/deploy.sh # 3. 查看 timer systemctl list-timers market-sync* # 4. 查看 worker / 任务日志 journalctl -u market-sync -f journalctl -u market-sync-moneyflow -f ``` systemd 模式下: - 所有 14 个 task 都由 systemd timer 触发 - `market-sync-worker.service` 会被部署脚本自动 **stop / disable / mask**,避免进程内 scheduler 与 systemd timers 重叠 - 每日 23:00 `market-sync-daily-check.timer` 跑巡检,失败时 POST webhook ### 本地开发模式 ```bash # 1. 准备环境(首次) cp .env.example .env # 编辑 .env 填写凭据 chmod +x start.sh # 2. 启动 API + scheduler(默认 docker 行为,等价于本地单进程) ./start.sh # http://localhost:8100 # 3. 常用命令 ./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 表 # 4. 一键全量同步(首次接入) python bin/runall_once.py # 5. 跑测试 .venv/bin/pytest tests/ -v ``` ## 项目结构 ``` app/ # 应用源码 ├── core/ # 核心抽象(config / db / sync / scheduler / datasource base) ├── sources/ # 数据源实现 ├── tasks/ # 同步任务实现(14 个) ├── api/ # FastAPI 管理接口 └── entrypoints/ # 进程入口(cli + worker) bin/ # 通用脚本(运行入口、CLI、一次性任务) config/ # 配置文件、secrets deploy/ # 部署相关 ├── docker/ # Dockerfile + docker-compose.yml └── systemd/ # systemd units + 部署脚本 │ ├── units/ # *.service / *.timer │ └── deploy.sh # 一键部署脚本 docs/ # 架构文档 logs/ # 日志输出 tests/ # 单元测试 Dockerfile -> deploy/docker/Dockerfile docker-compose.yml -> deploy/docker/docker-compose.yml bin/deploy_systemd.sh -> deploy/systemd/deploy.sh bin/systemd_deploy.sh -> deploy/systemd/deploy.sh ``` ## 内置同步任务 | dataset_id | systemd 触发时间 | Docker scheduler 时间 | 说明 | |---|---|---|---| | `stock_basic` | 工作日 09:00 | 09:00 | 全市场股票基础信息 + 股本 | | `kline_index` | 工作日 15:30 | 15:30 | 六大指数日线 | | `kline_daily` | 工作日 15:30(runall)| 15:40 | 增量日 K 线(OHLCV,多源交叉) | | `kline_5min` | 工作日 15:30(runall)| 16:00 | 增量 5 分钟 K 线 | | `market_regime` | 工作日 15:30(runall)| 16:15 | 市场情绪(衍生源) | | `share_snapshot` | 工作日 15:30(runall)| 16:20 | 股本快照(雪球) | | `mairui_ma_daily` | 工作日 16:30 | 16:30 | 日 K MA5/10/20/60(本地派生) | | `mairui_indicators` | 工作日 16:40 | 16:40 | 日 K MACD/KDJ/BOLL(mairui) | | `moneyflow` | 工作日 21:35 | 21:35 | 资金流(主力/大/中/小单净额) | | `tick_trade` | 工作日 21:05 | 21:05 | 当天逐笔成交(mairui) | | `longhubang` | 工作日 22:00 | 22:00 | 龙虎榜(akshare / 东方财富) | | `stock_node` | 周六 11:30 | 周六 11:30 | 股票-节点映射(mairui) | ## 添加新数据源 1. 在 `app/sources/` 新建 `my_source.py`,继承 `DataSource` 2. 在 `app/core/datasource/registry.py` 的 `build_default_registry()` 注册 ## 添加新同步任务 1. 在 `app/tasks/` 新建 `task_xxx.py`,继承 `SyncTask`,设置 `dataset_id` 2. 在 `app/tasks/__init__.py` 的 `TASKS` 字典注册 3. 在 `app/core/sync/registry.py` 的 `SYNC_DEFINITIONS` 加条目 4. 如果使用 systemd 模式,在 `deploy/systemd/units/` 新增对应的 `.service` 和 `.timer` 5. 如果使用 Docker 模式,在 `app/core/scheduler/scheduler.py` 的 `DEFAULT_SCHEDULES` 新增调度项 ## License 私有