Files
FinDataHub d7d2a1e8ad chore(repo): 补齐长期未入库的核心源码、文档与本次复查修复
背景
- HEAD 长期停在 08-03 的安全审计提交,此后六周的工作全部只在工作区。
- 更严重的是部分源码从未进入过版本控制(非"改了没提交"):
    · Services/findatahub-core/  索引 0 条 —— 18 个核心模块(pipeline/gate/cleaner/
      db/cross_validator/health/retry…)全新 clone 拿不到
    · Services/findatahub-client/ 索引 0 条
    · App/Sources 磁盘 74 个 .swift、索引 54 —— 20 个未入库(AutoRecoveryManager、
      全套 Settings*Section、PowerSaver、MySQLOnDemandManager、DependencyScanner…)
  一次 `git clean -fd`、误删目录或磁盘故障即可不可恢复地丢失这些文件。

本提交内容
1. 补齐上述未跟踪源码、测试、文档与报告(Services/App/Docs/Tests/根报告)。
2. 纳入 .workbuddy/memory(项目知识)与 .github CI 配置。
3. 本次代码与架构复查的修复(详见下一段说明):
   - Scripts/bin/common.py         PidManager.status 改 split(":", 1),修复时间戳被截断到整点
   - Scripts/bin/db_pool.py        取连接加超时、归还前 rollback、失败归还池位、双检锁初始化
   - Scripts/bin/newsflash_backend.py  _query_all 改 try/finally 无条件归还连接
   - Scripts/bin/newsflash_collect.py 新增 _install_crash_handlers(faulthandler + excepthook)
   - tushare_fetcher/core/fetcher.py  _fetch_static 增量走 upsert,仅全量快照才 replace
   - tushare_fetcher/scripts/tushare_sync.sh 银层迁移补 stock_weekly/stock_monthly;
                                     月度增加分红按报告期全量刷新
   - kuaixun-service/extend/content_enricher.py 禁用自动重定向 + 逐跳 SSRF 校验
   - App/.../AutoRecoveryManager.swift 反复故障改告警不熔断(避免拉长数据空窗)
   - 新增 Scripts/bin/repair_dividend_history.py(分红历史修复,按报告期分页幂等 upsert)
   - 新增 Docs/repro/*(两个可运行的缺陷复现脚本)
   - 补齐 6 个文件共 20 条回归用例(均做过证伪:旧实现下必然失败)

安全
- 已确认未纳入任何凭据:Services/tushare_fetcher/.env 被其 .gitignore 覆盖;
  ~/.config/findatahub/env(0600)在仓库外。

验证
- Python 测试 1074 passed(Scripts/bin 207 / core 105 / tushare 174 / kuaixun 405 / akshare 183)
- Swift 经 `swift build --disable-sandbox` 编译通过,产物 v1.5.2 已部署
2026-09-18 22:37:55 +08:00

260 lines
17 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!-- Generated by Trae Work -->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>FinDataHub 项目实施分析报告</title>
<style>
:root{--bg:#f8fafc;--bg2:#fff;--ink:#1e293b;--muted:#64748b;--rule:#e2e8f0;--accent:#2563eb;--accent2:#7c3aed;--code-bg:#f1f5f9;--success:#059669;--warning:#d97706}
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
html{font-size:16px;scroll-behavior:smooth}
body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei',sans-serif;font-size:15px;line-height:1.75;color:var(--ink);background:var(--bg)}
.container{max-width:1000px;margin:0 auto;padding:0 2rem}
@media(max-width:600px){.container{padding:0 1rem}}
.cover{text-align:center;padding:4rem 2rem 2.5rem;background:linear-gradient(135deg,var(--bg2)0%,var(--bg)100%);border-bottom:1px solid var(--rule)}
.cover .badge{display:inline-block;font-size:.75rem;font-weight:700;text-transform:uppercase;letter-spacing:.1em;color:var(--accent);background:var(--accent)11;padding:.3rem 1rem;border-radius:99px;margin-bottom:1.5rem}
.cover h1{font-size:2.2rem;font-weight:700;line-height:1.3;margin-bottom:.5rem}
.cover .sub{font-size:1rem;color:var(--muted);max-width:600px;margin:0 auto}
.cover .meta{font-size:.85rem;color:var(--muted);margin-top:1rem}
main{padding:2rem 0 4rem}
.metrics{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:1rem;margin:1.5rem 0}
.metric{background:var(--bg2);border:1px solid var(--rule);border-radius:10px;padding:1.25rem;text-align:center}
.metric .num{font-size:2rem;font-weight:700;color:var(--accent);line-height:1.2}
.metric .lbl{font-size:.8rem;color:var(--muted);margin-top:.25rem}
h2{font-size:1.5rem;font-weight:700;margin-top:3rem;margin-bottom:1rem;padding-bottom:.5rem;border-bottom:2px solid var(--rule)}
h3{font-size:1.15rem;font-weight:700;margin-top:2rem;margin-bottom:.75rem}
.table-wrap{overflow-x:auto;margin:1rem 0}
table{width:100%;border-collapse:collapse;font-size:.9em;border:1px solid var(--rule)}
thead th{background:var(--code-bg);font-weight:700;text-align:left;padding:.5rem .8rem;border-bottom:2px solid var(--rule);font-size:.8em;text-transform:uppercase;letter-spacing:.05em;color:var(--muted)}
tbody td{padding:.45rem .8rem;border-bottom:1px solid var(--rule);vertical-align:top}
tbody tr:hover{background:var(--accent)04}
.callout{padding:.6rem 1rem;border-radius:6px;margin:1rem 0;border-left:4px solid var(--accent);background:var(--accent)08;font-size:.9em}
.callout.success{border-left-color:var(--success);background:var(--success)08}
.tag{display:inline-block;font-size:.65rem;font-weight:700;padding:.1rem .4rem;border-radius:3px;text-transform:uppercase;letter-spacing:.05em}
.tag-ok{background:var(--success)18;color:var(--success)}
.tag-wip{background:var(--warning)18;color:var(--warning)}
.chart-figure{margin:2rem 0}
.chart-figure figcaption{font-size:.85rem;font-weight:600;color:var(--ink);margin-bottom:.75rem}
.chart-row{display:grid;grid-template-columns:1fr 1fr;gap:1.5rem}
@media(max-width:700px){.chart-row{grid-template-columns:1fr}}
.card-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:1rem;margin:1rem 0}
.card{background:var(--bg2);border:1px solid var(--rule);border-radius:10px;padding:1.25rem}
.card h4{margin-top:0}
.card p{font-size:.9em;color:var(--muted);margin:0}
footer{padding:3rem 2rem;border-top:1px solid var(--rule);text-align:center}
footer p{font-size:.85rem;color:var(--muted)}
</style>
</head>
<body>
<header class="cover">
<div class="badge">Implementation Report</div>
<h1>FinDataHub 项目实施分析报告</h1>
<p class="sub">从数据采集到数据消费 — 三层架构全链路实施状态</p>
<p class="meta">2026-08-09 · v1.0 · 全部 P1-P5 阶段</p>
</header>
<main class="container">
<!-- ═══════════ 总览 ═══════════ -->
<h2>一、实施总览</h2>
<div class="metrics">
<div class="metric"><div class="num">14.7M</div><div class="lbl">数据总行数</div></div>
<div class="metric"><div class="num">5,751</div><div class="lbl">股票覆盖</div></div>
<div class="metric"><div class="num">2</div><div class="lbl">数据源</div></div>
<div class="metric"><div class="num">0.85</div><div class="lbl">质量评分</div></div>
<div class="metric"><div class="num">6</div><div class="lbl">微服务</div></div>
<div class="metric"><div class="num">100%</div><div class="lbl">P1-P4 完成</div></div>
</div>
<div class="table-wrap">
<table>
<thead><tr><th>阶段</th><th>内容</th><th>状态</th><th>关键指标</th></tr></thead>
<tbody>
<tr><td><strong>P1</strong></td><td>采集层:双源交叉验证 + AKShare 修复 + 北交所重拉</td><td><span class="tag tag-ok">DONE</span></td><td>匹配率 96-100%</td></tr>
<tr><td><strong>P2</strong></td><td>预处理层:7 步 Pipeline + 4 级门控 + 策略画像</td><td><span class="tag tag-ok">DONE</span></td><td>质量分 0.85</td></tr>
<tr><td><strong>P3</strong></td><td>使用层:SDK 11 方法 + API 14 端点</td><td><span class="tag tag-ok">DONE</span></td><td>4 层递进接入</td></tr>
<tr><td><strong>P4</strong></td><td>AI 接入:Skills + MCP 7 工具</td><td><span class="tag tag-ok">DONE</span></td><td>自然语言直达数据</td></tr>
<tr><td><strong>P5</strong></td><td>云端扩展:阿里云 MySQL 同步 + 版本管理 + 血缘追踪</td><td><span class="tag tag-ok">DONE</span></td><td>14.8GB 全量同步</td></tr>
</tbody>
</table>
</div>
<!-- ═══════════ 数据规模 ═══════════ -->
<h2>二、数据规模与质量</h2>
<div class="card-grid">
<div class="card"><h4>stock_daily</h4><p>12,670,167 行 · 5,751 只股票 · 2021-01-04 ~ 2026-08-07</p></div>
<div class="card"><h4>stock_weekly</h4><p>1,681,905 行 · 质量分 0.85</p></div>
<div class="card"><h4>stock_monthly</h4><p>395,487 行 · 质量分 0.85</p></div>
<div class="card"><h4>fina_indicator</h4><p>244,601 行 · 最新 ROE=2.65%</p></div>
<div class="card"><h4>stock_basic</h4><p>5,549 行 · 全市场股票基础信息</p></div>
<div class="card"><h4>辅助表(6 张)</h4><p>_data_issues / _table_meta / _retry_queue 等</p></div>
</div>
<figure class="chart-figure"><figcaption>图 1:本地数据规模(行数)</figcaption><div id="chart-scale" style="width:100%;min-height:300px"></div></figure>
<div class="chart-row">
<figure class="chart-figure"><figcaption>图 2:各板块股票分布</figcaption><div id="chart-market" style="width:100%;min-height:320px"></div></figure>
<figure class="chart-figure"><figcaption>图 3:阿里云 RDS 数据分布 (MB)</figcaption><div id="chart-rds" style="width:100%;min-height:320px"></div></figure>
</div>
<!-- ═══════════ 交叉验证 ═══════════ -->
<h2>三、双源交叉验证</h2>
<figure class="chart-figure"><figcaption>图 4:TuShare vs AKShare 匹配率历史趋势</figcaption><div id="chart-cv" style="width:100%;min-height:300px"></div></figure>
<div class="table-wrap">
<table>
<thead><tr><th>日期</th><th>对比对数</th><th>匹配率</th><th>差异</th><th>差异字段分布</th></tr></thead>
<tbody>
<tr><td>2026-08-07</td><td>5,535</td><td>96.1%</td><td>216</td><td>pct_chg(217) / pre_close(101)</td></tr>
<tr><td>2026-07-01</td><td>5,511</td><td>99.8%</td><td>13</td><td>pct_chg(12) / pre_close(1)</td></tr>
<tr><td>2025-01-02</td><td>5,331</td><td>99.9%</td><td>3</td><td>pct_chg(2) / vol(1)</td></tr>
<tr><td>2024-01-02</td><td>5,241</td><td>99.9%</td><td>3</td><td>pre_close(3)</td></tr>
<tr><td>2023-01-03</td><td>4,927</td><td>96.7%</td><td>161</td><td>pct_chg(155) / pre_close(6)</td></tr>
</tbody>
</table>
</div>
<p>差异主要集中在<strong>涨跌幅(pct_chg)和昨收价(pre_close)</strong>两个字段,成交量/成交额差异极小(共 6 条)。最新日(2026-08-07)匹配率偏低至 96.1%,可能是某数据源更新时序延迟导致。</p>
<!-- ═══════════ 数据质量 ═══════════ -->
<h2>四、数据质量校验</h2>
<div class="table-wrap">
<table>
<thead><tr><th>检查项</th><th>结果</th><th>实现</th></tr></thead>
<tbody>
<tr><td>OHLC 关系违规</td><td><strong>0 行</strong></td><td><code>cleaner.py</code> — 自动修正 high<low / open>high / close>high</td></tr>
<tr><td>价格为负</td><td><strong>0 行</strong></td><td><code>gate.py</code> — Gate3 BLOCK 拦截</td></tr>
<tr><td>AKShare 成交额异常</td><td>637 万行修正</td><td><code>cleaner._fix_akshare_broken_amount</code></td></tr>
<tr><td>科创板 vol 单位</td><td>688/689 ÷100</td><td><code>cleaner._fix_akshare_star_vol</code></td></tr>
<tr><td>AKShare 涨跌幅重算</td><td>从 close/pre_close 推导</td><td><code>cleaner._recompute_akshare_pct_chg</code></td></tr>
<tr><td>AKShare pre_close 时效</td><td>253,513 行更新</td><td><code>fix_akshare_preclose.py</code></td></tr>
<tr><td>北交所数据补齐</td><td>333 只 / 186,460 行</td><td><code>em_fetch.py</code> — 新浪源直连</td></tr>
</tbody>
</table>
</div>
<!-- ═══════════ 模块清单 ═══════════ -->
<h2>五、完整模块清单</h2>
<div class="table-wrap">
<table>
<thead><tr><th>层级</th><th>模块</th><th>文件</th><th>行数</th><th>职责</th></tr></thead>
<tbody>
<tr><td rowspan="4"><strong>L1 采集</strong></td><td>tushare_fetcher</td><td><code>Services/tushare_fetcher/</code></td><td>~800</td><td>TuShare Pro API 封装 + 幂等写入</td></tr>
<tr><td>akshare_fetcher</td><td><code>Services/akshare_fetcher/</code></td><td>~1200</td><td>AKShare 腾讯/东财/新浪多接口路由</td></tr>
<tr><td>DatabaseManager</td><td><code>tushare_fetcher/core/db.py</code><br><code>akshare_fetcher/core/db.py</code></td><td>50+60</td><td>继承 BaseDatabaseManager,覆写配置路径</td></tr>
<tr><td>RetryManager</td><td><code>findatahub_core/retry.py</code></td><td>~80</td><td>指数退避 + 熔断 + 失败队列</td></tr>
<tr><td rowspan="8"><strong>L2 预处理</strong></td><td>DataCleaner</td><td><code>findatahub_core/cleaner.py</code></td><td>~200</td><td>5 个子步骤(类型修正/去重/字段清洗/OHLC/AK修复)</td></tr>
<tr><td>DataImputer</td><td><code>findatahub_core/imputer.py</code></td><td>~80</td><td>3 种策略(ffill/linear/median)</td></tr>
<tr><td>OutlierDetector</td><td><code>findatahub_core/outlier.py</code></td><td>~70</td><td>IQR/MAD 检测 + 标记列</td></tr>
<tr><td>StatsAnalyzer</td><td><code>findatahub_core/stats.py</code></td><td>~100</td><td>描述性统计 + 缺失率 + 分布特征</td></tr>
<tr><td>CorrelationAnalyzer</td><td><code>findatahub_core/correlation.py</code></td><td>~120</td><td>Pearson/Spearman + 冗余检测</td></tr>
<tr><td>PCAProcessor</td><td><code>findatahub_core/pca.py</code></td><td>~90</td><td>PCA 降维 + Normalizer(3 种)</td></tr>
<tr><td>QualityGate</td><td><code>findatahub_core/gate.py</code></td><td>~90</td><td>4 级门控 + BLOCK/WARN/INFO</td></tr>
<tr><td>CrossValidator</td><td><code>findatahub_core/cross_validator.py</code></td><td>~150</td><td>OHLCV 8 字段双源对比</td></tr>
<tr><td rowspan="4"><strong>L3 使用</strong></td><td>Python SDK</td><td><code>findatahub/client.py</code></td><td>~330</td><td>11 个方法(daily/weekly/monthly/fina/search/export 等)</td></tr>
<tr><td>REST API</td><td><code>findatahub/api.py</code></td><td>~270</td><td>14 个端点(含健康监控)</td></tr>
<tr><td>Skills 层</td><td><code>findatahub/skill.md</code></td><td>—</td><td>5 表 schema + 查询示例</td></tr>
<tr><td>MCP 服务</td><td><code>findatahub/mcp_server.py</code></td><td>~210</td><td>7 个 MCP 工具(搜索/日线/财务/质量/统计等)</td></tr>
<tr><td rowspan="4"><strong>基础设施</strong></td><td>Pipeline</td><td><code>findatahub_core/pipeline.py</code></td><td>~340</td><td>DAG 编排 + 并行执行 + 反馈回路</td></tr>
<tr><td>BaseDatabaseManager</td><td><code>findatahub_core/db.py</code></td><td>~280</td><td>连接池 + 幂等 upsert + safe_identifier</td></tr>
<tr><td>ProfileLoader</td><td><code>findatahub_core/profile.py</code></td><td>~50</td><td>YAML 策略画像加载(3 种)</td></tr>
<tr><td>HealthMonitor</td><td><code>findatahub_core/health.py</code></td><td>~60</td><td>API 耗时/成功率 + REST 端点</td></tr>
<tr><td rowspan="3"><strong>P5 云端</strong></td><td>CloudSyncWorker</td><td><code>flows/cloud_sync.py</code></td><td>~180</td><td>全量 + 增量同步 to RDS</td></tr>
<tr><td>数据版本</td><td><code>_data_versions</code></td><td>—</td><td>版本号标记 + 回滚查询</td></tr>
<tr><td>数据血缘</td><td><code>_data_lineage</code></td><td>—</td><td>Pipeline Step 自动记录行数/耗时</td></tr>
</tbody>
</table>
</div>
<!-- ═══════════ 架构重构 ═══════════ -->
<h2>六、架构重构摘要</h2>
<div class="table-wrap">
<table>
<thead><tr><th>重构项</th><th>效果</th><th>状态</th></tr></thead>
<tbody>
<tr><td>删除 alpha-common 废弃模块</td><td>减少 4 文件,消除混淆</td><td><span class="tag tag-ok">DONE</span></td></tr>
<tr><td>两个 fetcher db.py 继承 BaseDatabaseManager</td><td>670 行 → 110 行(减少 83%)</td><td><span class="tag tag-ok">DONE</span></td></tr>
<tr><td>bootstrap.py 移除反向依赖</td><td>核心层 0 import fetcher</td><td><span class="tag tag-ok">DONE</span></td></tr>
<tr><td>FetchStepProtocol 协议</td><td>采集器通过接口注入 Pipeline</td><td><span class="tag tag-ok">DONE</span></td></tr>
<tr><td>pyproject.toml 补声明</td><td>findatahub-client → findatahub-core</td><td><span class="tag tag-ok">DONE</span></td></tr>
<tr><td>Docs 文档整理</td><td>10 文件 → 3 分类目录 + 3 README</td><td><span class="tag tag-ok">DONE</span></td></tr>
<tr><td>Tests/ 提升到根级</td><td>5 端到端用例全部通过</td><td><span class="tag tag-ok">DONE</span></td></tr>
<tr><td>设计文档合并</td><td>14 文档 → 10 (减少 29%)</td><td><span class="tag tag-ok">DONE</span></td></tr>
</tbody>
</table>
</div>
<!-- ═══════════ 目录结构 ═══════════ -->
<h2>七、最终目录结构</h2>
<pre>FinDataHub/
├── App/ # macOS SwiftUI 桌面应用(29 文件)
├── Docs/ # 文档中心
│ ├── README.md # 总索引
│ ├── pipeline/ # 数据管道架构
│ │ ├── findatahub-data-pipeline.html # 架构设计 + 规范(合并)
│ │ ├── rate_limit_pull_plan.md
│ │ └── EXECUTION_PLAN.md # 已归档
│ ├── macos/ # macOS App 设计
│ │ ├── DESIGN.md # HIG 设计 + Liquid Glass(合并)
│ │ └── DEVLOG.md
│ └── tracking/ # 项目管理
│ └── TODO.md # 待办 + P1-P4 完成记录(合并)
├── Services/ # 6 个微服务
│ ├── tushare_fetcher/ # TuShare 采集(db.py 50 行)
│ ├── akshare_fetcher/ # AKShare 采集(db.py 60 行)
│ ├── findatahub-core/ # 核心预处理(18 模块 + 6 flows)
│ ├── findatahub-client/ # SDK + API + MCP
│ ├── kuaixun-service/ # 快讯 API
│ └── kuaixun-frontend/ # 快讯 Vue.js 前端
├── Tests/ # 跨层集成测试(5 用例)
├── Scripts/ # 运维部署脚本
└── implementation-report/ # 本报告</pre>
<!-- ═══════════ 依赖方向 ═══════════ -->
<h2>八、架构合规状态</h2>
<div class="callout success">
<strong>核心铁律:依赖单向流动(采集层 → 核心层 → 使用层)</strong><br>
✅ 12 个核心模块 0 反向依赖<br>
✅ FetchStepProtocol 协议(依赖倒置)<br>
✅ pyproject.toml 全部声明<br>
✅ 两个 fetcher db.py 继承 BaseDatabaseManager<br>
✅ bootstrap.py 使用 BaseDatabaseManager 直连
</div>
<div class="metrics">
<div class="metric"><div class="num">0</div><div class="lbl">反向依赖</div></div>
<div class="metric"><div class="num">6</div><div class="lbl">Service(删1)</div></div>
<div class="metric"><div class="num">3</div><div class="lbl">策略画像</div></div>
<div class="metric"><div class="num">14.8GB</div><div class="lbl">RDS 同步</div></div>
</div>
</main>
<footer>
<p>FinDataHub · Implementation Analysis Report · 2026-08-09 · v1.0</p>
</footer>
<script src="./_shared/js/echarts.min.js"></script>
<script src="assets/charts.js"></script>
</body>
</html>