Files
sanguo_vnpy_v2/docs/archive/data/2026-07-23-akshare-low-freq-schtask.md
T
claude_dev c3e53fbef3 docs(data): 归档数据层验证产物 + 数据层总览README
- scripts/data_platform/_archive/legacy/: 归档20个独立探针/诊断/旧降级脚本(零引用验证)
- docs/archive/data/: 归档17个数据相关旧设计/plan/report(保留fusion spec作深读)
- docs/data-platform/README.md: 数据层单一权威记录(8节:架构/布局/源/管线/铁律/API/缺口/待办)
- 删除 _mootdx_depth_result.txt
- Phase2待办: 15m灌库链+旧回填import链(有测试/wrapper依赖,VPS schtask确认后归档)
2026-07-29 10:11:38 +08:00

12 KiB
Raw Blame History

akshare 低频任务 schtask 部署 Plan (spec §14.5)

For agentic workers: REQUIRED SUB-SKILL: superpowers:subagent-driven-development / executing-plans。本 plan 自包含(实测现状+脚本能力+VPS访问),fresh agent 可直接执行。

Goal: 部署 spec §14.5 akshare/index 低频 schtask — A 三表/估值增量 + B 成份股月度 + C 事件类 7 种。方案A 数据层(dbbardata/constituent_unified/valuation_baostock)的使用层配套,补全 LocalUnifiedProvider 依赖的静态数据源。

Architecture: 复用 akshare_static_download.py(16类/marker断点/4模式)+ baostock_constituent_download.py;改 merge_constituent.py/migrate_constituent.py 可重跑;按 akshare per-stock 全量慢 + 东财限流,拆多 schtask(日频/季频/月频)。

Tech Stack: Python 3.10, akshare, baostock, sqlite3, Windows schtasks

Global Constraints(铁律)

  • akshare: 单线程 0.8s sleep / 30s 超时 / 断路器(连30 failed exit) / marker 断点 / unset proxyakshare_static_download.py 已内置;东财限流严,per-stock 全量慢,夜间跑
  • baostock: 单进程单登录 48000/天,不并发(防黑名单)
  • staging→验证→合并(成份股 B,用户铁律:下载质量不可控,不直接写主库)
  • VPS: ssh alias = 49.232.102.198(IP 即 alias,User Administrator,key id_ed25519);C:\Python310\python.exe -X utf8;schtasks /create /ru SYSTEM /rl HIGHEST /sc daily|monthly;Windows ssh 引号地狱 → 脚本 scp + ssh python 跑最稳
  • dbbardata UNIQUE 不破坏;constituent_unified 治偏差
  • 直连不走代理(schtask wrapper 开头 unset http_proxy https_proxy all_proxy)

实测现状(2026-07-23 probe_akshare_status.py)

  • static/(C:\sanguo_vnpy_v2\data\static\): balance/income/cashflow/valuation/financial_abstract 各 5530 parquet,停 2026-07-22 18:25(sanguo-bs-akshare disabled 前最后一次);provider fundamentals 依赖,要续更
  • events/: 全 MISSING(龙虎榜/北向/两融/解禁/大宗/可转债/研报从未采集)
  • constituent_unified: 7110 行 = baostock 2938(000016:195/000300:940/000905:1803) + akshare_cni 1172(深证 399001:702/399005:145/399006:175/399330:150) + akshare_csindex 3000(000852:1000/932000:2000);静态,月度更新 schtask 无
  • schtask 状态: sanguo-bs-akshare / sanguo-index / sanguo-index-hist 全无(方案A stop_all_data_schtasks.ps1 清了)
  • akshare_static_download.py 16 类分 5 组:
    • PER_STOCK(5500股循环,unit={symbol}_{type}): valuation/northbound/share_capital/balance/income/cashflow/financial_abstract
    • TOP_HOLDERS(per-stock×period): top_holders
    • PER_DATE(每交易日,unit={date}_{type}): dragon_tiger/block_trade/margin_sse/restricted
    • PER_PERIOD(报告期,unit={period}_{type}): forecast/express
    • ONE_SHOT: index_const/industry
    • marker 是 symbol 级(非 period 级)→ 三表/估值要更新新数据必须 --force(否则 marker 跳过永不更新)
  • merge_constituent.py 不可重跑: ALTER TABLE bs_index_constituent RENAME TO bs_index_constituent_old 只能一次(_old 已存在);无 DROP/REPLACE constituent_unified
  • existing wrappers(参考模式): bs_eod_wrapper.ps1 / xt_eod_wrapper.ps1(unset proxy + log + 调 python);register_schtasks.ps1(schtasks /create 模板)

schtask 清单(方案A §14.5 适配,按频率拆)

