worklog

2026-02-24 工作日志:自动化管道 + 部署 + 代码整理

今天的核心工作是把项目从”本地能跑”推进到”自动化运行、线上可访问”。包括修复数据抓取逻辑、搭建 GitHub Actions 自动更新管道、清除代码中的密钥、推送到新仓库、以及 Streamlit Cloud 部署适配。


一、fd_share 抓取逻辑修复

问题daily_update.py 中 ETF 份额(fd_share)的抓取逻辑有设计缺陷。当昨天的 fd_share 拉不到时,代码会偷偷用更早日期的缓存值来替代,而不是像其他数据一样触发重试。

分析:我们用的是 T-1(昨天)的 fd_share 来计算今天的 ETF 换手率。到了 17:30 去拉昨天的数据,正常情况下肯定有。如果拉不到,说明接口出了问题,应该等一等再重试,而不是拿更旧的数据凑合。用旧数据算出来的换手率是不准的,会影响交易信号的判断。

修复内容


二、从 Windows 定时任务迁移到 GitHub Actions

背景:之前计划用 Windows Task Scheduler(update_daily.bat)每天 17:30 触发数据更新。但项目要上传到 GitHub 公开仓库,未来通过云端访问看板,本地定时任务就不合适了——电脑关机就跑不了。

方案对比

方案 优点 缺点
Windows Task Scheduler 简单直接 依赖本地电脑开机
Vercel Cron 跟仓库绑定 超时上限太短(免费10秒/Pro 300秒),无持久文件系统,完全不适合我们有无限重试的脚本
GitHub Actions 免费(public 仓库无限制)、最长可跑 6 小时、可自动 commit push 回仓库 需要写 workflow 配置文件

最终选择 GitHub Actions,创建了 .github/workflows/daily_update.yml

触发条件:
  - 定时:每周一至周五 UTC 09:30(= 北京时间 17:30)
  - 手动:在 GitHub 仓库 Actions 页面点击 Run workflow(可指定日期)

执行流程:
  1. Checkout 仓库代码
  2. 安装 Python 3.11 + requirements.txt 依赖
  3. 运行 python daily_update.py
  4. 如果有数据变更,自动 git commit & push 回仓库

重试上限:最初加了 RETRY_MAX_TOTAL=10 的环境变量来限制 CI 中的重试次数,后来确认 public 仓库 GitHub Actions 完全免费、无分钟数限制,就去掉了上限。现在 CI 和本地一样,无限重试直到成功,最多跑到 6 小时 job 超时。

测试:手动触发了一次 workflow,31 秒内全部通过。因为 20260224 的数据在之前本地测试时已经更新过,防重复逻辑生效,显示”已成功更新,跳过”。


三、Token 安全处理

项目要放到 public 仓库,代码里不能留 API 密钥。

改动

密钥存储

全面扫描确认:用 ripgrep 搜索所有 .py 文件,确认代码中零 token 残留。


四、推送到新的 GitHub 仓库

新仓库https://github.com/JerryZ8889/CSI500(public)

操作

.gitignore 配置:排除了以下不该上传的文件:


五、Streamlit Cloud 部署适配

5.1 中文字体兼容

问题:dashboard.py 里 matplotlib 图表用 SimHei 字体显示中文。SimHei 只有 Windows 系统自带,Streamlit Cloud 的 Linux 服务器上没有这个字体,中文会全部显示为方块。

解决

  1. 创建 packages.txt,内容为 fonts-wqy-zenhei(Streamlit Cloud 会自动 apt-install 这个中文字体包)
  2. 字体设置改为自动检测机制:遍历 ['SimHei', 'WenQuanYi Zen Hei', 'Microsoft YaHei'],找到第一个本机存在的字体就用
import matplotlib.font_manager as _fm
_available = {f.name for f in _fm.fontManager.ttflist}
for _font in ['SimHei', 'WenQuanYi Zen Hei', 'Microsoft YaHei']:
    if _font in _available:
        plt.rcParams['font.sans-serif'] = [_font]
        break

注意:最初尝试直接写字体回退列表 ['WenQuanYi Zen Hei', 'SimHei', ...],结果在 Windows 上因为第一个字体不存在导致全部中文变方块。matplotlib 的字体回退机制不太可靠,所以改用主动检测的方式。

5.2 配色调整

原始配色:顶栏背景、分节标题侧边条、策略净值曲线都用了亮红色 #e11d48,视觉冲击太强,55 岁以上的合作伙伴看着不舒服。

调整为深藏青蓝

整体风格从”警报红”变成了”金融蓝”,更专业、更耐看。

5.3 依赖文件

创建了 requirements.txt

tushare>=1.4.0
pandas>=2.0.0
numpy>=1.24.0
streamlit>=1.30.0
matplotlib>=3.7.0
mplfinance>=0.12.9b7

注意 mplfinance 没有正式版 0.12.10,PyPI 上全是 beta 版本号,最初写 >=0.12.10 导致 CI pip install 失败,改成了 >=0.12.9b7


六、Streamlit Cloud 部署

已在 Streamlit Cloud 上完成部署,链接为 https://csi500-mog4ccaigs8grc2sazknxq.streamlit.app/

发现的问题streamlit.app 域名在中国大陆无法访问,合作伙伴看不到。

待办:后续考虑用腾讯云轻量应用服务器(香港节点)部署,不需要 ICP 备案,国内访问也快。域名 sophiaz.cn 本身就在腾讯云管理,可以直接绑定子域名 csi500.sophiaz.cn


七、当前项目文件结构

CSI500/
├── .github/workflows/
│   └── daily_update.yml        ← GitHub Actions 每日自动更新
├── stocks_data/                ← 1074 只成分股后复权日线数据
│   ├── 000006.SZ.csv
│   ├── ...
│   └── 689009.SH.csv
├── strategy_data.csv           ← 策略总表(14列,1730行,20190102~20260224)
├── csi500_components_schedule.csv ← 成分股调度表
├── adj_factor_base.csv         ← 全市场复权基准表(5485只股票,基准日20260213)
├── update_status.json          ← 数据同步状态(GitHub Actions 每次更新后写入)
├── daily_update.py             ← 每日增量更新脚本(GitHub Actions 调用)
├── build_strategy_data.py      ← 全量构建 strategy_data.csv 的脚本
├── dashboard.py                ← Streamlit 决策看板
├── backtest.py                 ← 回测引擎(本地运行,生成 K线图 + 净值曲线)
├── requirements.txt            ← Python 依赖
├── packages.txt                ← Streamlit Cloud 系统依赖(中文字体)
├── CLAUDE.md                   ← 项目说明(策略参数速查、待确认差异等)
└── .gitignore                  ← 排除日志/缓存/临时文件

八、待办事项

  1. 腾讯云部署:购买香港轻量服务器,部署 Streamlit,绑定 csi500.sophiaz.cn,让国内合作伙伴能访问
  2. 自动同步:服务器上配置 git pull 定时任务,GitHub Actions 更新数据后自动拉取
  3. 首次真实运行验证:等下一个交易日(2026-02-25),观察 GitHub Actions 是否在 17:30 自动触发并成功更新数据