From 86a7f8ef2de19d24b8dc614cc1b0d2b612fbd6ac Mon Sep 17 00:00:00 2001 From: claude_dev Date: Fri, 10 Jul 2026 08:16:41 +0800 Subject: [PATCH] =?UTF-8?q?docs+fix(data):=20run=5Fdaily=5Fupdate=E9=87=8D?= =?UTF-8?q?=E5=86=99raw+qfq=E5=A2=9E=E9=87=8F=20+=20daily-update-design=20?= =?UTF-8?q?v3=E5=8F=8C=E6=BA=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - run_daily_update.sh: 重写raw+qfq增量(跳daily_all_update新浪坏接口KeyError:date, 持久路径data_cache/daily_update不进tmp, set -uo pipefail不-e); C-S3每日raw(撮合)+qfq(warmup) - daily-update-design.md: v3.0变更记录+十六节(双源raw/qfq架构/脚本更新清单/launchd15:30部署/准确性验证/与v2关系) - config/data_platform.yaml: minute_15_qfq_dir/minute_15_raw_dir(15min双源目录) --- docs/data-platform/daily-update-design.md | 39 ++++++++++++ scripts/data_platform/run_daily_update.sh | 77 ++++++++++++----------- 2 files changed, 80 insertions(+), 36 deletions(-) diff --git a/docs/data-platform/daily-update-design.md b/docs/data-platform/daily-update-design.md index 56960c5..18c7f9e 100644 --- a/docs/data-platform/daily-update-design.md +++ b/docs/data-platform/daily-update-design.md @@ -531,6 +531,7 @@ sanguo_vnpy/ | 2026-05-03 | v1.1 | 司马懿评审后修改:interval→15m, 严格增量追加, 日线进度文件, 全局源检测, DB轮转备份, 失败率告警 | 赵云 | | 2026-05-05 | v1.2 | 东方财富集成:日线主源切换为东方财富(amount真实,反爬策略4s/请求+随机抖动), 腾讯降为备源 | 赵云 | | 2026-05-06 | v2.0 | **重大架构变更**:BaoStock替代所有主源(无反爬、全量历史、amount真实);15min interval改为1m;vnpy DB写入改为本地构建+rsync;新浪API已挂移除;多源fallback机制重构 | 赵云 | +| 2026-07-10 | v3.0 | **双源架构+脚本重构**:raw/qfq双源(task#79,5yr全市场29600×2); run_daily_update.sh重写(raw+qfq增量,跳daily_all_update新浪坏接口,持久路径,不set-e); baostock_download.py(15min双源+reconnect retry限流鲁棒); raw_redownload断点续传; launchd 15:30 | 楚锋 | --- @@ -774,3 +775,41 @@ M2 失败暂停:改为失败率检测(最近100只>80%切换源)。 历史回补: 日线+15min:BaoStock(全量历史,无反爬) ``` + +--- + +## 十六、v3.0 双源架构 + 脚本重构(2026-07-10) + +### 16.1 背景:task#79 mixed-adjust 假跌 + +v2.0 `daily_dir` 是 mixed-adjust(hfq bulk + raw tail 拼接),3-30 类单日 -94% 假跌。C-S3 模拟盘撮合/涨跌停需真实价,策略信号需无除权缺口 → **双源**。 + +### 16.2 双源设计(raw + qfq) + +| 源 | 用途 | adjustflag | 目录(cfg.data_paths)| +|----|------|-----------|------| +| **raw** | 撮合/涨跌停/成交价(真实交易价,含除权缺口)| akshare `adjust=""` / baostock `flag=3` | `raw_dir` / `minute_15_raw_dir` | +| **qfq** | 策略 on_bar 信号(前复权,无除权缺口 → MA 信号准)| akshare `adjust="qfq"` / baostock `flag=2` | `qfq_dir` / `minute_15_qfq_dir` | +| daily(mixed) | 仅 backtest 兼容,**模拟盘不用** | - | `daily_dir` | + +`data_source.py _resolve_dir_key` 路由:日线/15min 均支持 raw/qfq 双源,缺配置明确报错(不 fallback 防混源)。 + +### 16.3 脚本更新清单 + +| 脚本 | 更新 | 用途 | +|------|------|------| +| `run_daily_update.sh` | **重写**:raw+qfq 增量(最近5天),跳 `daily_all_update`(新浪源坏 `KeyError:date`),持久路径 `data_cache/daily_update`(不进 /tmp 重启丢),`set -uo pipefail`(不 -e,单只失败不退)| 每日增量(C-S3 实走)| +| `baostock_download.py` | **新**:15min 双源(qfq+raw),`reconnect()`+`download_one max_retries=3`(限流/broken pipe 自动 `bs.logout+login` 重连)| 15min 全量/增量 | +| `raw_redownload.py` | 断点续传(`exists()`/skip 已存在,扩范围重下覆盖)| raw/qfq 全量/增量 | +| `full_deploy_5yr.sh` | **新**:5yr 全量部署 pipeline(qfq→raw→rsync→验证)| 一次性部署 | +| `verify_dual_source.py` | **新**:容器内双源验证(fetch_day/iter_bars/除权日/抽检)| 部署验证 | + +### 16.4 部署与验证 + +- **launchd** `com.sanguo.data-update`:每日 **15:30** 跑 `run_daily_update.sh`(收盘后增量 raw+qfq 最近 5 天 → NAS;Mac 睡眠错过唤醒补跑) +- **数据量**:日线双源 5yr 全市场(qfq+raw 各 ~29600 文件);15min 沪深300 baostock(131/300,限流续下,断点续传) +- **准确性验证**:除权日 raw 含缺口 / qfq 平滑(浦发 2022-07-21 raw -5.9% / qfq -0.6%;宁德 2023-04-26 raw -41.8% / qfq +5.4%);跨源一致(日线 raw close = 15min raw 当日末 bar);全市场抽检无 mixed 假跌 + +### 16.5 与 v2.0 的关系 + +v3.0 在 v2.0(BaoStock 主源 + 本地构建 rsync)基础上,**新增双源(raw/qfq)** 区分撮合价与信号价,解决 mixed-adjust 假跌。`run_daily_update.sh` 从 v1 `daily_all_update` 包装改为 raw+qfq 直接增量(跳过新浪坏接口)。BaoStock 仍是 15min 主源(v2.0 遗产),日线用 akshare 新浪源 `stock_zh_a_daily`(adjust ""/qfq 双源)。 diff --git a/scripts/data_platform/run_daily_update.sh b/scripts/data_platform/run_daily_update.sh index 319b455..a9ae067 100755 --- a/scripts/data_platform/run_daily_update.sh +++ b/scripts/data_platform/run_daily_update.sh @@ -1,46 +1,51 @@ #!/bin/bash -# v2 数据下载包装(SSH 模式:rsync NAS↔本地 + 跑 v1 daily_all_update + raw 增量) -# 不依赖 SMB 挂载,用 sanguo-nas SSH key 免密。 -# 用法:./run_daily_update.sh [--skip-daily|--skip-15min] +# 每日数据增量(C-S3 实走用):raw 真实价 + qfq 前复权,最近 N 天 → NAS。 +# +# 跳过 v1 daily_all_update(新浪源接口坏 KeyError:date,C-S3 不用 daily mixed)。 +# raw/qfq 用 raw_redownload.py(akshare 新浪 stock_zh_a_daily,全量 29600 已验证)。 +# 15min baostock 增量 = 分期项(默认跳,日内策略落地时加)。 +# # env: -# STOCK_LIMIT=N 限制股票数(验证用,默认 0=全市场) -# SKIP_PULL=1 跳过 rsync 拉(验证用;生产必须拉,v1 才能增量) -# SKIP_RAW=1 跳过 raw 增量(默认跑,C-S3 实走需当日 raw) -set -e +# DAYS=5 增量回看天数(C-S3 实走需当日,5 天兜底停牌/补缺) +# STOCK_LIST=... 全市场 csv(默认 data_cache/stock_info) +# SKIP_RAW=1 跳 raw 增量 +# SKIP_QFQ=1 跳 qfq 增量 +set -uo pipefail # 不用 -e:单只失败不退(raw_redownload 内部已容错记 fail) + NAS=sanguo-nas -LOCAL=${STOCK_MOUNT:-/tmp/stock_dl} -export STOCK_MOUNT=$LOCAL +ROOT="$(cd "$(dirname "$0")/../.." && pwd)" +LOCAL=${STOCK_MOUNT:-$ROOT/data_cache/daily_update} # 持久目录(不进 /tmp,重启不丢) +SL=${STOCK_LIST:-$ROOT/data_cache/stock_info/stock_basic_info_raw_20260326_113530.csv} SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +DAYS=${DAYS:-5} +START=$(python3 -c "import datetime;print((datetime.date.today()-datetime.timedelta(days=$DAYS)).isoformat())") -mkdir -p "$LOCAL/logs/daily_update/progress" \ - "$LOCAL/A股数据/日线数据/daily" \ - "$LOCAL/A股数据/日线数据/raw" \ - "$LOCAL/minute_kline/15min" \ - "$LOCAL/A股数据/stock_info" \ - "$LOCAL/sanguo_vnpy/data" - -if [ "${SKIP_PULL:-0}" != "1" ]; then - echo "=== 1. rsync 拉 NAS 现有 → 本地(增量,首次慢后续快)===" - rsync -az "$NAS:/volume1/stock/A股数据/stock_info/" "$LOCAL/A股数据/stock_info/" || echo " stock_info pull warn" - rsync -az "$NAS:/volume1/stock/A股数据/日线数据/daily/" "$LOCAL/A股数据/日线数据/daily/" || echo " daily pull warn" - rsync -az "$NAS:/volume1/stock/A股数据/日线数据/raw/" "$LOCAL/A股数据/日线数据/raw/" || echo " raw pull warn" - rsync -az "$NAS:/volume1/stock/minute_kline/15min/" "$LOCAL/minute_kline/15min/" || echo " 15min pull warn" - rsync -az "$NAS:/volume1/stock/sanguo_vnpy/data/" "$LOCAL/sanguo_vnpy/data/" || echo " vnpy data pull warn" -fi - -echo "=== 2. 跑 v1 增量更新(STOCK_MOUNT=$LOCAL STOCK_LIMIT=${STOCK_LIMIT:-0})===" +mkdir -p "$LOCAL/raw" "$LOCAL/qfq" +echo "=== $(date) 每日增量 start=$START DAYS=$DAYS ===" cd "$SCRIPT_DIR" -python3 daily_all_update.py "$@" -if [ "${SKIP_RAW:-0}" != "1" ]; then - echo "=== 2.5 raw 增量(最近 5 天覆盖 raw_dir,C-S3 实走需当日 raw)===" - RAW_START=$(python3 -c "import datetime;print((datetime.date.today()-datetime.timedelta(days=5)).isoformat())") - SLEEP=0.5 python3 raw_redownload.py --all --start "$RAW_START" || echo " raw 增量 warn" +# 拉 stock_info(代码列表)若本地缺 +if [ ! -f "$SL" ]; then + mkdir -p "$(dirname "$SL")" + rsync -az "$NAS:/volume1/stock/A股数据/stock_info/" "$(dirname "$SL")/" || true fi -echo "=== 3. rsync 推 本地 → NAS ===" -rsync -az "$LOCAL/A股数据/日线数据/daily/" "$NAS:/volume1/stock/A股数据/日线数据/daily/" -rsync -az "$LOCAL/A股数据/日线数据/raw/" "$NAS:/volume1/stock/A股数据/日线数据/raw/" -rsync -az "$LOCAL/minute_kline/15min/" "$NAS:/volume1/stock/minute_kline/15min/" -rsync -az "$LOCAL/sanguo_vnpy/data/" "$NAS:/volume1/stock/sanguo_vnpy/data/" +# 1. raw 增量(C-S3 撮合真实价,adjustflag=3 / akshare adjust="") +if [ "${SKIP_RAW:-0}" != "1" ]; then + echo "=== 1. raw 增量(最近 $DAYS 天 → $LOCAL/raw)===" + STOCK_LIST="$SL" RAW_DIR="$LOCAL/raw" SLEEP=0.5 \ + python3 raw_redownload.py --all --start "$START" --adjust "" || echo " raw warn(单只失败已记)" +fi + +# 2. qfq 增量(C-S3 warmup 信号,无除权缺口) +if [ "${SKIP_QFQ:-0}" != "1" ]; then + echo "=== 2. qfq 增量(最近 $DAYS 天 → $LOCAL/qfq)===" + STOCK_LIST="$SL" RAW_DIR="$LOCAL/qfq" SLEEP=0.5 \ + python3 raw_redownload.py --all --start "$START" --adjust qfq || echo " qfq warn(单只失败已记)" +fi + +# 3. rsync 推 NAS(raw_dir + qfq_dir) +echo "=== 3. rsync → NAS ===" +rsync -az "$LOCAL/raw/" "$NAS:/volume1/stock/A股数据/日线数据/raw/" || echo " raw push warn" +rsync -az "$LOCAL/qfq/" "$NAS:/volume1/stock/A股数据/日线数据/qfq/" || echo " qfq push warn" echo "=== 完成 $(date) ==="