给一只 ETF 写了个本地优先的研究台:React 19 + Vite 8 + 三源 fallback
最近在 GitHub 上线了一个个人项目,分享一下技术决策和取舍。
项目背景
我自己持有 512400(南方有色金属 ETF),盘中想要一个工具同时回答这 4 个问题:
- 今天到底是追高、观望,还是回调低吸?
- 现在价格离估算净值多远?折价还是溢价?
- 是黄金 / 铜 / 铝 / 锂 / 稀土哪个商品在推这只 ETF?
- 相对 000819 基准跟踪和流动性怎么样?
雪球、同花顺、东财之间能凑齐,但一屏看完的工具我没找到。商业级量化平台又太重,单标的研究只用 5% 的能力。Notebook 写出来又麻烦每次手跑。
所以自己写了一个:github.com/Leonard-Don…(开源 MIT)。
下面讲讲核心的技术取舍。
为什么 React 19 + Vite 8 纯前端 SPA
后端我考虑过 FastAPI + TimescaleDB,但单标的场景下:
- 数据量小:一只 ETF 的盘中 + 历史最多几千个 K 线 + 数百次报价
- 用户场景是「一个人盘中看自己电脑」,不是多人并发
- 后端反而增加部署 / 维护成本,给一个工具加包袱
最终选纯前端 SPA + 本地 JSON 快照。React 19 + Vite 8 的理由:
- Vite 的 HMR 比 webpack 快一个量级,盘中频繁改代码的开发体验好
- React 19 的并发渲染(useTransition / startTransition)对盘中频繁更新友好
- 不需要 SSR,组件树并不复杂
三源数据 Fallback 怎么设计
每个数据源都有自己的失败模式:
| 源 | 优势 | 失败模式 |
|---|---|---|
| 东方财富 | quote / K 线 / 估值完整 | 接口结构偶尔变 |
| 腾讯财经 | 实时报价稳定 | 历史数据少 |
| 天天基金 | 净值 / 阶段收益权威 | 盘中估值有延迟 |
实现层:所有读取都走 runtime fetcher 抽象,按 priority 顺序调用。任一源返回非预期结构时记录错误状态并立刻切到下一源。
关键点:UI 上同时展示当前数据来源 + 新鲜度(例如「东方财富,2 秒前」)—— 用户永远不会被偷偷换源。降级可见,是合规和信任的底线。
代码层关键入口:
src/analysis/realtimeQuote.js // 实时报价兜底逻辑
/api/realtime/* // 本地代理路由(仅 dev 环境,规避浏览器跨域)
本地 JSON 快照而不是 DB
每次刷新会追加 src/data/history/512400-snapshots.json:
- ✅ 优点:无 schema、无 migration、git diff 可读、刷新 = pure append
- ⚠️ 缺点:单文件最终会变大(目前几 MB 量级,未到性能瓶颈)
对于「研究我自己投的 ETF」这个场景,JSON 快照 100% 够用。如果以后要做多标的,再换 PostgreSQL / TimescaleDB。
信号合成:简单加权而不是 ML
研究台核心是把多个信号合成「今天的建议动作」:
- 趋势跟随:均线穿越 + 动量斜率
- 回撤低吸:从近 30 日高点的回撤幅度
- 因子共振:商品驱动(铜 / 铝 / 锂 / 稀土)与 ETF 持仓权重的耦合
- 自动优化:在最近样本上 grid search 最优参数,做样本外验证评分
合成层用简单加权而不是 ML,理由:
- 单标的样本少,ML 容易过拟合
- 简单规则可解释,复盘时容易回溯哪一步信号错了
- 维护成本低,全部逻辑在
src/analysis/下可读
最有用的部分:原因链。系统给出每个判断的 3 条具体证据,可读可改可辩论。
跟踪质量层(vs 000819 基准)
ETF 不是越接近基准越好,但跟踪偏差太大也是 risk。专门做了一个 panel:
- 跟踪差:与 000819 日 return 的差
- 折溢价温度:IOPV 估算 vs 实际价格(用标准差 σ 量化偏离)
- 成交额分位:流动性是否够
局限性诚实呈现
- 单标的不可扩展——这就是设计哲学,要做多标的请重写
- 本地优先依赖你电脑——关机就没了,需要主动备份历史
- 不接交易——所有信号仅供研究 / 复盘,没有实盘执行入口
- 数据源依赖公开网页接口——东方财富改版我也要跟着改
谁用得上
- 自己投了 512400 或类似单标的 ETF,想盘中看真实状态
- ETF 套利学习者,想理解折溢价 / 跟踪误差怎么算
- 量化研究 builder,想看一个「单标的 + 本地优先」的工程实践参考
仓库
MIT 协议,欢迎 Issue / PR / fork。如果你也在做单标的研究台、ETF 本地工具或多源数据 fallback 架构,欢迎评论里聊。