schtask 频率 时间 脚本 内容
sanguo-ak-eod daily 19:00 ak_eod_wrapper.ps1 valuation + financial_abstract --force(日频,5500×2×0.8s≈2.2h 夜间)
sanguo-ak-quarter monthly(财报季 5/9/11 月+年报4月) 周末 02:00 ak_quarter_wrapper.ps1 balance + income + cashflow + forecast + express --force(季频,5500×3×0.8≈2.2h)
sanguo-ak-events daily 19:30 ak_events_wrapper.ps1 dragon_tiger + block_trade + margin_sse + restricted --start today --end today(per-date 日频,4 unit 快)
sanguo-ak-stock weekly 周六 03:00 ak_stock_wrapper.ps1 northbound + share_capital + top_holders(per-stock 慢,周频)
sanguo-index monthly 19:50 index_monthly_wrapper.ps1 成份股 3 源 + merge(B)

File Structure

  • Modify: scripts/data_platform/merge_constituent.py(可重跑: DROP/REPLACE 替代 RENAME)
  • Modify: scripts/data_platform/migrate_constituent.py(可重跑: staging 隔离 + DROP staging 重建)
  • Create: scripts/data_platform/ak_eod_wrapper.ps1 / ak_quarter_wrapper.ps1 / ak_events_wrapper.ps1 / ak_stock_wrapper.ps1(4 个 akshare wrapper)
  • Create: scripts/data_platform/index_monthly_wrapper.ps1(B 成份股 3 源编排)
  • Create: scripts/data_platform/register_akshare_schtasks.ps1(注册 5 schtask)
  • Create: scripts/data_platform/verify_akshare_e2e.py(验证全部)
  • Test: tests/portfolio/test_merge_constituent_rerun.py(B 改造 TDD)

Task A: 三表/估值增量(2 schtask)

Files: Create 4 akshare wrapper + register; 复用 akshare_static_download.py(不改)。

  • A1: ak_eod_wrapper.ps1(日频估值/财务摘要)
# unset proxy + 调 akshare_static_download.py --types valuation,financial_abstract --force
$env:http_proxy=""; $env:https_proxy=""; $env:all_proxy=""
cd C:\sanguo_vnpy_v2
C:\Python310\python.exe -X utf8 scripts\data_platform\akshare_static_download.py `
  --types valuation,financial_abstract --force `
  *>> C:\sanguo_vnpy_v2\data\ak_eod.log
  • A2: ak_quarter_wrapper.ps1(季频三表+预告/快报,财报季)— 同上 --types balance,income,cashflow,forecast,express --force
  • A3: 验证 A — scp wrapper + 手动跑 --limit 5 确认 valuation parquet 更新今日:
scp scripts/data_platform/ak_eod_wrapper.ps1 49.232.102.198:'C:/sanguo_vnpy_v2/scripts/data_platform/'
ssh 49.232.102.198 'cd /d C:\sanguo_vnpy_v2 && C:\Python310\python.exe -X utf8 scripts\data_platform\akshare_static_download.py --types valuation --force --limit 3'
# 验 static/valuation/<code>_valuation.parquet mtime = 今日
  • A4: 注册 schtask(register_akshare_schtasks.ps1 含 sanguo-ak-eod daily 19:00 + sanguo-ak-quarter monthly)

Task B: 成份股月度(sanguo-index)— 代码改造 TDD

Files: Modify merge_constituent.py + migrate_constituent.py; Create index_monthly_wrapper.ps1; Test test_merge_constituent_rerun.py

  • B1: 写失败测试 — merge_constituent 可重跑
# tests/portfolio/test_merge_constituent_rerun.py
def test_merge_constituent_rerun_twice(tmp_path):
    """merge_constituent 跑两次不崩(第二次 DROP 重建,不 RENAME 已 _old 的表)。"""
    db = tmp_path / "t.db"; c = sqlite3.connect(str(db))
    # 造 constituent_unified + bs_index_constituent_old(已存在,_old 状态)
    c.execute("CREATE TABLE constituent_unified(index_code,code,source,in_current,was_removed)")
    c.execute("CREATE TABLE constituent_unified_staging(index_code,code,source,in_current,was_removed)")
    c.execute("CREATE TABLE bs_index_constituent_old(code,date)")  # _old 已存在
    c.executemany("INSERT INTO constituent_unified_staging VALUES(?,?,?,?,?)",
                  [("000300","600519","baostock",1,0)])
    c.commit(); c.close()
    # 跑两次
    import scripts.data_platform.merge_constituent as m  # 或函数级 import
    m.merge(str(db))   # 第一次: staging→unified(DROP 旧 unified 重建)
    m.merge(str(db))   # 第二次: 不崩, unified 仍 1 行
    c = sqlite3.connect(str(db))
    assert c.execute("SELECT COUNT(*) FROM constituent_unified").fetchone()[0] == 1
  • B2: 改 merge_constituent.py 可重跑 — 把 ALTER TABLE bs_index_constituent RENAME TO _old(只能一次)改为:staging→DROP TABLE IF EXISTS constituent_unifiedCREATE constituent_unified AS SELECT FROM staging。bs_index_constituent_old 已存在不碰。幂等。

  • B3: 改 migrate_constituent.py 可重跑 — staging 表 DROP IF EXISTS constituent_unified_staging 重建(每次重新聚合 baostock 988 时点 + akshare cni union + csindex),不依赖上次状态。

  • B4: index_monthly_wrapper.ps1(3 源编排)

