动笔之前,我画完了全套架构图
我给自己定了个目标:搭一套个人量化研究系统——不做实盘下单,只产出信号和分析报告,日线级别、盘后批处理。这本来是个"先跑起来再说"的活,结果开工之前,我把设计做到了 v0.6,最后拆成四份文档:需求、架构、产品、页面。
那四份文档长什么样?核心数据契约(bar、因子、信号、回测报告的字段冻结,防返工)、存储方案选型(parquet + SQLite + DuckDB,从"全量三千万行导入 SQLite 慢"这种真实痛点推出来)、七包架构(tj-core 到 tj-web 的 monorepo)、11 页 Web UI 的产品设计、MCP 工具集(让 AI 能创建策略、触发回测)、甚至备份恢复、webhook 通知矩阵。
页面是我一页页聊出来的:行情数据页要有 K 线叠加因子,股票池页要有分组管理,任务中心要有统计图表。每确认一页,就往契约里加一条引擎必须提供的接口。很爽,很"专业"。
然后我发现,这违背了我刚写完的方法论
就在几天前,我刚在另一个专栏写完《架构不是设计出来的》,里面讲了一个四阶段框架:能跑 → 跑得准 → 跑得稳 → 跑得快。核心就一句话:在信息最少的时候用最少的东西,先证明方向值得继续,再谈别的。"能跑"阶段的原则是三个字:砍、硬、短——砍功能,硬编码可以,代码短、依赖轻。退出信号是:当你开始问"这样写对不对"而不是"能不能跑",才说明该进入下一阶段了。
我对照了一下自己:一行代码没写,却已经完成了四份设计文档,在讨论"架构怎么最优"。我在"能不能跑"都还没验证的时候,就开始了"怎么写对"的讨论。这不是设计,这是阶段前移。
更具体地说,我踩了三个坑:
把"跑得快"的决策提前了。 Rust 回测核心,理由之一是"现成回测库不是 A 股特化"——这是功能需求,没毛病。但另一个理由"不接受一次策略跑数小时"是性能预判,我还没跑过任何一次回测。先 Python 写个简版,真慢了 profiling 再决定要不要 Rust,才是"跑得快"该干的事。
把"跑得稳"的复杂度提前了。 11 页 Web UI、MCP 服务、数据管理(备份/恢复/迁移/清理)、webhook 通知矩阵——这些在"能跑"阶段全是"砍"的对象。备份恢复是"万一数据被搞坏了"的保险,MCP 是"万一要用 AI 操作"的便利,没有一个对应到当下的真实痛点。
用"确定性交付型"的标准做"探索型"的项目。 需求明确、数据量有预估的项目,前期设计要重,该预留的扩展点要预留。但这个系统的功能需求明确,结果高度不确定——因子有没有效、循环能不能转起来、我会不会坚持用半年。这是典型的探索型项目,简单优先本该是死守的原则。
但有些设计,我觉得没做错
复盘也不能全盘否定自己。有几个决策我现在依然认为是"信息充分"的:
核心数据契约不省。 bar 存什么字段、复权用后复权、信号 T+1 开盘成交、财务数据带公告日对齐——这些是防返工的关键,也是"能跑"阶段就该有的东西。它们不是复杂度,是正确性。
A 股语义做对。 涨跌停、费用、T+1、停牌,这些在最小闭环里就要做对,因为它们是功能需求不是性能需求。回测数字不对,后面的一切都是沙上建塔。
区别在哪?契约和语义是"做了才准",UI 和 Rust 是"不做也能跑"。这就是"做当下信息量下最合理的决策"的边界。
补救:给设计稿降级,加一份路线图
我没有把四份文档扔掉——它们描述的完整形态是真实的,只是不该作为第一批代码的规格。我给设计稿加了一份路线图,把它降级成"形态参考",实施按四阶段走:
- 能跑:一个脚本/单包,拉数 → 一个因子 → 一个策略 → Python 简版回测 → 出报告,真实数据跑通,数字和手工核算一致
- 跑得准:数据校验、端到端对账、因子 IC 验证
- 跑得稳:任务表、日志、告警、备份——按真实痛点逐个引入,不是一次全上
- 跑得快:profiling 之后,按瓶颈决定要不要 parquet、DuckDB、Rust
每阶段有明确的验证信号,通过了才进下一阶段。设计稿里的每个复杂度,都标注了"落地阶段"和"可能被推翻的假设"。比如:如果 Python 回测足够快,整个 Rust 取消;如果数据量远小于预估,SQLite 单库足够,整套存储简化。
系列预告
这个专栏会按四阶段记录这个系统的构建过程:能跑、跑得准、跑得稳、跑得快,每阶段一篇主线。期间每一次真实的权衡取舍和技术选型——数据源选 Tushare 还是自建、存储为什么第一步不建库、回测引擎为什么自研、复权用前还是后——都会单独成篇,因为决策发生的现场,才是这套系统最有信息量的地方。主线讲"系统怎么长出来",副线讲"决策怎么做的",配合量化专栏的投资方法论一起看。
最后说一句这次最大的教训:好的架构不是设计出来的——这句话不是反对设计,是反对在信息不足时做一步到位的设计。设计可以画到 v0.6,但代码要按四阶段长出来。现在,我要开始写"能跑"那部分了。
寒蝉 Hancic