$env:http_proxy=""; $env:https_proxy=""; $env:all_proxy=""
cd C:\sanguo_vnpy_v2
# 1. baostock 300/500/50 最新快照(单进程)
C:\Python310\python.exe -X utf8 scripts\data_platform\baostock_constituent_download.py --start 2026-01-01
# 2. akshare cni 深证 + csindex 中证(复用 P0 脚本 index_const_hist_download 或 akshare_static_download --types index_const)
C:\Python310\python.exe -X utf8 scripts\data_platform\akshare_constituent_download.py
# 3. migrate + merge(可重跑版)
C:\Python310\python.exe -X utf8 scripts\data_platform\migrate_constituent.py
C:\Python310\python.exe -X utf8 scripts\data_platform\merge_constituent.py

(注:akshare_constituent_download.py 若不存在,从 akshare_static_download.py --types index_const 或 P0 的 index_const_hist_download.py 复用;执行 agent 确认现有脚本)

  • B5: 验证 B — 手动跑 wrapper,确认 constituent_unified 行数 ≥ 7110,source 含 baostock/akshare_cni/akshare_csindex,跑两次不崩。
  • B6: 注册 sanguo-index monthly 19:50

Task C: 事件类(per-date 日频 + per-stock 周频)

Files: Create ak_events_wrapper.ps1 + ak_stock_wrapper.ps1(已在 A 的 register 注册)。

  • C1: ak_events_wrapper.ps1(per-date 日频)— --types dragon_tiger,block_trade,margin_sse,restricted --start {today} --end {today}。每日 4 类×1 unit,快。落 events/{type}/{date}_{type}.parquet
  • C2: ak_stock_wrapper.ps1(per-stock 周频慢)— --types northbound,share_capital,top_holders --force。5500×3 慢,周六 03:00。
  • C3: 可转债/研报(spec §14.2 列但 akshare_static_download.py 16 类无对应 fetcher) — 评估:若 akshare 有 bond_zh_hs_cov_min/stock_research_info_em 接口,加 fetcher;否则 N/A 标注使用说明。执行 agent 确认 akshare 接口可用性,不可用则跳过并在 verify 标注。
  • C4: 验证 C — 手动跑 events wrapper --start today --end today,确认 events/dragon_tiger/{today}_dragon_tiger.parquet 生成。

Task D: 注册 + E2E

  • D1: register_akshare_schtasks.ps1 — 注册 5 schtask(sanguo-ak-eod/ak-quarter/ak-events/ak-stock/index),/create /ru SYSTEM /rl HIGHEST,verify 段 schtasks /query 确认 Status=Ready。
  • D2: verify_akshare_e2e.py — 验证全部:
    • static/valuation 最新 mtime = 近日
    • events/dragon_tiger 有 parquet
    • constituent_unified ≥ 7110 + 3 source
  • D3: 更新 memory + 使用说明data-fusion-design-finalized 的"剩余待办 akshare schtask"标完成;docs/portfolio_local_unified_provider.md 事件类从 N/A 更新。

Self-Review

  1. spec §14.5 覆盖: sanguo-bs-akshare(三表+事件)→ 拆 ak-eod/ak-quarter/ak-events/ak-stock(频率适配);sanguo-index 月度 → B。✓
  2. provider 依赖: valuation/balance/income/cashflow/financial_abstract(LocalUnifiedProvider.get_fundamentals_df)→ A 覆盖。✓
  3. 限流现实: per-stock --force 全量慢,日频 valuation 2.2h / 季频三表 2.2h,夜间 + 周末 schtask。events per-date 日频快。✓
  4. B 可重跑: merge DROP 重建幂等,migrate staging 隔离。TDD 跑两次不崩。✓
  5. 风险: akshare 东财封 IP(per-stock 全量)→ wrapper 内置断路器 + sleep;财报季触发 ak-quarter(/sc monthly 指定月或手动);可转债/研报接口待确认(C3)。

Execution Handoff

Plan saved to docs/superpowers/plans/2026-07-23-akshare-low-freq-schtask.md。compact 后新 session 派 Sub Agent 执行(参考 LocalUnifiedProvider 模式:Task A→B→C→D,每 task 验证 + commit)。

关联文档/memory

  • spec: docs/superpowers/specs/2026-07-21-data-source-fusion-design.md §14.5
  • memory: data-fusion-design-finalized(方案A)/ local-unified-provider-complete(使用层)/ vps-local-data-layout / baostock-concurrent-blacklist / schtasks-system-bat-gotchas
  • VPS 访问: ssh 49.232.102.198,见 memory windows-vps-access